1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "base64.h" 18 19 #include "ABuffer.h" 20 #include "ADebug.h" 21 22 namespace android { 23 24 sp<ABuffer> decodeBase64(const AString &s) { 25 if ((s.size() % 4) != 0) { 26 return NULL; 27 } 28 29 size_t n = s.size(); 30 size_t padding = 0; 31 if (n >= 1 && s.c_str()[n - 1] == '=') { 32 padding = 1; 33 34 if (n >= 2 && s.c_str()[n - 2] == '=') { 35 padding = 2; 36 } 37 } 38 39 size_t outLen = 3 * s.size() / 4 - padding; 40 41 sp<ABuffer> buffer = new ABuffer(outLen); 42 43 uint8_t *out = buffer->data(); 44 size_t j = 0; 45 uint32_t accum = 0; 46 for (size_t i = 0; i < n; ++i) { 47 char c = s.c_str()[i]; 48 unsigned value; 49 if (c >= 'A' && c <= 'Z') { 50 value = c - 'A'; 51 } else if (c >= 'a' && c <= 'z') { 52 value = 26 + c - 'a'; 53 } else if (c >= '0' && c <= '9') { 54 value = 52 + c - '0'; 55 } else if (c == '+') { 56 value = 62; 57 } else if (c == '/') { 58 value = 63; 59 } else if (c != '=') { 60 return NULL; 61 } else { 62 if (i < n - padding) { 63 return NULL; 64 } 65 66 value = 0; 67 } 68 69 accum = (accum << 6) | value; 70 71 if (((i + 1) % 4) == 0) { 72 out[j++] = (accum >> 16); 73 74 if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 75 if (j < outLen) { out[j++] = accum & 0xff; } 76 77 accum = 0; 78 } 79 } 80 81 return buffer; 82 } 83 84 static char encode6Bit(unsigned x) { 85 if (x <= 25) { 86 return 'A' + x; 87 } else if (x <= 51) { 88 return 'a' + x - 26; 89 } else if (x <= 61) { 90 return '0' + x - 52; 91 } else if (x == 62) { 92 return '+'; 93 } else { 94 return '/'; 95 } 96 } 97 98 void encodeBase64( 99 const void *_data, size_t size, AString *out) { 100 out->clear(); 101 102 const uint8_t *data = (const uint8_t *)_data; 103 104 size_t i; 105 for (i = 0; i < (size / 3) * 3; i += 3) { 106 uint8_t x1 = data[i]; 107 uint8_t x2 = data[i + 1]; 108 uint8_t x3 = data[i + 2]; 109 110 out->append(encode6Bit(x1 >> 2)); 111 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 112 out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f)); 113 out->append(encode6Bit(x3 & 0x3f)); 114 } 115 switch (size % 3) { 116 case 0: 117 break; 118 case 2: 119 { 120 uint8_t x1 = data[i]; 121 uint8_t x2 = data[i + 1]; 122 out->append(encode6Bit(x1 >> 2)); 123 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 124 out->append(encode6Bit((x2 << 2) & 0x3f)); 125 out->append('='); 126 break; 127 } 128 default: 129 { 130 uint8_t x1 = data[i]; 131 out->append(encode6Bit(x1 >> 2)); 132 out->append(encode6Bit((x1 << 4) & 0x3f)); 133 out->append("=="); 134 break; 135 } 136 } 137 } 138 139 } // namespace android 140