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 padding = 0;
     32     if (n >= 1 && s.c_str()[n - 1] == '=') {
     33         padding = 1;
     34 
     35         if (n >= 2 && s.c_str()[n - 2] == '=') {
     36             padding = 2;
     37 
     38             if (n >= 3 && s.c_str()[n - 3] == '=') {
     39                 padding = 3;
     40             }
     41         }
     42     }
     43 
     44     // We divide first to avoid overflow. It's OK to do this because we
     45     // already made sure that n % 4 == 0.
     46     size_t outLen = (n / 4) * 3 - padding;
     47 
     48     sp<ABuffer> buffer = new ABuffer(outLen);
     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 == '+' || c == '-') {
     65             value = 62;
     66         } else if (c == '/' || 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             if (j < outLen) { out[j++] = (accum >> 16); }
     82             if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
     83             if (j < outLen) { out[j++] = accum & 0xff; }
     84 
     85             accum = 0;
     86         }
     87     }
     88 
     89     return buffer;
     90 }
     91 
     92 static char encode6Bit(unsigned x) {
     93     if (x <= 25) {
     94         return 'A' + x;
     95     } else if (x <= 51) {
     96         return 'a' + x - 26;
     97     } else if (x <= 61) {
     98         return '0' + x - 52;
     99     } else if (x == 62) {
    100         return '+';
    101     } else {
    102         return '/';
    103     }
    104 }
    105 
    106 void encodeBase64(
    107         const void *_data, size_t size, AString *out) {
    108     out->clear();
    109 
    110     const uint8_t *data = (const uint8_t *)_data;
    111 
    112     size_t i;
    113     for (i = 0; i < (size / 3) * 3; i += 3) {
    114         uint8_t x1 = data[i];
    115         uint8_t x2 = data[i + 1];
    116         uint8_t x3 = data[i + 2];
    117 
    118         out->append(encode6Bit(x1 >> 2));
    119         out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
    120         out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
    121         out->append(encode6Bit(x3 & 0x3f));
    122     }
    123     switch (size % 3) {
    124         case 0:
    125             break;
    126         case 2:
    127         {
    128             uint8_t x1 = data[i];
    129             uint8_t x2 = data[i + 1];
    130             out->append(encode6Bit(x1 >> 2));
    131             out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
    132             out->append(encode6Bit((x2 << 2) & 0x3f));
    133             out->append('=');
    134             break;
    135         }
    136         default:
    137         {
    138             uint8_t x1 = data[i];
    139             out->append(encode6Bit(x1 >> 2));
    140             out->append(encode6Bit((x1 << 4) & 0x3f));
    141             out->append("==");
    142             break;
    143         }
    144     }
    145 }
    146 
    147 void encodeBase64Url(
    148         const void *_data, size_t size, AString *out) {
    149     encodeBase64(_data, size, out);
    150 
    151     if ((-1 != out->find("+")) || (-1 != out->find("/"))) {
    152         size_t outLen = out->size();
    153         char *base64url = new char[outLen];
    154         for (size_t i = 0; i < outLen; ++i) {
    155             if (out->c_str()[i] == '+')
    156                 base64url[i] = '-';
    157             else if (out->c_str()[i] == '/')
    158                 base64url[i] = '_';
    159             else
    160                 base64url[i] = out->c_str()[i];
    161         }
    162 
    163         out->setTo(base64url, outLen);
    164         delete[] base64url;
    165     }
    166 }
    167 
    168 
    169 }  // namespace android
    170