Home | History | Annotate | Download | only in foundation
      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     size_t n = s.size();
     26 
     27     if ((n % 4) != 0) {
     28         return NULL;
     29     }
     30 
     31     size_t bufSize = n / 4 * 3;
     32     sp<ABuffer> buf = new ABuffer(bufSize);
     33 
     34     if (decodeBase64(buf->data(), &bufSize, s.c_str())) {
     35         buf->setRange(0, bufSize);
     36         return buf;
     37     }
     38     return NULL;
     39 }
     40 
     41 bool decodeBase64(uint8_t *out, size_t *inOutBufSize, const char* s) {
     42     size_t n = strlen(s);
     43 
     44     if ((n % 4) != 0) {
     45         return false;
     46     }
     47 
     48     size_t padding = 0;
     49     if (n >= 1 && s[n - 1] == '=') {
     50         padding = 1;
     51 
     52         if (n >= 2 && s[n - 2] == '=') {
     53             padding = 2;
     54 
     55             if (n >= 3 && s[n - 3] == '=') {
     56                 padding = 3;
     57             }
     58         }
     59     }
     60 
     61     // We divide first to avoid overflow. It's OK to do this because we
     62     // already made sure that n % 4 == 0.
     63     size_t outLen = (n / 4) * 3 - padding;
     64 
     65     if (out == NULL || *inOutBufSize < outLen) {
     66         return false;
     67     }
     68     size_t j = 0;
     69     uint32_t accum = 0;
     70     for (size_t i = 0; i < n; ++i) {
     71         char c = s[i];
     72         unsigned value;
     73         if (c >= 'A' && c <= 'Z') {
     74             value = c - 'A';
     75         } else if (c >= 'a' && c <= 'z') {
     76             value = 26 + c - 'a';
     77         } else if (c >= '0' && c <= '9') {
     78             value = 52 + c - '0';
     79         } else if (c == '+' || c == '-') {
     80             value = 62;
     81         } else if (c == '/' || c == '_') {
     82             value = 63;
     83         } else if (c != '=') {
     84             return false;
     85         } else {
     86             if (i < n - padding) {
     87                 return false;
     88             }
     89 
     90             value = 0;
     91         }
     92 
     93         accum = (accum << 6) | value;
     94 
     95         if (((i + 1) % 4) == 0) {
     96             if (j < outLen) { out[j++] = (accum >> 16); }
     97             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
     98             if (j < outLen) { out[j++] = accum & 0xff; }
     99 
    100             accum = 0;
    101         }
    102     }
    103 
    104     *inOutBufSize = j;
    105     return true;
    106 }
    107 
    108 static char encode6Bit(unsigned x) {
    109     if (x <= 25) {
    110         return 'A' + x;
    111     } else if (x <= 51) {
    112         return 'a' + x - 26;
    113     } else if (x <= 61) {
    114         return '0' + x - 52;
    115     } else if (x == 62) {
    116         return '+';
    117     } else {
    118         return '/';
    119     }
    120 }
    121 
    122 void encodeBase64(
    123         const void *_data, size_t size, AString *out) {
    124     out->clear();
    125 
    126     const uint8_t *data = (const uint8_t *)_data;
    127 
    128     size_t i;
    129     for (i = 0; i < (size / 3) * 3; i += 3) {
    130         uint8_t x1 = data[i];
    131         uint8_t x2 = data[i + 1];
    132         uint8_t x3 = data[i + 2];
    133 
    134         out->append(encode6Bit(x1 >> 2));
    135         out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
    136         out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
    137         out->append(encode6Bit(x3 & 0x3f));
    138     }
    139     switch (size % 3) {
    140         case 0:
    141             break;
    142         case 2:
    143         {
    144             uint8_t x1 = data[i];
    145             uint8_t x2 = data[i + 1];
    146             out->append(encode6Bit(x1 >> 2));
    147             out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
    148             out->append(encode6Bit((x2 << 2) & 0x3f));
    149             out->append('=');
    150             break;
    151         }
    152         default:
    153         {
    154             uint8_t x1 = data[i];
    155             out->append(encode6Bit(x1 >> 2));
    156             out->append(encode6Bit((x1 << 4) & 0x3f));
    157             out->append("==");
    158             break;
    159         }
    160     }
    161 }
    162 
    163 void encodeBase64Url(
    164         const void *_data, size_t size, AString *out) {
    165     encodeBase64(_data, size, out);
    166 
    167     if ((-1 != out->find("+")) || (-1 != out->find("/"))) {
    168         size_t outLen = out->size();
    169         char *base64url = new char[outLen];
    170         for (size_t i = 0; i < outLen; ++i) {
    171             if (out->c_str()[i] == '+')
    172                 base64url[i] = '-';
    173             else if (out->c_str()[i] == '/')
    174                 base64url[i] = '_';
    175             else
    176                 base64url[i] = out->c_str()[i];
    177         }
    178 
    179         out->setTo(base64url, outLen);
    180         delete[] base64url;
    181     }
    182 }
    183 
    184 
    185 }  // namespace android
    186