All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.ut.Base64 Maven / Gradle / Ivy

There is a newer version: 2024.11.18598.20241113T125352Z-241000
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright 2005 Adobe Systems Incorporated All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Adobe Systems Incorporated and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Adobe Systems
 * Incorporated and its suppliers and may be covered by U.S. and Foreign
 * Patents, patents in process, and are protected by trade secret or copyright
 * law. Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained from
 * Adobe Systems Incorporated.
 */
package com.adobe.xfa.ut;


/**
 * Utility class for Base64 encoding and decoding
 *
 * @exclude from published api.
 */
public final class Base64 {

	private static final char cBase64Pad = '=';

	// 127 is the "invalid" value
	private static final byte[] szBase64Decoding = {
		127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 
		127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 
		127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,  62, 127, 127, 127, 63, 
		 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 127, 127, 127, 127, 127, 127, 
		127,   0,   1,   2,   3,  4,    5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
		 15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25, 127, 127, 127, 127, 127,
		127,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
		 41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51, 127, 127, 127, 127, 127,
	};

	private static final String szBase64Encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

	// This method has been optimized for decoding chars
	// It will not use the template implementation
	private static void decode(byte[] pData, String pEncoded) {
		// BaseBase64Decode (pData, nResultSize, pEncoded, nInputLength,
		// pnNumUnDecodedChars);

		int nCount = 0;
		int nAccumulator = 0;
		int nBits = 0;
		int resultPos = 0;

		// Check for an empty string
		if (pEncoded.length() == 0)
			return;

		while (nCount < pEncoded.length()) {
			int iChar = pEncoded.charAt(nCount);
			// Check for the end of the base 64 encoded data
			if (iChar == '=')
				break;

			// ignore new lines and white space
			// '\n', '\r', ' ', '\t'
			if (iChar < 33
				&& (iChar == '\n' || iChar == '\r' || iChar == ' '
						|| iChar == '\t')) {
					nCount++;
					continue;
				}

			// wait to do the assignment on nDecodedChar until iChar is checked
			// to be within the range of the szBase64Decoding table
			byte nDecodedChar;
			if (iChar > 127 || szBase64Decoding[iChar] > 63)
				throw new ExFull(ResId.ILLEGAL_BASE64_ENCODING);
			
			nDecodedChar = szBase64Decoding[iChar];
			nAccumulator <<= 6;
			nAccumulator |= nDecodedChar;
			nBits += 6;
			if (nBits >= 8) {
				pData[resultPos++] = (byte) (nAccumulator >> (nBits - 8));
				nBits -= 8;
			}

			nCount++;
		}
		// if the "extra" bits aren't 0, the data was wrong
		if (nBits != 0
			&& (nAccumulator & ((~0 << nBits) ^ ~0)) != 0)
				throw new ExFull(ResId.ILLEGAL_BASE64_ENCODING);
	}

	// // Enables encoding a large base64 data block by calling the method
	// // several times, will not add padding characters until the last part.
	// void Base64EncodePart(byte[] pEncoded,
	// byte[] pData,
	// char[] pcRemaining,
	// int& nNumRemaining,
	// int nStartIndex,
	// long& nAccumulator,
	// int& nChars,
	// int& nEncodedLength,
	// int nMaxEncodeLength,
	// int nDataSize,
	// boolean bLastPart,
	// boolean bBreakLines)
	// {
	// int nBits = 0;
	// int nCount;
	// int nTotal = 0;
	//
	// // return if we have no data
	// if (nDataSize == 0 || pData == null)
	// {
	// *pEncoded = 0;
	// nNumRemaining = 0;
	// nEncodedLength = 0;
	// return;
	// }
	//
	// // reset the number of buffered characters
	// nNumRemaining = 0;
	//
	// for (nCount = 0; nCount < nDataSize; nCount++)
	// {
	// // add a line feed every 76 characters (as per the base64 specification
	// // in the MIME standard)
	// if (bBreakLines && nChars % 76 == 0 && nChars != 0)
	// {
	// if (nTotal < nMaxEncodeLength)
	// {
	// pEncoded[nStartIndex+nTotal] = '\n';
	// nTotal++;
	// }
	// else
	// pcRemaining[nNumRemaining++] = '\n';
	// }
	//
	// // collect another character
	// nAccumulator <<= 8;
	// // thought about just casting to unsigned char * instead of to int and
	// then masking,
	// // but wasn't sure if that was portable
	// nAccumulator |= (int)((char *)pData)[nCount] & 0xffl;
	// nBits += 8;
	//
	// // encode all the 6-bit groups we have
	// while (nBits >= 6)
	// {
	// if (nTotal < nMaxEncodeLength)
	// {
	// pEncoded[nStartIndex+nTotal] = szBase64Encoding [(nAccumulator >> (nBits
	// - 6)) & 0x3f];
	// nTotal++;
	// }
	// else
	// pcRemaining[nNumRemaining++] = szBase64Encoding [(nAccumulator >> (nBits
	// - 6)) & 0x3f];
	//				
	// nChars++;
	// nBits -= 6;
	// }
	// }
	//			
	// if (nBits != 0 && bLastPart)
	// {
	// pEncoded[nStartIndex+nTotal] = szBase64Encoding [(nAccumulator << (6 -
	// nBits)) & 0x3f];
	// nTotal++;
	// pEncoded[nStartIndex+nTotal] = cBase64Pad; // we need at least one pad
	// character
	// nTotal++;
	// if (nDataSize % 3 == 1)
	// {
	// pEncoded[nStartIndex+nTotal] = cBase64Pad; // in this case we need an
	// extra pad character
	// nTotal++;
	// }
	// }
	//
	// nEncodedLength = nStartIndex+nTotal;
	// }

