View Javadoc
1 /* 2 * Copyright (c) 2003 3 * Information Desire GmbH 4 * All rights reserved. 5 */ 6 package com.infodesire.infobit.external.impl; 7 8 import org.apache.commons.logging.Log; 9 import org.apache.commons.logging.LogFactory; 10 11 import java.io.IOException; 12 import java.io.OutputStream; 13 14 /*** 15 * Decodes binary data encoded as base64. 16 * 17 * @author peter2 18 * @created 1. September 2003 19 * @version $Revision: 1.1 $ 20 */ 21 class Base64Decoder implements Decoder { 22 23 private final static Log _log = LogFactory.getLog(Base64Decoder.class); 24 25 /*** 26 * The destination where to write the decoded data to 27 */ 28 private OutputStream _destination; 29 30 /*** 31 * The text chunk currently being decoded 32 */ 33 private char[] _textChunk = new char[24 / 6]; 34 35 /*** 36 * The data chunk currently being decoded 37 */ 38 private byte[] _dataChunk = new byte[24 / 8]; 39 40 /*** 41 * Number of unprocessed characters hold in the {@link _textChunk input 42 * buffer} 43 */ 44 private int _textLength; 45 46 /*** 47 * Number of bytes to decode 48 */ 49 private int _contentLength; 50 51 /*** 52 * Number of decoded bytes 53 */ 54 private int _writtenLength; 55 56 /*** 57 * Inconsistent encoding data 58 */ 59 private boolean _error; 60 61 /*** 62 * A description of the first decoding error encountered 63 */ 64 private String _errorText = "OK"; 65 66 67 /*** 68 * Gets the WrittenLength attribute of the Base64Decoder object 69 * 70 * @return The WrittenLength value 71 */ 72 public int getWrittenLength() { 73 return _writtenLength; 74 } 75 76 77 /*** 78 * Gets the ErrorText attribute of the Base64Decoder object 79 * 80 * @return The ErrorText value 81 */ 82 public String getErrorText() { 83 return _errorText; 84 } 85 86 87 /*** 88 * Sets the Destination attribute of the Base64Decoder object 89 * 90 * @param dest The new Destination value 91 */ 92 public void setDestination(OutputStream dest) { 93 _destination = dest; 94 } 95 96 97 /*** 98 * Defines the number of bytes to process. 99 * 100 * @param contentLength The new ContentLength value 101 */ 102 public void setContentLength(int contentLength) { 103 _contentLength = contentLength; 104 } 105 106 107 /*** 108 * DOCUMENT METHOD 109 * 110 * @return Description of the Returned Value 111 */ 112 public boolean hasError() { 113 return _error; 114 } 115 116 117 /*** 118 * DOCUMENT METHOD 119 * 120 * @param b Description of Parameter 121 * @param offset Description of Parameter 122 * @param length Description of Parameter 123 * @exception IOException Description of Exception 124 */ 125 public void decodeChunk(char[] b, int offset, int length) 126 throws IOException { 127 128 int n = 0; 129 130 while (!_error && 131 (n = fill(b, offset, length)) > -1 132 && _textLength == _textChunk.length) { 133 134 offset += n; 135 length -= n; 136 137 for (int i = 0; !_error && i < _textChunk.length; ++i) { 138 139 int j = 6 * i / 8; 140 int k = 6 * i % 8; 141 int d = decode(_textChunk[i]) << k; 142 int low = (d & 0xff); 143 int high = (d >>> 8); 144 int maskLow = (0x3f << k) & 0xff; 145 int maskHigh = 0x3f << k >>> 8; 146 _dataChunk[j] = (byte) (_dataChunk[j] & ~maskLow | low); 147 148 if (j + 1 < _dataChunk.length) { 149 _dataChunk[j + 1] = 150 (byte) (_dataChunk[j + 1] & ~maskHigh | high); 151 } 152 } 153 154 _textLength = 0; 155 int l = Math.min(_contentLength - _writtenLength, 156 _dataChunk.length); 157 _destination.write(_dataChunk, 0, l); 158 _writtenLength += l; 159 } 160 } 161 162 163 /*** 164 * DOCUMENT METHOD 165 */ 166 public void endOfData() { 167 if (_writtenLength < _contentLength) { 168 recordError("short data: " + (_contentLength - _writtenLength) + 169 " Bytes"); 170 } 171 } 172 173 174 /*** 175 * Marks an error. Does not override previously set errors. 176 * 177 * @param desc Brief error description 178 */ 179 private void recordError(String desc) { 180 if (!_error) { 181 _errorText = desc; 182 _error = true; 183 } 184 } 185 186 187 /*** 188 * Fills the {@link _textChunk input buffer} from the specified source. Test 189 * for overflow. Does not accept data on error. 190 * 191 * @param b Holds the data from which to fill the input buffer 192 * @param offset Index of the first element from which to fill the input 193 * buffer 194 * @param length Number of contiguous characters from which to fill the 195 * input buffer. 196 * @return The number of characters consumed from <code>b</code>, or 197 * -1 if an error occured 198 */ 199 private int fill(char[] b, int offset, int length) { 200 int n = 0; 201 boolean checkOverflow = _writtenLength == _contentLength; 202 203 while (!_error && _textLength < _textChunk.length && n < length) { 204 char c = b[offset + n++]; 205 206 if (!Character.isWhitespace(c)) { 207 if (checkOverflow) { 208 recordError("Input too large"); 209 // _error is true 210 } 211 212 _textChunk[_textLength++] = c; 213 } 214 } 215 216 return _error ? -1 : n; 217 } 218 219 220 /*** 221 * Decodes a character of the base64 alphabet. 222 * 223 * @param c The base64 character to decode 224 * @return The value mapping to <code>c</code>, or -1 for error 225 */ 226 private int decode(char c) { 227 int d = -1; 228 229 if ('A' <= c && c <= 'Z') { 230 d = c - 'A'; 231 } 232 else if ('a' <= c && c <= 'z') { 233 d = c - 'a' + 26; 234 } 235 else if ('0' <= c && c <= '9') { 236 d = c - '0' + 52; 237 } 238 else if (c == '+') { 239 d = 62; 240 } 241 else if (c == '/') { 242 d = 63; 243 } 244 else if (c == '=') { 245 d = 0; 246 } 247 else { 248 recordError("Illegal input data: 0x" + Integer.toHexString(c)); 249 } 250 251 return d; 252 } 253 254 }

This page was automatically generated by Maven