📄 base64.java
字号:
* Valid options:<pre>
* ENCODE or DECODE: Encode or Decode as data is read.
* DONT_BREAK_LINES: don't break lines at 76 characters
* (only meaningful when encoding)
* <i>Note: Technically, this makes your encoding non-compliant.</i>
* </pre>
* <p>
* Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
*
*
* @param in the <tt>java.io.InputStream</tt> from which to read data.
* @param options Specified options
* @see Base64#ENCODE
* @see Base64#DECODE
* @see Base64#DONT_BREAK_LINES
* @since 2.0
*/
public InputStream( java.io.InputStream in, int options )
{
super( in );
this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
this.encode = (options & ENCODE) == ENCODE;
this.bufferLength = encode ? 4 : 3;
this.buffer = new byte[ bufferLength ];
this.position = -1;
this.lineLength = 0;
this.options = options; // Record for later, mostly to determine which alphabet to use
this.alphabet = getAlphabet(options);
this.decodabet = getDecodabet(options);
} // end constructor
/**
* Reads enough of the input stream to convert
* to/from Base64 and returns the next byte.
*
* @return next byte
* @since 1.3
*/
public int read() throws java.io.IOException
{
// Do we need to get data?
if( position < 0 )
{
if( encode )
{
byte[] b3 = new byte[3];
int numBinaryBytes = 0;
for( int i = 0; i < 3; i++ )
{
try
{
int b = in.read();
// If end of stream, b is -1.
if( b >= 0 )
{
b3[i] = (byte)b;
numBinaryBytes++;
} // end if: not end of stream
} // end try: read
catch( java.io.IOException e )
{
// Only a problem if we got no data at all.
if( i == 0 )
throw e;
} // end catch
} // end for: each needed input byte
if( numBinaryBytes > 0 )
{
encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
position = 0;
numSigBytes = 4;
} // end if: got data
else
{
return -1;
} // end else
} // end if: encoding
// Else decoding
else
{
byte[] b4 = new byte[4];
int i = 0;
for( i = 0; i < 4; i++ )
{
// Read four "meaningful" bytes:
int b = 0;
do{ b = in.read(); }
while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
if( b < 0 )
break; // Reads a -1 if end of stream
b4[i] = (byte)b;
} // end for: each needed input byte
if( i == 4 )
{
numSigBytes = decode4to3( b4, 0, buffer, 0, options );
position = 0;
} // end if: got four characters
else if( i == 0 ){
return -1;
} // end else if: also padded correctly
else
{
// Must have broken out from above.
throw new java.io.IOException( "Improperly padded Base64 input." );
} // end
} // end else: decode
} // end else: get data
// Got data?
if( position >= 0 )
{
// End of relevant data?
if( /*!encode &&*/ position >= numSigBytes )
return -1;
if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
{
lineLength = 0;
return '\n';
} // end if
else
{
lineLength++; // This isn't important when decoding
// but throwing an extra "if" seems
// just as wasteful.
int b = buffer[ position++ ];
if( position >= bufferLength )
position = -1;
return b & 0xFF; // This is how you "cast" a byte that's
// intended to be unsigned.
} // end else
} // end if: position >= 0
// Else error
else
{
// When JDK1.4 is more accepted, use an assertion here.
throw new java.io.IOException( "Error in Base64 code reading stream." );
} // end else
} // end read
/**
* Calls {@link #read()} repeatedly until the end of stream
* is reached or <var>len</var> bytes are read.
* Returns number of bytes read into array or -1 if
* end of stream is encountered.
*
* @param dest array to hold values
* @param off offset for array
* @param len max number of bytes to read into array
* @return bytes read into array or -1 if end of stream is encountered.
* @since 1.3
*/
public int read( byte[] dest, int off, int len ) throws java.io.IOException
{
int i;
int b;
for( i = 0; i < len; i++ )
{
b = read();
//if( b < 0 && i == 0 )
// return -1;
if( b >= 0 )
dest[off + i] = (byte)b;
else if( i == 0 )
return -1;
else
break; // Out of 'for' loop
} // end for: each byte read
return i;
} // end read
} // end inner class InputStream
/* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
/**
* A {@link Base64.OutputStream} will write data to another
* <tt>java.io.OutputStream</tt>, given in the constructor,
* and encode/decode to/from Base64 notation on the fly.
*
* @see Base64
* @since 1.3
*/
public static class OutputStream extends java.io.FilterOutputStream
{
private boolean encode;
private int position;
private byte[] buffer;
private int bufferLength;
private int lineLength;
private boolean breakLines;
private byte[] b4; // Scratch used in a few places
private boolean suspendEncoding;
private int options; // Record for later
private byte[] alphabet; // Local copies to avoid extra method calls
private byte[] decodabet; // Local copies to avoid extra method calls
/**
* Constructs a {@link Base64.OutputStream} in ENCODE mode.
*
* @param out the <tt>java.io.OutputStream</tt> to which data will be written.
* @since 1.3
*/
public OutputStream( java.io.OutputStream out )
{
this( out, ENCODE );
} // end constructor
/**
* Constructs a {@link Base64.OutputStream} in
* either ENCODE or DECODE mode.
* <p>
* Valid options:<pre>
* ENCODE or DECODE: Encode or Decode as data is read.
* DONT_BREAK_LINES: don't break lines at 76 characters
* (only meaningful when encoding)
* <i>Note: Technically, this makes your encoding non-compliant.</i>
* </pre>
* <p>
* Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
*
* @param out the <tt>java.io.OutputStream</tt> to which data will be written.
* @param options Specified options.
* @see Base64#ENCODE
* @see Base64#DECODE
* @see Base64#DONT_BREAK_LINES
* @since 1.3
*/
public OutputStream( java.io.OutputStream out, int options )
{
super( out );
this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
this.encode = (options & ENCODE) == ENCODE;
this.bufferLength = encode ? 3 : 4;
this.buffer = new byte[ bufferLength ];
this.position = 0;
this.lineLength = 0;
this.suspendEncoding = false;
this.b4 = new byte[4];
this.options = options;
this.alphabet = getAlphabet(options);
this.decodabet = getDecodabet(options);
} // end constructor
/**
* Writes the byte to the output stream after
* converting to/from Base64 notation.
* When encoding, bytes are buffered three
* at a time before the output stream actually
* gets a write() call.
* When decoding, bytes are buffered four
* at a time.
*
* @param theByte the byte to write
* @since 1.3
*/
public void write(int theByte) throws java.io.IOException
{
// Encoding suspended?
if( suspendEncoding )
{
super.out.write( theByte );
return;
} // end if: supsended
// Encode?
if( encode )
{
buffer[ position++ ] = (byte)theByte;
if( position >= bufferLength ) // Enough to encode.
{
out.write( encode3to4( b4, buffer, bufferLength, options ) );
lineLength += 4;
if( breakLines && lineLength >= MAX_LINE_LENGTH )
{
out.write( NEW_LINE );
lineLength = 0;
} // end if: end of line
position = 0;
} // end if: enough to output
} // end if: encoding
// Else, Decoding
else
{
// Meaningful Base64 character?
if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC )
{
buffer[ position++ ] = (byte)theByte;
if( position >= bufferLength ) // Enough to output.
{
int len = Base64.decode4to3( buffer, 0, b4, 0, options );
out.write( b4, 0, len );
//out.write( Base64.decode4to3( buffer ) );
position = 0;
} // end if: enough to output
} // end if: meaningful base64 character
else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC )
{
throw new java.io.IOException( "Invalid character in Base64 data." );
} // end else: not white space either
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -