org.apache.vinci.transport.util.Base64Converter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jVinci Show documentation
Show all versions of jVinci Show documentation
This is a non-standard protocol for higher efficiency than
SOAP, used by the base UIMA Collection processing manager for supporting
networked deployment. See UIMA-AS as a more modern alternative supporting
more standard protocols.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.vinci.transport.util;
/**
* Provides utility methods for Binary <=> Base64 conversion.
*/
public class Base64Converter {
/**
* If you ask for line-breaks, this is the maximum line length used.
*/
static public final int LINE_LENGTH = 70;
static private final byte[] B64_CODE = { (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D',
(byte) 'E', (byte) 'F', (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K',
(byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R',
(byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y',
(byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f',
(byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm',
(byte) 'n', (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't',
(byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0',
(byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7',
(byte) '8', (byte) '9', (byte) '+', (byte) '/' };
/**
* Utility class not meant to be instantiated.
*/
private Base64Converter() {
}
/**
* @pre from != null
* @param from -
* @return -
*/
static public byte[] convertBinaryToBase64(byte[] from) {
return convertBinaryToBase64(from, from.length, true);
}
/**
* @pre convert_me != null
* @param convert_me -
* @return -
*/
static public String convertStringToBase64String(String convert_me) {
return new String(convertBinaryToBase64(convert_me.getBytes()));
}
/**
* @pre base64 != null
* @param base64 -
* @return -
* @throws Base64FormatException -
*/
static public String convertBase64StringToString(String base64) throws Base64FormatException {
return new String(convertBase64ToBinary(base64.getBytes()));
}
/**
* @pre count ≤ from.length
* @param from -
* @param count -
* @param line_breaks -
* @return -
*/
static public byte[] convertBinaryToBase64(byte[] from, final int count, boolean line_breaks) {
int size = calculateBase64OutputSize(count, line_breaks);
byte[] tmp = new byte[size];
int used = 0;
for (int done = 0; done < count; done += 3) {
b64encodeOctet(tmp, used, from, done, count - done);
used += 4;
}
if (line_breaks) {
byte[] to = new byte[size];
int pos = 0;
for (int breaks = 0; breaks < used; breaks += LINE_LENGTH) {
int length = used - breaks;
if (length > LINE_LENGTH) {
length = LINE_LENGTH;
}
System.arraycopy(tmp, breaks, to, pos, length);
pos += length;
to[pos++] = (byte) '\n';
}
// Debug.Assert(pos == to.length);
return to;
} else {
// Debug.Assert(used == tmp.length);
return tmp;
}
}
/**
* Calculates the size of the resulting Base64 string returned by this class for a binary byte
* array of the specified length. Includes carriage returns and all.
* @param input_size -
* @param line_breaks -
* @return -
*/
static public int calculateBase64OutputSize(int input_size, boolean line_breaks) {
int q = input_size / 3;
if (input_size % 3 != 0) {
q += 1;
}
// Output is always a multiple of 4 characters.
q *= 4;
// Factor in the extra length needed for line breaks.
if (line_breaks) {
q += (q / LINE_LENGTH) + (q % LINE_LENGTH == 0 ? 0 : 1);
}
return q;
}
/**
* @pre input != null
* @param input -
* @return -
* @throws Base64FormatException -
*/
static public byte[] convertBase64ToBinary(byte[] input) throws Base64FormatException {
return convertBase64ToBinary(input, input.length);
}
/**
* @pre input != null
* @pre input_size ≤ input.length
* @param input -
* @param input_size -
* @return -
* @throws Base64FormatException -
*/
static public byte[] convertBase64ToBinary(byte[] input, final int input_size)
throws Base64FormatException {
int output_size = calculateBinaryOutputSize(input, input_size);
byte[] output = new byte[output_size];
int pos = 0;
int i = 0;
while (pos + 4 <= input_size) {
pos = b64decodeOctet(input, pos, output, 3 * i, input_size);
i++;
}
return output;
}
/**
* Calculate the number of bytes encoded by a given Base64 input.
*
* @pre input != null
* @pre input_size ≤ input.length
* @param input -
* @param input_size -
* @return -
* @throws Base64FormatException -
*/
static public int calculateBinaryOutputSize(byte[] input, final int input_size)
throws Base64FormatException {
int output_size = 0;
for (int i = 0; i + 4 <= input_size;) {
i = consumeInvalidDigits(input, i, input_size);
i++;
i = consumeInvalidDigits(input, i, input_size);
i++;
i = consumeInvalidDigits(input, i, input_size);
if (input[i] == (byte) '=') {
output_size += 1;
break;
}
i++;
i = consumeInvalidDigits(input, i, input_size);
if (input[i] == (byte) '=') {
output_size += 2;
break;
}
i++;
output_size += 3;
}
return output_size;
}
static private int consumeInvalidDigits(byte[] in, int off, int max_offset)
throws Base64FormatException {
if (off >= max_offset) {
throw new Base64FormatException("short read");
}
while (!b64validDigit(in[off])) {
off++;
if (off >= max_offset) {
throw new Base64FormatException("short read");
}
}
return off;
}
/**
* @pre in != null
* @pre out != null
*/
static private int b64decodeOctet(byte[] in, int in_offset, byte[] out, int out_offset,
int max_offset) throws Base64FormatException {
int A;
int B;
int C;
int D;
in_offset = consumeInvalidDigits(in, in_offset, max_offset);
A = in[in_offset++];
if (A < 0) {
throw new Base64FormatException();
}
in_offset = consumeInvalidDigits(in, in_offset, max_offset);
B = in[in_offset++];
if (B < 0) {
throw new Base64FormatException();
}
in_offset = consumeInvalidDigits(in, in_offset, max_offset);
C = in[in_offset++];
in_offset = consumeInvalidDigits(in, in_offset, max_offset);
D = in[in_offset++];
A = b64decodeDigit(A);
A <<= 2;
B = b64decodeDigit(B);
A |= (B >> 4);
out[out_offset] = (byte) A;
B <<= 4;
C = b64decodeDigit(C);
if (C < 0) {
return max_offset; // we are done
}
B |= C >> 2;
out[out_offset + 1] = (byte) B;
C <<= 6;
D = b64decodeDigit(D);
if (D < 0) {
return max_offset; // we are done
}
C |= D;
out[out_offset + 2] = (byte) C;
return in_offset;
}
static private int b64decodeDigit(int c) {
if (c >= (byte) 'A' && c <= (byte) 'Z') {
return c - (byte) 'A';
} else if (c >= (byte) 'a' && c <= (byte) 'z') {
return c - (byte) 'a' + 26;
} else if (c >= (byte) '0' && c <= (byte) '9') {
return c - (byte) '0' + 52;
} else if (c == (byte) '+') {
return 62;
} else if (c == (byte) '/') {
return 63;
} else if (c == (byte) '=') {
return -2;
}
return -1;
}
static private boolean b64validDigit(byte a) {
if (a >= (byte) 'A' && a <= (byte) 'Z') {
return true;
}
if (a >= (byte) 'a' && a <= (byte) 'z') {
return true;
}
if (a >= (byte) '0' && a <= (byte) '9') {
return true;
}
if (a == (byte) '/' || a == (byte) '+' || a == (byte) '=') {
return true;
}
return false;
}
static private void b64encodeOctet(byte[] to, int to_offset, byte[] from, int from_offset,
int count) {
int A = 0;
int B = 0;
int C = 0;
int D = 0;
int tmp = 0;
A = from[from_offset];
if (A < 0) {
A += 256;
}
A >>= 2;
B = from[from_offset];
if (B < 0) {
B += 256;
}
B &= 3;
B <<= 4;
if (count > 1) {
tmp = from[from_offset + 1] < 0 ? (from[from_offset + 1]) + 256 : from[from_offset + 1];
B |= tmp >> 4;
C = from[from_offset + 1];
if (C < 0) {
C += 256;
}
C &= 15;
C <<= 2;
}
if (count > 2) {
tmp = from[from_offset + 2] < 0 ? (from[from_offset + 2]) + 256 : from[from_offset + 2];
C |= tmp >> 6;
D = from[from_offset + 2];
if (D < 0) {
D += 256;
}
D &= 0x3F;
}
to[to_offset] = b64codes(A);
to[to_offset + 1] = b64codes(B);
if (count > 1) {
to[to_offset + 2] = b64codes(C);
} else {
to[to_offset + 2] = (byte) '=';
}
if (count > 2) {
to[to_offset + 3] = b64codes(D);
} else {
to[to_offset + 3] = (byte) '=';
}
}
static private byte b64codes(int which) {
if (which < 0) {
which += 256;
}
return B64_CODE[which];
}
/*
* public static void main(String[] args) throws Base64FormatException { int to = 256; if
* (args.length > 0) { to = Integer.parseInt(args[0]); } System.out.println("TESTING case: " +
* to); byte[] input = new byte[to]; for (int i=0; i 0) { // Test all
* cases all the way down to 0 length arrays args[0] = Integer.toString(to-1); main(args); } }
*/
} // class
© 2015 - 2024 Weber Informatics LLC | Privacy Policy