You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2011/01/26 16:22:39 UTC
svn commit: r1063759 -
/commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base32.java
Author: sebb
Date: Wed Jan 26 15:22:39 2011
New Revision: 1063759
URL: http://svn.apache.org/viewvc?rev=1063759&view=rev
Log:
Javadoc
Modified:
commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base32.java
Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base32.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base32.java?rev=1063759&r1=1063758&r2=1063759&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base32.java (original)
+++ commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base32.java Wed Jan 26 15:22:39 2011
@@ -17,11 +17,6 @@
package org.apache.commons.codec.binary;
-import org.apache.commons.codec.BinaryDecoder;
-import org.apache.commons.codec.BinaryEncoder;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.EncoderException;
-
/**
* Provides Base32 encoding and decoding as defined by RFC 4648.
*
@@ -46,11 +41,7 @@ import org.apache.commons.codec.EncoderE
* @since 1.5
* @version $Revision$
*/
-public class Base32 implements BinaryEncoder, BinaryDecoder {
-
- private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
-
- private static final int DEFAULT_BUFFER_SIZE = 8192;
+public class Base32 extends BasedCodec {
/**
* BASE32 characters are 5 bits in length.
@@ -61,31 +52,6 @@ public class Base32 implements BinaryEnc
private static final int BYTES_PER_UNENCODED_BLOCK = 5;
private static final int BYTES_PER_ENCODED_BLOCK = 8;
-
- /**
- * MIME chunk size per RFC 2045 section 6.8.
- *
- * <p>
- * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
- * equal signs.
- * </p>
- *
- * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
- */
- public static final int MIME_CHUNK_SIZE = 76;
-
- /**
- * PEM chunk size per RFC 1421 section 4.3.2.4.
- *
- * <p>
- * The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
- * equal signs.
- * </p>
- *
- * @see <a href="http://tools.ietf.org/html/rfc1421">RFC 1421 section 4.3.2.4</a>
- */
- public static final int PEM_CHUNK_SIZE = 64;
-
/**
* Chunk separator per RFC 2045 section 2.1.
*
@@ -168,9 +134,8 @@ public class Base32 implements BinaryEnc
* Encode table to use.
*/
private final byte[] encodeTable;
-
- private final byte[] decodeTable; // need different decode table to support Hex version
+ private final byte[] decodeTable;
/**
* Line length for encoding. Not used when decoding. A value of zero or less implies no chunking of the Base32
* encoded data.
@@ -197,45 +162,6 @@ public class Base32 implements BinaryEnc
private final int encodeSize;
/**
- * Buffer for streaming.
- */
- private byte[] buffer;
-
- /**
- * Position where next character should be written in the buffer.
- */
- private int pos;
-
- /**
- * Position where next character should be read from the buffer.
- */
- private int readPos;
-
- /**
- * Variable tracks how many characters have been written to the current line. Only used when encoding. We use it to
- * make sure each encoded line never goes beyond lineLength (if lineLength > 0).
- */
- private int currentLinePos;
-
- /**
- * Writes to the buffer only occur after every 5 reads when encoding, and every 8 reads when decoding. This variable
- * helps track that.
- */
- private int modulus;
-
- /**
- * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this Base32 object becomes useless,
- * and must be thrown away.
- */
- private boolean eof;
-
- /**
- * Place holder for the 8 bytes we're dealing with for our Base32 logic. Bitwise operations store and extract the
- * Base32 encoding or decoding from this variable.
- */
- private long x; // 64 bits; enough for 40 bits i.e. 5 octets unencoded
-
- /**
* Creates a Base32 codec used for decoding and encoding.
* <p>
* When encoding the line length is 0 (no chunking).
@@ -338,274 +264,13 @@ public class Base32 implements BinaryEnc
}
/**
- * Returns true if this Base32 object has buffered data for reading.
- *
- * @return true if there is Base32 object still available for reading.
- */
- boolean hasData() {
- return this.buffer != null;
- }
-
- /**
- * Returns the amount of buffered data available for reading.
- *
- * @return The amount of buffered data available for reading.
- */
- int avail() {
- return buffer != null ? pos - readPos : 0;
- }
-
- /** Doubles our buffer. */
- private void resizeBuffer() {
- if (buffer == null) {
- buffer = new byte[DEFAULT_BUFFER_SIZE];
- pos = 0;
- readPos = 0;
- } else {
- byte[] b = new byte[buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
- System.arraycopy(buffer, 0, b, 0, buffer.length);
- buffer = b;
- }
- }
-
- /**
- * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
- * bytes. Returns how many bytes were actually extracted.
- *
- * @param b
- * byte[] array to extract the buffered data into.
- * @param bPos
- * position in byte[] array to start extraction at.
- * @param bAvail
- * amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
- * @return The number of bytes successfully extracted into the provided byte[] array.
- */
- int readResults(byte[] b, int bPos, int bAvail) {
- if (buffer != null) {
- int len = Math.min(avail(), bAvail);
- System.arraycopy(buffer, readPos, b, bPos, len);
- readPos += len;
- if (readPos >= pos) {
- buffer = null;
- }
- return len;
- }
- return eof ? -1 : 0;
- }
-
- /**
- * <p>
- * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
- * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last
- * remaining bytes (if not multiple of 5).
- * </p>
- *
- * @param in
- * byte[] array of binary data to Base32 encode.
- * @param inPos
- * Position to start reading data from.
- * @param inAvail
- * Amount of bytes available from input for encoding.
- */
- void encode(byte[] in, int inPos, int inAvail) {
- if (eof) {
- return;
- }
- // inAvail < 0 is how we're informed of EOF in the underlying data we're
- // encoding.
- if (inAvail < 0) {
- eof = true;
- if (buffer == null || buffer.length - pos < encodeSize) {
- resizeBuffer();
- }
- switch (modulus) { // % 5
- case 1 : // Only 1 octet; take top 5 bits then remainder
- buffer[pos++] = encodeTable[(int)(x >> 3) & MASK_5BITS]; // 8-1*5 = 3
- buffer[pos++] = encodeTable[(int)(x << 2) & MASK_5BITS]; // 5-3=2
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- break;
-
- case 2 : // 2 octets = 16 bits to use
- buffer[pos++] = encodeTable[(int)(x >> 11) & MASK_5BITS]; // 16-1*5 = 11
- buffer[pos++] = encodeTable[(int)(x >> 6) & MASK_5BITS]; // 16-2*5 = 6
- buffer[pos++] = encodeTable[(int)(x >> 1) & MASK_5BITS]; // 16-3*5 = 1
- buffer[pos++] = encodeTable[(int)(x << 4) & MASK_5BITS]; // 5-1 = 4
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- break;
- case 3 : // 3 octets = 24 bits to use
- buffer[pos++] = encodeTable[(int)(x >> 19) & MASK_5BITS]; // 24-1*5 = 19
- buffer[pos++] = encodeTable[(int)(x >> 14) & MASK_5BITS]; // 24-2*5 = 14
- buffer[pos++] = encodeTable[(int)(x >> 9) & MASK_5BITS]; // 24-3*5 = 9
- buffer[pos++] = encodeTable[(int)(x >> 4) & MASK_5BITS]; // 24-4*5 = 4
- buffer[pos++] = encodeTable[(int)(x << 1) & MASK_5BITS]; // 5-4 = 1
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- buffer[pos++] = PAD;
- break;
- case 4 : // 4 octets = 32 bits to use
- buffer[pos++] = encodeTable[(int)(x >> 27) & MASK_5BITS]; // 32-1*5 = 27
- buffer[pos++] = encodeTable[(int)(x >> 22) & MASK_5BITS]; // 32-2*5 = 22
- buffer[pos++] = encodeTable[(int)(x >> 17) & MASK_5BITS]; // 32-3*5 = 17
- buffer[pos++] = encodeTable[(int)(x >> 12) & MASK_5BITS]; // 32-4*5 = 12
- buffer[pos++] = encodeTable[(int)(x >> 7) & MASK_5BITS]; // 32-5*5 = 7
- buffer[pos++] = encodeTable[(int)(x >> 2) & MASK_5BITS]; // 32-6*5 = 2
- buffer[pos++] = encodeTable[(int)(x << 3) & MASK_5BITS]; // 5-2 = 3
- buffer[pos++] = PAD;
- break;
- }
- // Don't want to append the CRLF two times in a row, so make sure previous
- // character is not from CRLF!
- byte b = lineSeparator[lineSeparator.length - 1];
- if (lineLength > 0 && pos > 0 && buffer[pos-1] != b) {
- System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
- pos += lineSeparator.length;
- }
- } else {
- for (int i = 0; i < inAvail; i++) {
- if (buffer == null || buffer.length - pos < encodeSize) {
- resizeBuffer();
- }
- modulus = (++modulus) % BITS_PER_ENCODED_CHAR;
- int b = in[inPos++];
- if (b < 0) {
- b += 256;
- }
- x = (x << 8) + b; // ??
- if (0 == modulus) { // we have enough bytes to create our output
- buffer[pos++] = encodeTable[(int)(x >> 35) & MASK_5BITS];
- buffer[pos++] = encodeTable[(int)(x >> 30) & MASK_5BITS];
- buffer[pos++] = encodeTable[(int)(x >> 25) & MASK_5BITS];
- buffer[pos++] = encodeTable[(int)(x >> 20) & MASK_5BITS];
- buffer[pos++] = encodeTable[(int)(x >> 15) & MASK_5BITS];
- buffer[pos++] = encodeTable[(int)(x >> 10) & MASK_5BITS];
- buffer[pos++] = encodeTable[(int)(x >> 5) & MASK_5BITS];
- buffer[pos++] = encodeTable[(int)x & MASK_5BITS];
- currentLinePos += BYTES_PER_ENCODED_BLOCK;
- if (lineLength > 0 && lineLength <= currentLinePos) {
- System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
- pos += lineSeparator.length;
- currentLinePos = 0;
- }
- }
- }
- }
- }
-
- /**
- * <p>
- * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
- * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
- * call is not necessary when decoding, but it doesn't hurt, either.
- * </p>
- * <p>
- * Ignores all non-Base32 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
- * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
- * garbage-out philosophy: it will not check the provided data for validity.
- * </p>
- *
- * @param in
- * byte[] array of ascii data to Base32 decode.
- * @param inPos
- * Position to start reading data from.
- * @param inAvail
- * Amount of bytes available from input for encoding.
- *
- * Output is written to {@link #buffer} as 8-bit octets, using {@link pos} as the buffer position
- */
- void decode(byte[] in, int inPos, int inAvail) { // package protected for access from I/O streams
- if (eof) {
- return;
- }
- if (inAvail < 0) {
- eof = true;
- }
- for (int i = 0; i < inAvail; i++) {
- if (buffer == null || buffer.length - pos < decodeSize) {
- resizeBuffer();
- }
- byte b = in[inPos++];
- if (b == PAD) {
- // We're done.
- eof = true;
- break;
- } else {
- if (b >= 0 && b < this.decodeTable.length) {
- int result = this.decodeTable[b];
- if (result >= 0) {
- modulus = (++modulus) % BYTES_PER_ENCODED_BLOCK;
- x = (x << BITS_PER_ENCODED_CHAR) + result; // collect decoded bytes
- if (modulus == 0) { // we can output the 5 bytes
- buffer[pos++] = (byte) ((x >> 32) & MASK_8BITS);
- buffer[pos++] = (byte) ((x >> 24) & MASK_8BITS);
- buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
- buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
- buffer[pos++] = (byte) (x & MASK_8BITS);
- }
- }
- }
- }
- }
-
- // Two forms of EOF as far as Base32 decoder is concerned: actual
- // EOF (-1) and first time '=' character is encountered in stream.
- // This approach makes the '=' padding characters completely optional.
- if (eof && modulus != 0) {
- if (buffer == null || buffer.length - pos < decodeSize) {
- resizeBuffer();
- }
-
- // we ignore partial bytes, i.e. only multiples of 8 count
- switch (modulus) {
- case 2 : // 10 bits, drop 2 and output one byte
- buffer[pos++] = (byte) ((x >> 2) & MASK_8BITS);
- break;
- case 3 : // 15 bits, drop 7 and output 1 byte
- buffer[pos++] = (byte) ((x >> 7) & MASK_8BITS);
- break;
- case 4 : // 20 bits = 2*8 + 4
- x = x >> 4; // drop 4 bits
- buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
- buffer[pos++] = (byte) ((x) & MASK_8BITS);
- break;
- case 5 : // 25bits = 3*8 + 1
- x = x >> 1;
- buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
- buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
- buffer[pos++] = (byte) ((x) & MASK_8BITS);
- break;
- case 6 : // 30bits = 3*8 + 6
- x = x >> 6;
- buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
- buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
- buffer[pos++] = (byte) ((x) & MASK_8BITS);
- break;
- case 7 : // 35 = 4*8 +3
- x = x >> 3;
- buffer[pos++] = (byte) ((x >> 24) & MASK_8BITS);
- buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
- buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
- buffer[pos++] = (byte) ((x) & MASK_8BITS);
- break;
- }
- }
- }
-
- /**
* Returns whether or not the <code>octet</code> is in the Base32 alphabet.
*
* @param octet
* The value to test
* @return <code>true</code> if the value is defined in the the Base32 alphabet (or pad), <code>false</code> otherwise.
*/
- public static boolean isBase32(byte octet) {
+ public boolean isBase32(byte octet) {
return octet == PAD || (octet >= 0 && octet < BASE32_DECODE_TABLE.length && BASE32_DECODE_TABLE[octet] != -1);
}
@@ -616,7 +281,7 @@ public class Base32 implements BinaryEnc
* The value to test
* @return <code>true</code> if the value is defined in the the Base32 Hex alphabet (or pad), <code>false</code> otherwise.
*/
- public static boolean isBase32Hex(byte octet) {
+ public boolean isBase32Hex(byte octet) {
return octet == PAD || (octet >= 0 && octet < BASE32HEX_DECODE_TABLE.length && BASE32HEX_DECODE_TABLE[octet] != -1);
}
@@ -629,7 +294,7 @@ public class Base32 implements BinaryEnc
* @return <code>true</code> if all characters in the String are valid characters in the Base32 alphabet or if
* the String is empty; <code>false</code>, otherwise
*/
- public static boolean isBase32(String base32) {
+ public boolean isBase32(String base32) {
return isBase32(StringUtils.getBytesUtf8(base32));
}
@@ -642,7 +307,7 @@ public class Base32 implements BinaryEnc
* @return <code>true</code> if all bytes are valid characters in the Base32 alphabet or if the byte array is empty;
* <code>false</code>, otherwise
*/
- public static boolean isBase32(byte[] arrayOctet) {
+ public boolean isBase32(byte[] arrayOctet) {
for (int i = 0; i < arrayOctet.length; i++) {
if (!isBase32(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
return false;
@@ -652,14 +317,14 @@ public class Base32 implements BinaryEnc
}
/**
- * Tests a given byte array to see if it contains only valid characters within the Base32 alphabet.
+ * Tests a given byte array to see if it contains any characters within the Base32 alphabet.
* Does not allow white-space.
*
* @param arrayOctet
* byte array to test
* @return <code>true</code> if any byte is a valid character in the Base32 alphabet; <code>false</code> otherwise
*/
- private static boolean containsBase32Byte(byte[] arrayOctet) {
+ private boolean containsBase32Byte(byte[] arrayOctet) {
for (int i = 0; i < arrayOctet.length; i++) {
if (isBase32(arrayOctet[i])) {
return true;
@@ -713,56 +378,6 @@ public class Base32 implements BinaryEnc
}
/**
- * Decodes an Object using the Base32 algorithm. This method is provided in order to satisfy the requirements of the
- * Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String.
- *
- * @param pObject
- * Object to decode
- * @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String supplied.
- * @throws DecoderException
- * if the parameter supplied is not of type byte[]
- */
- public Object decode(Object pObject) throws DecoderException {
- if (pObject instanceof byte[]) {
- return decode((byte[]) pObject);
- } else if (pObject instanceof String) {
- return decode((String) pObject);
- } else {
- throw new DecoderException("Parameter supplied to Base32 decode is not a byte[] or a String");
- }
- }
-
- /**
- * Decodes a String containing characters in the Base32 alphabet.
- *
- * @param pArray
- * A String containing Base32 character data
- * @return a byte array containing binary data
- */
- public byte[] decode(String pArray) {
- return decode(StringUtils.getBytesUtf8(pArray));
- }
-
- /**
- * Decodes a byte[] containing characters in the Base32 alphabet.
- *
- * @param pArray
- * A byte array containing Base32 character data
- * @return a byte array containing binary data
- */
- public byte[] decode(byte[] pArray) {
- reset();
- if (pArray == null || pArray.length == 0) {
- return pArray;
- }
- decode(pArray, 0, pArray.length);
- decode(pArray, 0, -1); // Notify decoder of EOF.
- byte[] result = new byte[pos];
- readResults(result, 0, result.length);
- return result;
- }
-
- /**
* Encodes binary data using the Base32 algorithm, optionally chunking the output into 76 character blocks.
*
* @param binaryData
@@ -897,113 +512,239 @@ public class Base32 implements BinaryEnc
}
/**
- * Checks if a byte value is whitespace or not.
- *
- * @param byteToCheck
- * the byte to check
- * @return true if byte is whitespace, false otherwise
- */
- private static boolean isWhiteSpace(byte byteToCheck) {
- switch (byteToCheck) {
- case ' ' :
- case '\n' :
- case '\r' :
- case '\t' :
- return true;
- default :
- return false;
- }
- }
-
- // Implementation of the Encoder Interface
-
- /**
- * Encodes an Object using the Base32 algorithm. This method is provided in order to satisfy the requirements of the
- * Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[].
+ * <p>
+ * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
+ * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last
+ * remaining bytes (if not multiple of 5).
+ * </p>
*
- * @param pObject
- * Object to encode
- * @return An object (of type byte[]) containing the Base32 encoded data which corresponds to the byte[] supplied.
- * @throws EncoderException
- * if the parameter supplied is not of type byte[]
+ * @param in
+ * byte[] array of binary data to Base32 encode.
+ * @param inPos
+ * Position to start reading data from.
+ * @param inAvail
+ * Amount of bytes available from input for encoding.
*/
- public Object encode(Object pObject) throws EncoderException {
- if (!(pObject instanceof byte[])) {
- throw new EncoderException("Parameter supplied to Base32 encode is not a byte[]");
+ void encode(byte[] in, int inPos, int inAvail) { // package protected for access from I/O streams
+ if (eof) {
+ return;
}
- return encode((byte[]) pObject);
- }
-
- /**
- * Encodes a byte[] containing binary data, into a String containing characters in the Base32 alphabet.
- *
- * @param pArray
- * a byte array containing binary data
- * @return A String containing only Base32 character data
- */
- public String encodeToString(byte[] pArray) {
- return StringUtils.newStringUtf8(encode(pArray));
- }
-
- /**
- * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base32 alphabet.
- *
- * @param pArray
- * a byte array containing binary data
- * @return A byte array containing only Base32 character data
- */
- public byte[] encode(byte[] pArray) {
- reset();
- if (pArray == null || pArray.length == 0) {
- return pArray;
+ // inAvail < 0 is how we're informed of EOF in the underlying data we're
+ // encoding.
+ if (inAvail < 0) {
+ eof = true;
+ if (buffer == null || buffer.length - pos < encodeSize) {
+ resizeBuffer();
+ }
+ switch (modulus) { // % 5
+ case 1 : // Only 1 octet; take top 5 bits then remainder
+ buffer[pos++] = encodeTable[(int)(x >> 3) & MASK_5BITS]; // 8-1*5 = 3
+ buffer[pos++] = encodeTable[(int)(x << 2) & MASK_5BITS]; // 5-3=2
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ break;
+
+ case 2 : // 2 octets = 16 bits to use
+ buffer[pos++] = encodeTable[(int)(x >> 11) & MASK_5BITS]; // 16-1*5 = 11
+ buffer[pos++] = encodeTable[(int)(x >> 6) & MASK_5BITS]; // 16-2*5 = 6
+ buffer[pos++] = encodeTable[(int)(x >> 1) & MASK_5BITS]; // 16-3*5 = 1
+ buffer[pos++] = encodeTable[(int)(x << 4) & MASK_5BITS]; // 5-1 = 4
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ break;
+ case 3 : // 3 octets = 24 bits to use
+ buffer[pos++] = encodeTable[(int)(x >> 19) & MASK_5BITS]; // 24-1*5 = 19
+ buffer[pos++] = encodeTable[(int)(x >> 14) & MASK_5BITS]; // 24-2*5 = 14
+ buffer[pos++] = encodeTable[(int)(x >> 9) & MASK_5BITS]; // 24-3*5 = 9
+ buffer[pos++] = encodeTable[(int)(x >> 4) & MASK_5BITS]; // 24-4*5 = 4
+ buffer[pos++] = encodeTable[(int)(x << 1) & MASK_5BITS]; // 5-4 = 1
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ buffer[pos++] = PAD;
+ break;
+ case 4 : // 4 octets = 32 bits to use
+ buffer[pos++] = encodeTable[(int)(x >> 27) & MASK_5BITS]; // 32-1*5 = 27
+ buffer[pos++] = encodeTable[(int)(x >> 22) & MASK_5BITS]; // 32-2*5 = 22
+ buffer[pos++] = encodeTable[(int)(x >> 17) & MASK_5BITS]; // 32-3*5 = 17
+ buffer[pos++] = encodeTable[(int)(x >> 12) & MASK_5BITS]; // 32-4*5 = 12
+ buffer[pos++] = encodeTable[(int)(x >> 7) & MASK_5BITS]; // 32-5*5 = 7
+ buffer[pos++] = encodeTable[(int)(x >> 2) & MASK_5BITS]; // 32-6*5 = 2
+ buffer[pos++] = encodeTable[(int)(x << 3) & MASK_5BITS]; // 5-2 = 3
+ buffer[pos++] = PAD;
+ break;
+ }
+ // Don't want to append the CRLF two times in a row, so make sure previous
+ // character is not from CRLF!
+ byte b = lineSeparator[lineSeparator.length - 1];
+ if (lineLength > 0 && pos > 0 && buffer[pos-1] != b) {
+ System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
+ pos += lineSeparator.length;
+ }
+ } else {
+ for (int i = 0; i < inAvail; i++) {
+ if (buffer == null || buffer.length - pos < encodeSize) {
+ resizeBuffer();
+ }
+ modulus = (++modulus) % BITS_PER_ENCODED_CHAR;
+ int b = in[inPos++];
+ if (b < 0) {
+ b += 256;
+ }
+ x = (x << 8) + b; // ??
+ if (0 == modulus) { // we have enough bytes to create our output
+ buffer[pos++] = encodeTable[(int)(x >> 35) & MASK_5BITS];
+ buffer[pos++] = encodeTable[(int)(x >> 30) & MASK_5BITS];
+ buffer[pos++] = encodeTable[(int)(x >> 25) & MASK_5BITS];
+ buffer[pos++] = encodeTable[(int)(x >> 20) & MASK_5BITS];
+ buffer[pos++] = encodeTable[(int)(x >> 15) & MASK_5BITS];
+ buffer[pos++] = encodeTable[(int)(x >> 10) & MASK_5BITS];
+ buffer[pos++] = encodeTable[(int)(x >> 5) & MASK_5BITS];
+ buffer[pos++] = encodeTable[(int)x & MASK_5BITS];
+ currentLinePos += BYTES_PER_ENCODED_BLOCK;
+ if (lineLength > 0 && lineLength <= currentLinePos) {
+ System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
+ pos += lineSeparator.length;
+ currentLinePos = 0;
+ }
+ }
+ }
}
- encode(pArray, 0, pArray.length);
- encode(pArray, 0, -1); // Notify encoder of EOF.
- byte[] buf = new byte[pos - readPos];
- readResults(buf, 0, buf.length);
- return buf;
}
/**
- * Pre-calculates the amount of space needed to Base32-encode the supplied array.
- *
- * @param pArray byte[] array which will later be encoded
- * @param chunkSize line-length of the output (<= 0 means no chunking) between each
- * chunkSeparator (e.g. CRLF).
- * @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF).
+ * <p>
+ * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
+ * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
+ * call is not necessary when decoding, but it doesn't hurt, either.
+ * </p>
+ * <p>
+ * Ignores all non-Base32 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
+ * silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
+ * garbage-out philosophy: it will not check the provided data for validity.
+ * </p>
+ *
+ * @param in
+ * byte[] array of ascii data to Base32 decode.
+ * @param inPos
+ * Position to start reading data from.
+ * @param inAvail
+ * Amount of bytes available from input for encoding.
*
- * @return amount of space needed to encoded the supplied array. Returns
- * a long since a max-len array will require Integer.MAX_VALUE + 33%.
+ * Output is written to {@link #buffer} as 8-bit octets, using {@link pos} as the buffer position
*/
- private static long getEncodeLength(byte[] pArray, int chunkSize, byte[] chunkSeparator) {
- // Base32 always encodes to multiples of 8 (BYTES_PER_ENCODED_CHUNK).
- chunkSize = (chunkSize / BYTES_PER_ENCODED_BLOCK) * BYTES_PER_ENCODED_BLOCK;
-
- long len = (pArray.length * BYTES_PER_ENCODED_BLOCK) / BYTES_PER_UNENCODED_BLOCK;
- long mod = len % BYTES_PER_ENCODED_BLOCK;
- if (mod != 0) {
- len += BYTES_PER_ENCODED_BLOCK - mod;
- }
- if (chunkSize > 0) {
- boolean lenChunksPerfectly = len % chunkSize == 0;
- len += (len / chunkSize) * chunkSeparator.length;
- if (!lenChunksPerfectly) {
- len += chunkSeparator.length;
+ void decode(byte[] in, int inPos, int inAvail) { // package protected for access from I/O streams
+ if (eof) {
+ return;
+ }
+ if (inAvail < 0) {
+ eof = true;
+ }
+ for (int i = 0; i < inAvail; i++) {
+ if (buffer == null || buffer.length - pos < decodeSize) {
+ resizeBuffer();
+ }
+ byte b = in[inPos++];
+ if (b == PAD) {
+ // We're done.
+ eof = true;
+ break;
+ } else {
+ if (b >= 0 && b < this.decodeTable.length) {
+ int result = this.decodeTable[b];
+ if (result >= 0) {
+ modulus = (++modulus) % BYTES_PER_ENCODED_BLOCK;
+ x = (x << BITS_PER_ENCODED_CHAR) + result; // collect decoded bytes
+ if (modulus == 0) { // we can output the 5 bytes
+ buffer[pos++] = (byte) ((x >> 32) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x >> 24) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
+ buffer[pos++] = (byte) (x & MASK_8BITS);
+ }
+ }
+ }
+ }
+ }
+
+ // Two forms of EOF as far as Base32 decoder is concerned: actual
+ // EOF (-1) and first time '=' character is encountered in stream.
+ // This approach makes the '=' padding characters completely optional.
+ if (eof && modulus != 0) {
+ if (buffer == null || buffer.length - pos < decodeSize) {
+ resizeBuffer();
+ }
+
+ // we ignore partial bytes, i.e. only multiples of 8 count
+ switch (modulus) {
+ case 2 : // 10 bits, drop 2 and output one byte
+ buffer[pos++] = (byte) ((x >> 2) & MASK_8BITS);
+ break;
+ case 3 : // 15 bits, drop 7 and output 1 byte
+ buffer[pos++] = (byte) ((x >> 7) & MASK_8BITS);
+ break;
+ case 4 : // 20 bits = 2*8 + 4
+ x = x >> 4; // drop 4 bits
+ buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x) & MASK_8BITS);
+ break;
+ case 5 : // 25bits = 3*8 + 1
+ x = x >> 1;
+ buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x) & MASK_8BITS);
+ break;
+ case 6 : // 30bits = 3*8 + 6
+ x = x >> 6;
+ buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x) & MASK_8BITS);
+ break;
+ case 7 : // 35 = 4*8 +3
+ x = x >> 3;
+ buffer[pos++] = (byte) ((x >> 24) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS);
+ buffer[pos++] = (byte) ((x) & MASK_8BITS);
+ break;
}
}
- return len;
}
- /**
- * Resets this Base32 object to its initial newly constructed state.
- */
- private void reset() {
- buffer = null;
- pos = 0;
- readPos = 0;
- currentLinePos = 0;
- modulus = 0;
- eof = false;
- }
+ /**
+ * Pre-calculates the amount of space needed to Base32-encode the supplied array.
+ *
+ * @param pArray byte[] array which will later be encoded
+ * @param chunkSize line-length of the output (<= 0 means no chunking) between each
+ * chunkSeparator (e.g. CRLF).
+ * @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF).
+ *
+ * @return amount of space needed to encoded the supplied array. Returns
+ * a long since a max-len array will require Integer.MAX_VALUE + 33%.
+ */
+ private static long getEncodeLength(byte[] pArray, int chunkSize,
+ byte[] chunkSeparator) {
+ // Base32 always encodes to multiples of 8 (BYTES_PER_ENCODED_CHUNK).
+ chunkSize = (chunkSize / BYTES_PER_ENCODED_BLOCK) * BYTES_PER_ENCODED_BLOCK;
+
+ long len = (pArray.length * BYTES_PER_ENCODED_BLOCK) / BYTES_PER_UNENCODED_BLOCK;
+ long mod = len % BYTES_PER_ENCODED_BLOCK;
+ if (mod != 0) {
+ len += BYTES_PER_ENCODED_BLOCK - mod;
+ }
+ if (chunkSize > 0) {
+ boolean lenChunksPerfectly = len % chunkSize == 0;
+ len += (len / chunkSize) * chunkSeparator.length;
+ if (!lenChunksPerfectly) {
+ len += chunkSeparator.length;
+ }
+ }
+ return len;
+ }
}