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 decodeBase64(const AString & s)24sp<ABuffer> decodeBase64(const AString &s) { 25 size_t n = s.size(); 26 if ((n % 4) != 0) { 27 return NULL; 28 } 29 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 if (n >= 3 && s.c_str()[n - 3] == '=') { 38 padding = 3; 39 } 40 } 41 } 42 43 // We divide first to avoid overflow. It's OK to do this because we 44 // already made sure that n % 4 == 0. 45 size_t outLen = (n / 4) * 3 - padding; 46 47 sp<ABuffer> buffer = new ABuffer(outLen); 48 49 uint8_t *out = buffer->data(); 50 if (out == NULL || buffer->size() < outLen) { 51 return NULL; 52 } 53 size_t j = 0; 54 uint32_t accum = 0; 55 for (size_t i = 0; i < n; ++i) { 56 char c = s.c_str()[i]; 57 unsigned value; 58 if (c >= 'A' && c <= 'Z') { 59 value = c - 'A'; 60 } else if (c >= 'a' && c <= 'z') { 61 value = 26 + c - 'a'; 62 } else if (c >= '0' && c <= '9') { 63 value = 52 + c - '0'; 64 } else if (c == '+') { 65 value = 62; 66 } else if (c == '/') { 67 value = 63; 68 } else if (c != '=') { 69 return NULL; 70 } else { 71 if (i < n - padding) { 72 return NULL; 73 } 74 75 value = 0; 76 } 77 78 accum = (accum << 6) | value; 79 80 if (((i + 1) % 4) == 0) { 81 out[j++] = (accum >> 16); 82 83 if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 84 if (j < outLen) { out[j++] = accum & 0xff; } 85 86 accum = 0; 87 } 88 } 89 90 return buffer; 91 } 92 encode6Bit(unsigned x)93static char encode6Bit(unsigned x) { 94 if (x <= 25) { 95 return 'A' + x; 96 } else if (x <= 51) { 97 return 'a' + x - 26; 98 } else if (x <= 61) { 99 return '0' + x - 52; 100 } else if (x == 62) { 101 return '+'; 102 } else { 103 return '/'; 104 } 105 } 106 encodeBase64(const void * _data,size_t size,AString * out)107void encodeBase64( 108 const void *_data, size_t size, AString *out) { 109 out->clear(); 110 111 const uint8_t *data = (const uint8_t *)_data; 112 113 size_t i; 114 for (i = 0; i < (size / 3) * 3; i += 3) { 115 uint8_t x1 = data[i]; 116 uint8_t x2 = data[i + 1]; 117 uint8_t x3 = data[i + 2]; 118 119 out->append(encode6Bit(x1 >> 2)); 120 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 121 out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f)); 122 out->append(encode6Bit(x3 & 0x3f)); 123 } 124 switch (size % 3) { 125 case 0: 126 break; 127 case 2: 128 { 129 uint8_t x1 = data[i]; 130 uint8_t x2 = data[i + 1]; 131 out->append(encode6Bit(x1 >> 2)); 132 out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f)); 133 out->append(encode6Bit((x2 << 2) & 0x3f)); 134 out->append('='); 135 break; 136 } 137 default: 138 { 139 uint8_t x1 = data[i]; 140 out->append(encode6Bit(x1 >> 2)); 141 out->append(encode6Bit((x1 << 4) & 0x3f)); 142 out->append("=="); 143 break; 144 } 145 } 146 } 147 148 } // namespace android 149