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.google.android.mms.pdu; 19 20 import android.compat.annotation.UnsupportedAppUsage; 21 22 public class Base64 { 23 /** 24 * Used to get the number of Quadruples. 25 */ 26 static final int FOURBYTE = 4; 27 28 /** 29 * Byte used to pad output. 30 */ 31 static final byte PAD = (byte) '='; 32 33 /** 34 * The base length. 35 */ 36 static final int BASELENGTH = 255; 37 38 // Create arrays to hold the base64 characters 39 private static byte[] base64Alphabet = new byte[BASELENGTH]; 40 41 // Populating the character arrays 42 static { 43 for (int i = 0; i < BASELENGTH; i++) { 44 base64Alphabet[i] = (byte) -1; 45 } 46 for (int i = 'Z'; i >= 'A'; i--) { 47 base64Alphabet[i] = (byte) (i - 'A'); 48 } 49 for (int i = 'z'; i >= 'a'; i--) { 50 base64Alphabet[i] = (byte) (i - 'a' + 26); 51 } 52 for (int i = '9'; i >= '0'; i--) { 53 base64Alphabet[i] = (byte) (i - '0' + 52); 54 } 55 56 base64Alphabet['+'] = 62; 57 base64Alphabet['/'] = 63; 58 } 59 60 /** 61 * Decodes Base64 data into octects 62 * 63 * @param base64Data Byte array containing Base64 data 64 * @return Array containing decoded data. 65 */ 66 @UnsupportedAppUsage decodeBase64(byte[] base64Data)67 public static byte[] decodeBase64(byte[] base64Data) { 68 // RFC 2045 requires that we discard ALL non-Base64 characters 69 base64Data = discardNonBase64(base64Data); 70 71 // handle the edge case, so we don't have to worry about it later 72 if (base64Data.length == 0) { 73 return new byte[0]; 74 } 75 76 int numberQuadruple = base64Data.length / FOURBYTE; 77 byte decodedData[] = null; 78 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 79 80 // Throw away anything not in base64Data 81 82 int encodedIndex = 0; 83 int dataIndex = 0; 84 { 85 // this sizes the output array properly - rlw 86 int lastData = base64Data.length; 87 // ignore the '=' padding 88 while (base64Data[lastData - 1] == PAD) { 89 if (--lastData == 0) { 90 return new byte[0]; 91 } 92 } 93 decodedData = new byte[lastData - numberQuadruple]; 94 } 95 96 for (int i = 0; i < numberQuadruple; i++) { 97 dataIndex = i * 4; 98 marker0 = base64Data[dataIndex + 2]; 99 marker1 = base64Data[dataIndex + 3]; 100 101 b1 = base64Alphabet[base64Data[dataIndex]]; 102 b2 = base64Alphabet[base64Data[dataIndex + 1]]; 103 104 if (marker0 != PAD && marker1 != PAD) { 105 //No PAD e.g 3cQl 106 b3 = base64Alphabet[marker0]; 107 b4 = base64Alphabet[marker1]; 108 109 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 110 decodedData[encodedIndex + 1] = 111 (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 112 decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); 113 } else if (marker0 == PAD) { 114 //Two PAD e.g. 3c[Pad][Pad] 115 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 116 } else if (marker1 == PAD) { 117 //One PAD e.g. 3cQ[Pad] 118 b3 = base64Alphabet[marker0]; 119 120 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 121 decodedData[encodedIndex + 1] = 122 (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 123 } 124 encodedIndex += 3; 125 } 126 return decodedData; 127 } 128 129 /** 130 * Check octect whether it is a base64 encoding. 131 * 132 * @param octect to be checked byte 133 * @return ture if it is base64 encoding, false otherwise. 134 */ isBase64(byte octect)135 private static boolean isBase64(byte octect) { 136 if (octect == PAD) { 137 return true; 138 } else if (base64Alphabet[octect] == -1) { 139 return false; 140 } else { 141 return true; 142 } 143 } 144 145 /** 146 * Discards any characters outside of the base64 alphabet, per 147 * the requirements on page 25 of RFC 2045 - "Any characters 148 * outside of the base64 alphabet are to be ignored in base64 149 * encoded data." 150 * 151 * @param data The base-64 encoded data to groom 152 * @return The data, less non-base64 characters (see RFC 2045). 153 */ discardNonBase64(byte[] data)154 static byte[] discardNonBase64(byte[] data) { 155 byte groomedData[] = new byte[data.length]; 156 int bytesCopied = 0; 157 158 for (int i = 0; i < data.length; i++) { 159 if (isBase64(data[i])) { 160 groomedData[bytesCopied++] = data[i]; 161 } 162 } 163 164 byte packedData[] = new byte[bytesCopied]; 165 166 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 167 168 return packedData; 169 } 170 } 171