127ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi/* 227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * Copyright (C) 2007 Esmertec AG. 327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * Copyright (C) 2007 The Android Open Source Project 427ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * 527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * Licensed under the Apache License, Version 2.0 (the "License"); 627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * you may not use this file except in compliance with the License. 727ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * You may obtain a copy of the License at 827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * 927ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * http://www.apache.org/licenses/LICENSE-2.0 1027ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * 1127ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * Unless required by applicable law or agreed to in writing, software 1227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * distributed under the License is distributed on an "AS IS" BASIS, 1327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1427ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * See the License for the specific language governing permissions and 1527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * limitations under the License. 1627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi */ 172272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi 1827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshipackage com.google.android.mms.pdu; 1927ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 2027ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshipublic class Base64 { 2127ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi /** 2227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * Used to get the number of Quadruples. 2327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi */ 2427ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi static final int FOURBYTE = 4; 2527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 2627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi /** 273473846f64f5b28e1cbeb70ef5867073fc93159eTakeshi Aimi * Byte used to pad output. 2827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi */ 2927ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi static final byte PAD = (byte) '='; 3027ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 3127ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi /** 3227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * The base length. 3327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi */ 3427ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi static final int BASELENGTH = 255; 3527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 3627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi // Create arrays to hold the base64 characters 3727ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi private static byte[] base64Alphabet = new byte[BASELENGTH]; 3827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 3927ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi // Populating the character arrays 40c10ce33302f91896fc2a87c13b00518a4bc26e3aGloria Wang static { 411da9aa606096e14985924e8433a087d04f68ea22Gloria Wang for (int i = 0; i < BASELENGTH; i++) { 421da9aa606096e14985924e8433a087d04f68ea22Gloria Wang base64Alphabet[i] = (byte) -1; 431da9aa606096e14985924e8433a087d04f68ea22Gloria Wang } 441da9aa606096e14985924e8433a087d04f68ea22Gloria Wang for (int i = 'Z'; i >= 'A'; i--) { 451da9aa606096e14985924e8433a087d04f68ea22Gloria Wang base64Alphabet[i] = (byte) (i - 'A'); 461da9aa606096e14985924e8433a087d04f68ea22Gloria Wang } 471da9aa606096e14985924e8433a087d04f68ea22Gloria Wang for (int i = 'z'; i >= 'a'; i--) { 481da9aa606096e14985924e8433a087d04f68ea22Gloria Wang base64Alphabet[i] = (byte) (i - 'a' + 26); 49c10ce33302f91896fc2a87c13b00518a4bc26e3aGloria Wang } 501da9aa606096e14985924e8433a087d04f68ea22Gloria Wang for (int i = '9'; i >= '0'; i--) { 511da9aa606096e14985924e8433a087d04f68ea22Gloria Wang base64Alphabet[i] = (byte) (i - '0' + 52); 521da9aa606096e14985924e8433a087d04f68ea22Gloria Wang } 531da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 546b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang base64Alphabet['+'] = 62; 556b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang base64Alphabet['/'] = 63; 56c10ce33302f91896fc2a87c13b00518a4bc26e3aGloria Wang } 576b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang 586b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang /** 596b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang * Decodes Base64 data into octects 606b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang * 611da9aa606096e14985924e8433a087d04f68ea22Gloria Wang * @param base64Data Byte array containing Base64 data 621da9aa606096e14985924e8433a087d04f68ea22Gloria Wang * @return Array containing decoded data. 631da9aa606096e14985924e8433a087d04f68ea22Gloria Wang */ 641da9aa606096e14985924e8433a087d04f68ea22Gloria Wang public static byte[] decodeBase64(byte[] base64Data) { 651da9aa606096e14985924e8433a087d04f68ea22Gloria Wang // RFC 2045 requires that we discard ALL non-Base64 characters 661da9aa606096e14985924e8433a087d04f68ea22Gloria Wang base64Data = discardNonBase64(base64Data); 671da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 681da9aa606096e14985924e8433a087d04f68ea22Gloria Wang // handle the edge case, so we don't have to worry about it later 691da9aa606096e14985924e8433a087d04f68ea22Gloria Wang if (base64Data.length == 0) { 701da9aa606096e14985924e8433a087d04f68ea22Gloria Wang return new byte[0]; 711da9aa606096e14985924e8433a087d04f68ea22Gloria Wang } 721da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 731da9aa606096e14985924e8433a087d04f68ea22Gloria Wang int numberQuadruple = base64Data.length / FOURBYTE; 741da9aa606096e14985924e8433a087d04f68ea22Gloria Wang byte decodedData[] = null; 751da9aa606096e14985924e8433a087d04f68ea22Gloria Wang byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0; 761da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 771da9aa606096e14985924e8433a087d04f68ea22Gloria Wang // Throw away anything not in base64Data 781da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 791da9aa606096e14985924e8433a087d04f68ea22Gloria Wang int encodedIndex = 0; 80c10ce33302f91896fc2a87c13b00518a4bc26e3aGloria Wang int dataIndex = 0; 816b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang { 826b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang // this sizes the output array properly - rlw 836b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang int lastData = base64Data.length; 846b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang // ignore the '=' padding 856b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang while (base64Data[lastData - 1] == PAD) { 866b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang if (--lastData == 0) { 87c10ce33302f91896fc2a87c13b00518a4bc26e3aGloria Wang return new byte[0]; 886b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang } 896b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang } 906b2a35bbec228ce012065260ba153ee894f17a4eGloria Wang decodedData = new byte[lastData - numberQuadruple]; 911da9aa606096e14985924e8433a087d04f68ea22Gloria Wang } 921da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 931da9aa606096e14985924e8433a087d04f68ea22Gloria Wang for (int i = 0; i < numberQuadruple; i++) { 941da9aa606096e14985924e8433a087d04f68ea22Gloria Wang dataIndex = i * 4; 951da9aa606096e14985924e8433a087d04f68ea22Gloria Wang marker0 = base64Data[dataIndex + 2]; 961da9aa606096e14985924e8433a087d04f68ea22Gloria Wang marker1 = base64Data[dataIndex + 3]; 971da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 981da9aa606096e14985924e8433a087d04f68ea22Gloria Wang b1 = base64Alphabet[base64Data[dataIndex]]; 991da9aa606096e14985924e8433a087d04f68ea22Gloria Wang b2 = base64Alphabet[base64Data[dataIndex + 1]]; 1001da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 1011da9aa606096e14985924e8433a087d04f68ea22Gloria Wang if (marker0 != PAD && marker1 != PAD) { 1021da9aa606096e14985924e8433a087d04f68ea22Gloria Wang //No PAD e.g 3cQl 1031da9aa606096e14985924e8433a087d04f68ea22Gloria Wang b3 = base64Alphabet[marker0]; 1041da9aa606096e14985924e8433a087d04f68ea22Gloria Wang b4 = base64Alphabet[marker1]; 1051da9aa606096e14985924e8433a087d04f68ea22Gloria Wang 1061da9aa606096e14985924e8433a087d04f68ea22Gloria Wang decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 1071da9aa606096e14985924e8433a087d04f68ea22Gloria Wang decodedData[encodedIndex + 1] = 1081da9aa606096e14985924e8433a087d04f68ea22Gloria Wang (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 1091da9aa606096e14985924e8433a087d04f68ea22Gloria Wang decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4); 110ab00df4d8585b181e9058eb1b9c7996aa3bbaeabGloria Wang } else if (marker0 == PAD) { 1111da9aa606096e14985924e8433a087d04f68ea22Gloria Wang //Two PAD e.g. 3c[Pad][Pad] 1121da9aa606096e14985924e8433a087d04f68ea22Gloria Wang decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 1138f00151cbe693d52f3e233757c57fab3b6396d21Gloria Wang } else if (marker1 == PAD) { 1142272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi //One PAD e.g. 3cQ[Pad] 1152272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi b3 = base64Alphabet[marker0]; 1162272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi 1178f00151cbe693d52f3e233757c57fab3b6396d21Gloria Wang decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); 1182272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi decodedData[encodedIndex + 1] = 1192272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); 1202272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi } 1212272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi encodedIndex += 3; 1222272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi } 1232272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi return decodedData; 1242272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi } 1252272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi 1262272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi /** 1272272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi * Check octect wheter it is a base64 encoding. 1282272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi * 1292272ee27d9022d173b6eab45c409b3c3f57f30ecTakeshi Aimi * @param octect to be checked byte 130e943f84129326ab885cc7a69dcfa17f766b72b89Takeshi Aimi * @return ture if it is base64 encoding, false otherwise. 13127ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi */ 13227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi private static boolean isBase64(byte octect) { 13327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi if (octect == PAD) { 134e943f84129326ab885cc7a69dcfa17f766b72b89Takeshi Aimi return true; 13527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi } else if (base64Alphabet[octect] == -1) { 13627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi return false; 137e943f84129326ab885cc7a69dcfa17f766b72b89Takeshi Aimi } else { 13827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi return true; 13927ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi } 14027ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi } 141e943f84129326ab885cc7a69dcfa17f766b72b89Takeshi Aimi 14227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi /** 14327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * Discards any characters outside of the base64 alphabet, per 14427ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * the requirements on page 25 of RFC 2045 - "Any characters 14527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * outside of the base64 alphabet are to be ignored in base64 14627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * encoded data." 14727ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * 14827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * @param data The base-64 encoded data to groom 14927ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi * @return The data, less non-base64 characters (see RFC 2045). 15027ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi */ 15127ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi static byte[] discardNonBase64(byte[] data) { 15227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi byte groomedData[] = new byte[data.length]; 15327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi int bytesCopied = 0; 15427ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 15527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi for (int i = 0; i < data.length; i++) { 15627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi if (isBase64(data[i])) { 15727ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi groomedData[bytesCopied++] = data[i]; 15827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi } 15927ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi } 16027ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 16127ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi byte packedData[] = new byte[bytesCopied]; 16227ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 16327ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi System.arraycopy(groomedData, 0, packedData, 0, bytesCopied); 16427ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi 16527ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi return packedData; 16627ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi } 16727ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi} 16827ed8ad2db653f6ac07dcf8bcc05e2409c8bb024aimitakeshi