	public static byte[] decode(String sEncoded) {
		int nBufferLength = decodeLength(sEncoded.length());
		byte[] szResult = new byte[nBufferLength];
		decode(szResult, sEncoded);

		return szResult;
	}

	private static int decodeLength(int nLength) {
		// the length will always be an exact multiple of
		// four, after whitespace is ignored; therefore the
		// truncation here is not a problem.
		
		// (OH YEAH!??? Watson 2335637 says otherwise.
		// Allow space for the truncation by adding 3 first.
		return ((nLength+3) / 4) * 3;		
	}

	public static String encode(byte[] pData, boolean bBreakLines/* = true */) {
		String sResult = "";

		if (pData != null && pData.length != 0) {
			char[] pEncoded = new char[encodeLength(pData.length, bBreakLines)];
			encode(pEncoded, pData, bBreakLines);
			sResult = new String(pEncoded);
		}
		return sResult;
	}

	//
	// implement using template to ensure that no new memory needs to
	// be allocated (the encodings may be passwords, in which case
	// the memory needs to be secure)
	//
	public static void encode(char[] pEncoded, byte[] pData, boolean bBreakLines) {
		int nAccumulator = 0;
		int nBits = 0;
		int nCount;
		int nChars = 0;
		int nTotal = 0;

		// short circuit if we have no data
		if (pData == null || pData.length == 0) {
			pEncoded[0] = 0;
			return;
		}

		for (nCount = 0; nCount < pData.length; nCount++) {
			// add a line feed every 76 characters (as per the base64
			// specification
			// in the MIME standard)
			if (bBreakLines && nChars % 76 == 0 && nChars != 0)
				pEncoded[nTotal++] = '\n';

			// collect another character
			nAccumulator <<= 8;
			// thought about just casting to unsigned char * instead of to int
			// and then masking,
			// but wasn't sure if that was portable
			nAccumulator |= (int) pData[nCount] & 0xffl;
			nBits += 8;

			// encode all the 6-bit groups we have
			while (nBits >= 6) {
				pEncoded[nTotal++] = szBase64Encoding
						.charAt((nAccumulator >> (nBits - 6)) & 0x3f);
				nChars++;
				nBits -= 6;
			}
		}

		if (nBits != 0) {
			pEncoded[nTotal++] = szBase64Encoding
					.charAt((nAccumulator << (6 - nBits)) & 0x3f);
			pEncoded[nTotal++] = cBase64Pad; // we need at least one pad
												// character
			if (pData.length % 3 == 1)
				pEncoded[nTotal++] = cBase64Pad; // in this case we need an
													// extra pad character
		}
	}

	private static int encodeLength(int nSize, boolean bBreakLines) {
		if (nSize == 0)
			return 0;
		int nResult = (nSize + 2) / 3 * 4;
		if (bBreakLines)
			nResult += (nResult - 1) / 76;
		return nResult;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy