1 /* 2 * Copyright (C) 2007 Esmertec AG. 3 * Copyright (C) 2007 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.messaging.mmslib.pdu; 19 20 public class Base64 { 21 /** 22 * Used to get the number of Quadruples. 23 */ 24 static final int FOURBYTE = 4; 25 26 /** 27 * Byte used to pad output. 28 */ 29 static final byte PAD = (byte) '='; 30 31 /** 32 * The base length. 33 */ 34 static final int BASELENGTH = 255; 35 36 // Create arrays to hold the base64 characters 37 private static byte[] base64Alphabet = new byte[BASELENGTH]; 38 39 // Populating the character arrays 40 static { 41 for (int i = 0; i < BASELENGTH; i++) { 42 base64Alphabet[i] = (byte) -1; 43 } 44 for (int i = 'Z'; i >= 'A'; i--) { 45 base64Alphabet[i] = (byte) (i - 'A'); 46 } 47 for (int i = 'z'; i >= 'a'; i--) { 48 base64Alphabet[i] = (byte) (i - 'a' + 26); 49 } 50 for (int i = '9'; i >= '0'; i--) { 51 base64Alphabet[i] = (byte) (i - '0' + 52); 52 } 53 54 base64Alphabet['+'] = 62; 55 base64Alphabet['/'] = 63; 56 } 57 58 /** 59 * Decodes Base64 data into octects 60 * 61 * @param base64Data Byte array containing Base64 data 62 * @return Array containing decoded data. 63 */ decodeBase64(byte[] base64Data)64 public static byte[] decodeBase64(byte[] base64Data) { 65 // RFC 2045 requires that we discard ALL non-Base64 characters 66 base64Data = discardNonBase64(base64Data); 67 68 // handle the edge case, so we don't have to worry about it later 69 if (base64Data.length == 0) { 70 return new byte[0]; 71 } 72 73 int numberQuadruple = base64Data.length / FOURBYTE; 74 byte decodedData[] = null; 75 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 76 77 // Throw away anything not in base64Data 78 79 int encodedIndex = 0; 80 int dataIndex = 0; 81 { 82 // this sizes the output array properly - rlw 83 int lastData = base64Data.length; 84 // ignore the '=' padding 85 while (base64Data[lastData - 1] == PAD) { 86 if (--lastData == 0) { 87 return new byte[0]; 88 } 89 } 90 decodedData = new byte[lastData - numberQuadruple]; 91 } 92 93 for (int i = 0; i < numberQuadruple; i++) { 94 dataIndex = i * 4; 95 marker0 = base64Data[dataIndex + 2]; 96 marker1 = base64Data[dataIndex + 3]; 97 98 b1 = base64Alphabet[base64Data[dataIndex]]; 99 b2 = base64Alphabet[base64Data[dataIndex + 1]]; 100 101 if (marker0 != PAD && marker1 != PAD) { 102 //No PAD e.g 3cQl 103 b3 = base64Alphabet[marker0]; 104 b4 = base64Alphabet[marker1]; 105 106 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 107 decodedData[encodedIndex + 1] = 108 (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 109 decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); 110 } else if (marker0 == PAD) { 111 //Two PAD e.g. 3c[Pad][Pad] 112 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 113 } else if (marker1 == PAD) { 114 //One PAD e.g. 3cQ[Pad] 115 b3 = base64Alphabet[marker0]; 116 117 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 118 decodedData[encodedIndex + 1] = 119 (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 120 } 121 encodedIndex += 3; 122 } 123 return decodedData; 124 } 125 126 /** 127 * Check octect wheter it is a base64 encoding. 128 * 129 * @param octect to be checked byte 130 * @return ture if it is base64 encoding, false otherwise. 131 */ isBase64(byte octect)132 private static boolean isBase64(byte octect) { 133 if (octect == PAD) { 134 return true; 135 } else if (base64Alphabet[octect] == -1) { 136 return false; 137 } else { 138 return true; 139 } 140 } 141 142 /** 143 * Discards any characters outside of the base64 alphabet, per 144 * the requirements on page 25 of RFC 2045 - "Any characters 145 * outside of the base64 alphabet are to be ignored in base64 146 * encoded data." 147 * 148 * @param data The base-64 encoded data to groom 149 * @return The data, less non-base64 characters (see RFC 2045). 150 */ discardNonBase64(byte[] data)151 static byte[] discardNonBase64(byte[] data) { 152 byte groomedData[] = new byte[data.length]; 153 int bytesCopied = 0; 154 155 for (int i = 0; i < data.length; i++) { 156 if (isBase64(data[i])) { 157 groomedData[bytesCopied++] = data[i]; 158 } 159 } 160 161 byte packedData[] = new byte[bytesCopied]; 162 163 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 164 165 return packedData; 166 } 167 } 168