* Modified Base64 to use ChannelBuffer instead of byte[] in most cases

* Added a bunch of overloaded methods to Base64
This commit is contained in:
Trustin Lee 2008-12-29 11:41:34 +00:00
parent afcd2b8315
commit 051a6d0a07
2 changed files with 155 additions and 47 deletions

View File

@ -27,7 +27,8 @@
package org.jboss.netty.handler.codec.base64; package org.jboss.netty.handler.codec.base64;
import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.buffer.ChannelBufferFactory;
import org.jboss.netty.buffer.HeapChannelBufferFactory;
/** /**
* Utility class for {@link ChannelBuffer} that encodes and decodes to and from * Utility class for {@link ChannelBuffer} that encodes and decodes to and from
@ -44,34 +45,55 @@ import org.jboss.netty.buffer.ChannelBuffers;
public class Base64 { public class Base64 {
/** Maximum line length (76) of Base64 output. */ /** Maximum line length (76) of Base64 output. */
private final static int MAX_LINE_LENGTH = 76; private static final int MAX_LINE_LENGTH = 76;
/** The equals sign (=) as a byte. */ /** The equals sign (=) as a byte. */
private final static byte EQUALS_SIGN = (byte) '='; private static final byte EQUALS_SIGN = (byte) '=';
/** The new line character (\n) as a byte. */ /** The new line character (\n) as a byte. */
private final static byte NEW_LINE = (byte) '\n'; private static final byte NEW_LINE = (byte) '\n';
private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding private static final byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding private static final byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
private final static byte[] getAlphabet(Base64Dialect dialect) { private static final byte[] alphabet(Base64Dialect dialect) {
if (dialect == null) { if (dialect == null) {
throw new NullPointerException("dialect"); throw new NullPointerException("dialect");
} }
return dialect.alphabet; return dialect.alphabet;
} }
private final static byte[] getDecodabet(Base64Dialect dialect) { private static final byte[] decodabet(Base64Dialect dialect) {
if (dialect == null) { if (dialect == null) {
throw new NullPointerException("dialect"); throw new NullPointerException("dialect");
} }
return dialect.decodabet; return dialect.decodabet;
} }
private static final boolean breakLines(Base64Dialect dialect) {
if (dialect == null) {
throw new NullPointerException("dialect");
}
return breakLines(dialect);
}
public static ChannelBuffer encode(ChannelBuffer src) { public static ChannelBuffer encode(ChannelBuffer src) {
return encode(src, true); return encode(src, Base64Dialect.STANDARD);
}
public static ChannelBuffer encode(ChannelBuffer src, Base64Dialect dialect) {
return encode(src, breakLines(dialect), dialect);
}
public static ChannelBuffer encode(
ChannelBuffer src, ChannelBufferFactory bufferFactory) {
return encode(src, Base64Dialect.STANDARD, bufferFactory);
}
public static ChannelBuffer encode(
ChannelBuffer src, Base64Dialect dialect, ChannelBufferFactory bufferFactory) {
return encode(src, breakLines(dialect), dialect, bufferFactory);
} }
public static ChannelBuffer encode(ChannelBuffer src, boolean breakLines) { public static ChannelBuffer encode(ChannelBuffer src, boolean breakLines) {
@ -80,14 +102,41 @@ public class Base64 {
public static ChannelBuffer encode( public static ChannelBuffer encode(
ChannelBuffer src, boolean breakLines, Base64Dialect dialect) { ChannelBuffer src, boolean breakLines, Base64Dialect dialect) {
return encode(src, breakLines, dialect, HeapChannelBufferFactory.getInstance());
}
public static ChannelBuffer encode(
ChannelBuffer src, boolean breakLines, ChannelBufferFactory bufferFactory) {
return encode(src, breakLines, Base64Dialect.STANDARD, bufferFactory);
}
public static ChannelBuffer encode(
ChannelBuffer src, boolean breakLines, Base64Dialect dialect, ChannelBufferFactory bufferFactory) {
if (src == null) {
throw new NullPointerException("src");
}
ChannelBuffer dest = encode( ChannelBuffer dest = encode(
src, src.readerIndex(), src.readableBytes(), breakLines, dialect); src, src.readerIndex(), src.readableBytes(), breakLines, dialect, bufferFactory);
src.readerIndex(src.writerIndex()); src.readerIndex(src.writerIndex());
return dest; return dest;
} }
public static ChannelBuffer encode(ChannelBuffer src, int off, int len) { public static ChannelBuffer encode(ChannelBuffer src, int off, int len) {
return encode(src, off, len, true); return encode(src, off, len, Base64Dialect.STANDARD);
}
public static ChannelBuffer encode(ChannelBuffer src, int off, int len, Base64Dialect dialect) {
return encode(src, off, len, breakLines(dialect), dialect);
}
public static ChannelBuffer encode(ChannelBuffer src, int off, int len, ChannelBufferFactory bufferFactory) {
return encode(src, off, len, Base64Dialect.STANDARD, bufferFactory);
}
public static ChannelBuffer encode(ChannelBuffer src, int off, int len, Base64Dialect dialect, ChannelBufferFactory bufferFactory) {
return encode(src, off, len, breakLines(dialect), dialect, bufferFactory);
} }
public static ChannelBuffer encode( public static ChannelBuffer encode(
@ -98,10 +147,34 @@ public class Base64 {
public static ChannelBuffer encode( public static ChannelBuffer encode(
ChannelBuffer src, int off, int len, ChannelBuffer src, int off, int len,
boolean breakLines, Base64Dialect dialect) { boolean breakLines, Base64Dialect dialect) {
return encode(src, off, len, breakLines, dialect, HeapChannelBufferFactory.getInstance());
}
public static ChannelBuffer encode(
ChannelBuffer src, int off, int len,
boolean breakLines, ChannelBufferFactory bufferFactory) {
return encode(src, off, len, breakLines, Base64Dialect.STANDARD, bufferFactory);
}
public static ChannelBuffer encode(
ChannelBuffer src, int off, int len,
boolean breakLines, Base64Dialect dialect, ChannelBufferFactory bufferFactory) {
if (src == null) {
throw new NullPointerException("src");
}
if (dialect == null) {
throw new NullPointerException("dialect");
}
if (bufferFactory == null) {
throw new NullPointerException("bufferFactory");
}
int len43 = len * 4 / 3; int len43 = len * 4 / 3;
byte[] dest = new byte[len43 + (len % 3 > 0? 4 : 0) + // Account for padding ChannelBuffer dest = bufferFactory.getBuffer(
(breakLines? len43 / MAX_LINE_LENGTH : 0)]; // New lines len43 +
(len % 3 > 0? 4 : 0) + // Account for padding
(breakLines? len43 / MAX_LINE_LENGTH : 0)); // New lines
int d = 0; int d = 0;
int e = 0; int e = 0;
int len2 = len - 2; int len2 = len - 2;
@ -111,7 +184,7 @@ public class Base64 {
lineLength += 4; lineLength += 4;
if (breakLines && lineLength == MAX_LINE_LENGTH) { if (breakLines && lineLength == MAX_LINE_LENGTH) {
dest[e + 4] = NEW_LINE; dest.setByte(e + 4, NEW_LINE);
e ++; e ++;
lineLength = 0; lineLength = 0;
} // end if: end of line } // end if: end of line
@ -122,14 +195,14 @@ public class Base64 {
e += 4; e += 4;
} // end if: some padding needed } // end if: some padding needed
return ChannelBuffers.wrappedBuffer(dest, 0, e); return dest.slice(0, e);
} }
private static byte[] encode3to4( private static void encode3to4(
ChannelBuffer src, int srcOffset, int numSigBytes, ChannelBuffer src, int srcOffset, int numSigBytes,
byte[] dest, int destOffset, Base64Dialect dialect) { ChannelBuffer dest, int destOffset, Base64Dialect dialect) {
byte[] ALPHABET = getAlphabet(dialect); byte[] ALPHABET = alphabet(dialect);
// 1 2 3 // 1 2 3
// 01234567890123456789012345678901 Bit position // 01234567890123456789012345678901 Bit position
@ -149,25 +222,24 @@ public class Base64 {
switch (numSigBytes) { switch (numSigBytes) {
case 3: case 3:
dest[destOffset ] = ALPHABET[inBuff >>> 18 ]; dest.setByte(destOffset , ALPHABET[inBuff >>> 18 ]);
dest[destOffset + 1] = ALPHABET[inBuff >>> 12 & 0x3f]; dest.setByte(destOffset + 1, ALPHABET[inBuff >>> 12 & 0x3f]);
dest[destOffset + 2] = ALPHABET[inBuff >>> 6 & 0x3f]; dest.setByte(destOffset + 2, ALPHABET[inBuff >>> 6 & 0x3f]);
dest[destOffset + 3] = ALPHABET[inBuff & 0x3f]; dest.setByte(destOffset + 3, ALPHABET[inBuff & 0x3f]);
break; break;
case 2: case 2:
dest[destOffset ] = ALPHABET[inBuff >>> 18 ]; dest.setByte(destOffset , ALPHABET[inBuff >>> 18 ]);
dest[destOffset + 1] = ALPHABET[inBuff >>> 12 & 0x3f]; dest.setByte(destOffset + 1, ALPHABET[inBuff >>> 12 & 0x3f]);
dest[destOffset + 2] = ALPHABET[inBuff >>> 6 & 0x3f]; dest.setByte(destOffset + 2, ALPHABET[inBuff >>> 6 & 0x3f]);
dest[destOffset + 3] = EQUALS_SIGN; dest.setByte(destOffset + 3, EQUALS_SIGN);
break; break;
case 1: case 1:
dest[destOffset ] = ALPHABET[inBuff >>> 18 ]; dest.setByte(destOffset , ALPHABET[inBuff >>> 18 ]);
dest[destOffset + 1] = ALPHABET[inBuff >>> 12 & 0x3f]; dest.setByte(destOffset + 1, ALPHABET[inBuff >>> 12 & 0x3f]);
dest[destOffset + 2] = EQUALS_SIGN; dest.setByte(destOffset + 2, EQUALS_SIGN);
dest[destOffset + 3] = EQUALS_SIGN; dest.setByte(destOffset + 3, EQUALS_SIGN);
break; break;
} }
return dest;
} }
public static ChannelBuffer decode(ChannelBuffer src) { public static ChannelBuffer decode(ChannelBuffer src) {
@ -175,7 +247,20 @@ public class Base64 {
} }
public static ChannelBuffer decode(ChannelBuffer src, Base64Dialect dialect) { public static ChannelBuffer decode(ChannelBuffer src, Base64Dialect dialect) {
ChannelBuffer dest = decode(src, src.readerIndex(), src.readableBytes(), dialect); return decode(src, dialect, HeapChannelBufferFactory.getInstance());
}
public static ChannelBuffer decode(ChannelBuffer src, ChannelBufferFactory bufferFactory) {
return decode(src, Base64Dialect.STANDARD, bufferFactory);
}
public static ChannelBuffer decode(ChannelBuffer src, Base64Dialect dialect, ChannelBufferFactory bufferFactory) {
if (src == null) {
throw new NullPointerException("src");
}
ChannelBuffer dest = decode(src, src.readerIndex(), src.readableBytes(), dialect, bufferFactory);
src.readerIndex(src.writerIndex()); src.readerIndex(src.writerIndex());
return dest; return dest;
} }
@ -187,11 +272,32 @@ public class Base64 {
public static ChannelBuffer decode( public static ChannelBuffer decode(
ChannelBuffer src, int off, int len, Base64Dialect dialect) { ChannelBuffer src, int off, int len, Base64Dialect dialect) {
return decode(src, off, len, dialect, HeapChannelBufferFactory.getInstance());
}
byte[] DECODABET = getDecodabet(dialect); public static ChannelBuffer decode(
ChannelBuffer src, int off, int len, ChannelBufferFactory bufferFactory) {
return decode(src, off, len, Base64Dialect.STANDARD, bufferFactory);
}
public static ChannelBuffer decode(
ChannelBuffer src, int off, int len, Base64Dialect dialect,
ChannelBufferFactory bufferFactory) {
if (src == null) {
throw new NullPointerException("src");
}
if (dialect == null) {
throw new NullPointerException("dialect");
}
if (bufferFactory == null) {
throw new NullPointerException("bufferFactory");
}
byte[] DECODABET = decodabet(dialect);
int len34 = len * 3 / 4; int len34 = len * 3 / 4;
byte[] dest = new byte[len34]; // Upper limit on size of output ChannelBuffer dest = bufferFactory.getBuffer(len34); // Upper limit on size of output
int outBuffPosn = 0; int outBuffPosn = 0;
byte[] b4 = new byte[4]; byte[] b4 = new byte[4];
@ -225,14 +331,14 @@ public class Base64 {
} }
} }
return ChannelBuffers.wrappedBuffer(dest, 0, outBuffPosn); return dest.slice(0, outBuffPosn);
} }
private static int decode4to3( private static int decode4to3(
byte[] src, int srcOffset, byte[] src, int srcOffset,
byte[] dest, int destOffset, Base64Dialect dialect) { ChannelBuffer dest, int destOffset, Base64Dialect dialect) {
byte[] DECODABET = getDecodabet(dialect); byte[] DECODABET = decodabet(dialect);
// Example: Dk== // Example: Dk==
if (src[srcOffset + 2] == EQUALS_SIGN) { if (src[srcOffset + 2] == EQUALS_SIGN) {
@ -240,7 +346,7 @@ public class Base64 {
(DECODABET[src[srcOffset ]] & 0xFF) << 18 | (DECODABET[src[srcOffset ]] & 0xFF) << 18 |
(DECODABET[src[srcOffset + 1]] & 0xFF) << 12; (DECODABET[src[srcOffset + 1]] & 0xFF) << 12;
dest[destOffset] = (byte) (outBuff >>> 16); dest.setByte(destOffset, (byte) (outBuff >>> 16));
return 1; return 1;
} }
@ -251,8 +357,8 @@ public class Base64 {
(DECODABET[src[srcOffset + 1]] & 0xFF) << 12 | (DECODABET[src[srcOffset + 1]] & 0xFF) << 12 |
(DECODABET[src[srcOffset + 2]] & 0xFF) << 6; (DECODABET[src[srcOffset + 2]] & 0xFF) << 6;
dest[destOffset ] = (byte) (outBuff >>> 16); dest.setByte(destOffset , (byte) (outBuff >>> 16));
dest[destOffset + 1] = (byte) (outBuff >>> 8); dest.setByte(destOffset + 1, (byte) (outBuff >>> 8));
return 2; return 2;
} }
@ -265,9 +371,9 @@ public class Base64 {
(DECODABET[src[srcOffset + 2]] & 0xFF) << 6 | (DECODABET[src[srcOffset + 2]] & 0xFF) << 6 |
DECODABET[src[srcOffset + 3]] & 0xFF; DECODABET[src[srcOffset + 3]] & 0xFF;
dest[destOffset ] = (byte) (outBuff >> 16); dest.setByte(destOffset , (byte) (outBuff >> 16));
dest[destOffset + 1] = (byte) (outBuff >> 8); dest.setByte(destOffset + 1, (byte) (outBuff >> 8));
dest[destOffset + 2] = (byte) outBuff; dest.setByte(destOffset + 2, (byte) outBuff);
return 3; return 3;
} catch (Exception e) { } catch (Exception e) {
throw new IllegalArgumentException("not encoded in Base64"); throw new IllegalArgumentException("not encoded in Base64");

View File

@ -89,7 +89,7 @@ public enum Base64Dialect {
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
}), }, true),
/** /**
* Base64-like encoding that is URL-safe as described in the Section 4 of * Base64-like encoding that is URL-safe as described in the Section 4 of
* <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>. It is * <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>. It is
@ -148,7 +148,7 @@ public enum Base64Dialect {
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
}), }, false),
/** /**
* Special "ordered" dialect of Base64 described in * Special "ordered" dialect of Base64 described in
* <a href="http://www.faqs.org/qa/rfcc-1940.html">RFC1940</a>. * <a href="http://www.faqs.org/qa/rfcc-1940.html">RFC1940</a>.
@ -204,13 +204,15 @@ public enum Base64Dialect {
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */
}); }, true);
final byte[] alphabet; final byte[] alphabet;
final byte[] decodabet; final byte[] decodabet;
final boolean breakLinesByDefault;
private Base64Dialect(byte[] alphabet, byte[] decodabet) { private Base64Dialect(byte[] alphabet, byte[] decodabet, boolean breakLinesByDefault) {
this.alphabet = alphabet; this.alphabet = alphabet;
this.decodabet = decodabet; this.decodabet = decodabet;
this.breakLinesByDefault = breakLinesByDefault;
} }
} }