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     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