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