
com.upokecenter.mail.Base64Encoder Maven / Gradle / Ivy
package com.upokecenter.mail;
/*
Written by Peter O. in 2014.
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
If you like this, you should donate to Peter O.
at: http://upokecenter.dreamhosters.com/articles/donate-now-2/
*/
import java.io.*;
import com.upokecenter.util.*;
import com.upokecenter.text.*;
/**
* Encodes binary data in Base64.
*/
final class Base64Encoder implements ICharacterEncoder
{
private static final byte[] Base64Classic = {
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f
};
private int lineCount;
private int quantumCount;
private int byte1;
private int byte2;
private boolean padding;
private boolean lenientLineBreaks;
private boolean haveCR;
private boolean unlimitedLineLength;
private byte[] alphabet;
private boolean finalized;
private static byte[] StringAlphabetToBytes(String alphabetString) {
if (alphabetString == null) {
throw new NullPointerException("alphabet");
}
if (alphabetString.length() != 64) {
throw new IllegalArgumentException("alphabet.length (" + alphabetString.length() +
") is not equal to 64");
}
byte[] alphabet = new byte[64];
for (int i = 0; i < alphabetString.length(); ++i) {
if (alphabetString.charAt(i) >= 0x100) {
throw new IllegalArgumentException("alphabet String contains a non-Latin1 character");
}
alphabet[i] = (byte)alphabetString.charAt(i);
}
return alphabet;
}
public Base64Encoder (
boolean padding,
boolean lenientLineBreaks,
boolean unlimitedLineLength) {
this(
padding, lenientLineBreaks, unlimitedLineLength, Base64Classic);
}
public Base64Encoder (
boolean padding,
boolean lenientLineBreaks,
boolean unlimitedLineLength,
String alphabetString) {
this(
padding, lenientLineBreaks, unlimitedLineLength, StringAlphabetToBytes(alphabetString));
}
public Base64Encoder (
boolean padding,
boolean lenientLineBreaks,
boolean unlimitedLineLength,
byte[] alphabet) {
if (alphabet == null) {
throw new NullPointerException("alphabet");
}
if (alphabet.length != 64) {
throw new IllegalArgumentException("alphabet.length (" + alphabet.length +
") is not equal to 64");
}
this.padding = padding;
this.unlimitedLineLength = unlimitedLineLength;
this.lenientLineBreaks = lenientLineBreaks;
this.byte1 = -1;
this.byte2 = -1;
this.alphabet = alphabet;
}
private int LineAwareAppend(IWriter output, byte c) {
int charCount = 0;
if (!this.unlimitedLineLength) {
if (this.lineCount >= 76) {
output.write((byte)0x0d);
output.write((byte)0x0a);
charCount += 2;
this.lineCount = 0;
}
++this.lineCount;
}
output.write((byte)c);
return 1 + charCount;
}
private int LineAwareAppendFour(
IWriter output,
byte c1,
byte c2,
byte c3,
byte c4) {
int charCount = 0;
byte[] bytes = new byte[6];
if (!this.unlimitedLineLength) {
if (this.lineCount >= 76) {
// Output CRLF
bytes[charCount++]=((byte)0x0d);
bytes[charCount++]=((byte)0x0a);
this.lineCount = 0;
} else if (this.lineCount + 3 >= 76) {
charCount += this.LineAwareAppend(output, c1);
charCount += this.LineAwareAppend(output, c2);
charCount += this.LineAwareAppend(output, c3);
charCount += this.LineAwareAppend(output, c4);
return charCount;
}
this.lineCount += 4;
}
bytes[charCount++]=((byte)c1);
bytes[charCount++]=((byte)c2);
bytes[charCount++]=((byte)c3);
bytes[charCount++]=((byte)c4);
output.write(bytes, 0, charCount);
return charCount;
}
private int AddByteInternal(IWriter output, byte b) {
int ib = ((int)b) & 0xff;
if (this.quantumCount == 2) {
int ret = this.LineAwareAppendFour(
output,
this.alphabet[(this.byte1 >> 2) & 63],
this.alphabet[((this.byte1 & 3) << 4) + ((this.byte2 >> 4) & 15)],
this.alphabet[((this.byte2 & 15) << 2) + ((ib >> 6) & 3)],
this.alphabet[ib & 63]);
this.byte1 = -1;
this.byte2 = -1;
this.quantumCount = 0;
return ret;
} else if (this.quantumCount == 1) {
this.byte2 = ib;
this.quantumCount = 2;
return 0;
} else {
this.byte1 = ib;
this.quantumCount = 1;
return 0;
}
}
private int FinalizeEncoding(IWriter output) {
int count = 0;
if (this.quantumCount == 2) {
byte c1 = this.alphabet[(this.byte1 >> 2) & 63];
byte c2 = this.alphabet[((this.byte1 & 3) << 4) + ((this.byte2 >> 4) &
15)];
byte c3 = this.alphabet[((this.byte2 & 15) << 2)];
if (this.padding) {
count += this.LineAwareAppendFour(output, c1, c2, c3, (byte)'=');
} else {
count += this.LineAwareAppend(output, c1);
count += this.LineAwareAppend(output, c2);
count += this.LineAwareAppend(output, c3);
}
this.byte1 = -1;
this.byte2 = -1;
this.quantumCount = 0;
} else if (this.quantumCount == 1) {
byte c1 = this.alphabet[(this.byte1 >> 2) & 63];
byte c2 = this.alphabet[((this.byte1 & 3) << 4)];
if (this.padding) {
count += this.LineAwareAppendFour(output, c1, c2, (byte)'=' , (byte)'='
);
} else {
count += this.LineAwareAppend(output, c1);
count += this.LineAwareAppend(output, c2);
}
this.byte1 = -1;
this.byte2 = -1;
this.quantumCount = 0;
}
this.haveCR = false;
this.finalized = true;
return count;
}
public int Encode(int b, IWriter output) {
if (b < 0) {
return this.finalized ? (-1) : this.FinalizeEncoding(output);
}
b &= 0xff;
int count = 0;
if (this.lenientLineBreaks) {
if (b == 0x0d) {
// CR
this.haveCR = true;
count += this.AddByteInternal(output, (byte)0x0d);
count += this.AddByteInternal(output, (byte)0x0a);
return count;
}
if (b == 0x0a && !this.haveCR) {
// bare LF
if (this.haveCR) {
// Do nothing, this is an LF that follows CR
this.haveCR = false;
} else {
count += this.AddByteInternal(output, (byte)0x0d);
count += this.AddByteInternal(output, (byte)0x0a);
this.haveCR = false;
}
return count;
}
}
count += this.AddByteInternal(output, (byte)b);
this.haveCR = false;
return count;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy