172961230a5890071bcca436eb5630172ce84ec41Andreas Huber/*
272961230a5890071bcca436eb5630172ce84ec41Andreas Huber * Copyright (C) 2010 The Android Open Source Project
372961230a5890071bcca436eb5630172ce84ec41Andreas Huber *
472961230a5890071bcca436eb5630172ce84ec41Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
572961230a5890071bcca436eb5630172ce84ec41Andreas Huber * you may not use this file except in compliance with the License.
672961230a5890071bcca436eb5630172ce84ec41Andreas Huber * You may obtain a copy of the License at
772961230a5890071bcca436eb5630172ce84ec41Andreas Huber *
872961230a5890071bcca436eb5630172ce84ec41Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
972961230a5890071bcca436eb5630172ce84ec41Andreas Huber *
1072961230a5890071bcca436eb5630172ce84ec41Andreas Huber * Unless required by applicable law or agreed to in writing, software
1172961230a5890071bcca436eb5630172ce84ec41Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1272961230a5890071bcca436eb5630172ce84ec41Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1372961230a5890071bcca436eb5630172ce84ec41Andreas Huber * See the License for the specific language governing permissions and
1472961230a5890071bcca436eb5630172ce84ec41Andreas Huber * limitations under the License.
1572961230a5890071bcca436eb5630172ce84ec41Andreas Huber */
1672961230a5890071bcca436eb5630172ce84ec41Andreas Huber
1772961230a5890071bcca436eb5630172ce84ec41Andreas Huber#include "base64.h"
1872961230a5890071bcca436eb5630172ce84ec41Andreas Huber
1972961230a5890071bcca436eb5630172ce84ec41Andreas Huber#include "ABuffer.h"
2072961230a5890071bcca436eb5630172ce84ec41Andreas Huber#include "ADebug.h"
2172961230a5890071bcca436eb5630172ce84ec41Andreas Huber
2272961230a5890071bcca436eb5630172ce84ec41Andreas Hubernamespace android {
2372961230a5890071bcca436eb5630172ce84ec41Andreas Huber
2472961230a5890071bcca436eb5630172ce84ec41Andreas Hubersp<ABuffer> decodeBase64(const AString &s) {
2572961230a5890071bcca436eb5630172ce84ec41Andreas Huber    if ((s.size() % 4) != 0) {
2672961230a5890071bcca436eb5630172ce84ec41Andreas Huber        return NULL;
2772961230a5890071bcca436eb5630172ce84ec41Andreas Huber    }
2872961230a5890071bcca436eb5630172ce84ec41Andreas Huber
2972961230a5890071bcca436eb5630172ce84ec41Andreas Huber    size_t n = s.size();
3072961230a5890071bcca436eb5630172ce84ec41Andreas Huber    size_t padding = 0;
3172961230a5890071bcca436eb5630172ce84ec41Andreas Huber    if (n >= 1 && s.c_str()[n - 1] == '=') {
3272961230a5890071bcca436eb5630172ce84ec41Andreas Huber        padding = 1;
3372961230a5890071bcca436eb5630172ce84ec41Andreas Huber
3472961230a5890071bcca436eb5630172ce84ec41Andreas Huber        if (n >= 2 && s.c_str()[n - 2] == '=') {
3572961230a5890071bcca436eb5630172ce84ec41Andreas Huber            padding = 2;
364bbfff2dbf3968c267c3b2ea9f8912a38372a9daAndreas Huber
374bbfff2dbf3968c267c3b2ea9f8912a38372a9daAndreas Huber            if (n >= 3 && s.c_str()[n - 3] == '=') {
384bbfff2dbf3968c267c3b2ea9f8912a38372a9daAndreas Huber                padding = 3;
394bbfff2dbf3968c267c3b2ea9f8912a38372a9daAndreas Huber            }
4072961230a5890071bcca436eb5630172ce84ec41Andreas Huber        }
4172961230a5890071bcca436eb5630172ce84ec41Andreas Huber    }
4272961230a5890071bcca436eb5630172ce84ec41Andreas Huber
4372961230a5890071bcca436eb5630172ce84ec41Andreas Huber    size_t outLen = 3 * s.size() / 4 - padding;
4472961230a5890071bcca436eb5630172ce84ec41Andreas Huber
4572961230a5890071bcca436eb5630172ce84ec41Andreas Huber    sp<ABuffer> buffer = new ABuffer(outLen);
4672961230a5890071bcca436eb5630172ce84ec41Andreas Huber
4772961230a5890071bcca436eb5630172ce84ec41Andreas Huber    uint8_t *out = buffer->data();
4872961230a5890071bcca436eb5630172ce84ec41Andreas Huber    size_t j = 0;
4972961230a5890071bcca436eb5630172ce84ec41Andreas Huber    uint32_t accum = 0;
5072961230a5890071bcca436eb5630172ce84ec41Andreas Huber    for (size_t i = 0; i < n; ++i) {
5172961230a5890071bcca436eb5630172ce84ec41Andreas Huber        char c = s.c_str()[i];
5272961230a5890071bcca436eb5630172ce84ec41Andreas Huber        unsigned value;
5372961230a5890071bcca436eb5630172ce84ec41Andreas Huber        if (c >= 'A' && c <= 'Z') {
5472961230a5890071bcca436eb5630172ce84ec41Andreas Huber            value = c - 'A';
5572961230a5890071bcca436eb5630172ce84ec41Andreas Huber        } else if (c >= 'a' && c <= 'z') {
5672961230a5890071bcca436eb5630172ce84ec41Andreas Huber            value = 26 + c - 'a';
5772961230a5890071bcca436eb5630172ce84ec41Andreas Huber        } else if (c >= '0' && c <= '9') {
5872961230a5890071bcca436eb5630172ce84ec41Andreas Huber            value = 52 + c - '0';
5972961230a5890071bcca436eb5630172ce84ec41Andreas Huber        } else if (c == '+') {
6072961230a5890071bcca436eb5630172ce84ec41Andreas Huber            value = 62;
6172961230a5890071bcca436eb5630172ce84ec41Andreas Huber        } else if (c == '/') {
6272961230a5890071bcca436eb5630172ce84ec41Andreas Huber            value = 63;
6372961230a5890071bcca436eb5630172ce84ec41Andreas Huber        } else if (c != '=') {
6472961230a5890071bcca436eb5630172ce84ec41Andreas Huber            return NULL;
6572961230a5890071bcca436eb5630172ce84ec41Andreas Huber        } else {
6672961230a5890071bcca436eb5630172ce84ec41Andreas Huber            if (i < n - padding) {
6772961230a5890071bcca436eb5630172ce84ec41Andreas Huber                return NULL;
6872961230a5890071bcca436eb5630172ce84ec41Andreas Huber            }
6972961230a5890071bcca436eb5630172ce84ec41Andreas Huber
7072961230a5890071bcca436eb5630172ce84ec41Andreas Huber            value = 0;
7172961230a5890071bcca436eb5630172ce84ec41Andreas Huber        }
7272961230a5890071bcca436eb5630172ce84ec41Andreas Huber
7372961230a5890071bcca436eb5630172ce84ec41Andreas Huber        accum = (accum << 6) | value;
7472961230a5890071bcca436eb5630172ce84ec41Andreas Huber
7572961230a5890071bcca436eb5630172ce84ec41Andreas Huber        if (((i + 1) % 4) == 0) {
7672961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out[j++] = (accum >> 16);
7772961230a5890071bcca436eb5630172ce84ec41Andreas Huber
784bbfff2dbf3968c267c3b2ea9f8912a38372a9daAndreas Huber            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
7972961230a5890071bcca436eb5630172ce84ec41Andreas Huber            if (j < outLen) { out[j++] = accum & 0xff; }
8072961230a5890071bcca436eb5630172ce84ec41Andreas Huber
8172961230a5890071bcca436eb5630172ce84ec41Andreas Huber            accum = 0;
8272961230a5890071bcca436eb5630172ce84ec41Andreas Huber        }
8372961230a5890071bcca436eb5630172ce84ec41Andreas Huber    }
8472961230a5890071bcca436eb5630172ce84ec41Andreas Huber
8572961230a5890071bcca436eb5630172ce84ec41Andreas Huber    return buffer;
8672961230a5890071bcca436eb5630172ce84ec41Andreas Huber}
8772961230a5890071bcca436eb5630172ce84ec41Andreas Huber
8872961230a5890071bcca436eb5630172ce84ec41Andreas Huberstatic char encode6Bit(unsigned x) {
8972961230a5890071bcca436eb5630172ce84ec41Andreas Huber    if (x <= 25) {
9072961230a5890071bcca436eb5630172ce84ec41Andreas Huber        return 'A' + x;
9172961230a5890071bcca436eb5630172ce84ec41Andreas Huber    } else if (x <= 51) {
9272961230a5890071bcca436eb5630172ce84ec41Andreas Huber        return 'a' + x - 26;
9372961230a5890071bcca436eb5630172ce84ec41Andreas Huber    } else if (x <= 61) {
9472961230a5890071bcca436eb5630172ce84ec41Andreas Huber        return '0' + x - 52;
9572961230a5890071bcca436eb5630172ce84ec41Andreas Huber    } else if (x == 62) {
9672961230a5890071bcca436eb5630172ce84ec41Andreas Huber        return '+';
9772961230a5890071bcca436eb5630172ce84ec41Andreas Huber    } else {
9872961230a5890071bcca436eb5630172ce84ec41Andreas Huber        return '/';
9972961230a5890071bcca436eb5630172ce84ec41Andreas Huber    }
10072961230a5890071bcca436eb5630172ce84ec41Andreas Huber}
10172961230a5890071bcca436eb5630172ce84ec41Andreas Huber
10272961230a5890071bcca436eb5630172ce84ec41Andreas Hubervoid encodeBase64(
10372961230a5890071bcca436eb5630172ce84ec41Andreas Huber        const void *_data, size_t size, AString *out) {
10472961230a5890071bcca436eb5630172ce84ec41Andreas Huber    out->clear();
10572961230a5890071bcca436eb5630172ce84ec41Andreas Huber
10672961230a5890071bcca436eb5630172ce84ec41Andreas Huber    const uint8_t *data = (const uint8_t *)_data;
10772961230a5890071bcca436eb5630172ce84ec41Andreas Huber
10872961230a5890071bcca436eb5630172ce84ec41Andreas Huber    size_t i;
10972961230a5890071bcca436eb5630172ce84ec41Andreas Huber    for (i = 0; i < (size / 3) * 3; i += 3) {
11072961230a5890071bcca436eb5630172ce84ec41Andreas Huber        uint8_t x1 = data[i];
11172961230a5890071bcca436eb5630172ce84ec41Andreas Huber        uint8_t x2 = data[i + 1];
11272961230a5890071bcca436eb5630172ce84ec41Andreas Huber        uint8_t x3 = data[i + 2];
11372961230a5890071bcca436eb5630172ce84ec41Andreas Huber
11472961230a5890071bcca436eb5630172ce84ec41Andreas Huber        out->append(encode6Bit(x1 >> 2));
11572961230a5890071bcca436eb5630172ce84ec41Andreas Huber        out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
11672961230a5890071bcca436eb5630172ce84ec41Andreas Huber        out->append(encode6Bit((x2 << 2 | x3 >> 6) & 0x3f));
11772961230a5890071bcca436eb5630172ce84ec41Andreas Huber        out->append(encode6Bit(x3 & 0x3f));
11872961230a5890071bcca436eb5630172ce84ec41Andreas Huber    }
11972961230a5890071bcca436eb5630172ce84ec41Andreas Huber    switch (size % 3) {
12072961230a5890071bcca436eb5630172ce84ec41Andreas Huber        case 0:
12172961230a5890071bcca436eb5630172ce84ec41Andreas Huber            break;
12272961230a5890071bcca436eb5630172ce84ec41Andreas Huber        case 2:
12372961230a5890071bcca436eb5630172ce84ec41Andreas Huber        {
12472961230a5890071bcca436eb5630172ce84ec41Andreas Huber            uint8_t x1 = data[i];
12572961230a5890071bcca436eb5630172ce84ec41Andreas Huber            uint8_t x2 = data[i + 1];
12672961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out->append(encode6Bit(x1 >> 2));
12772961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out->append(encode6Bit((x1 << 4 | x2 >> 4) & 0x3f));
12872961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out->append(encode6Bit((x2 << 2) & 0x3f));
12972961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out->append('=');
13072961230a5890071bcca436eb5630172ce84ec41Andreas Huber            break;
13172961230a5890071bcca436eb5630172ce84ec41Andreas Huber        }
13272961230a5890071bcca436eb5630172ce84ec41Andreas Huber        default:
13372961230a5890071bcca436eb5630172ce84ec41Andreas Huber        {
13472961230a5890071bcca436eb5630172ce84ec41Andreas Huber            uint8_t x1 = data[i];
13572961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out->append(encode6Bit(x1 >> 2));
13672961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out->append(encode6Bit((x1 << 4) & 0x3f));
13772961230a5890071bcca436eb5630172ce84ec41Andreas Huber            out->append("==");
13872961230a5890071bcca436eb5630172ce84ec41Andreas Huber            break;
13972961230a5890071bcca436eb5630172ce84ec41Andreas Huber        }
14072961230a5890071bcca436eb5630172ce84ec41Andreas Huber    }
14172961230a5890071bcca436eb5630172ce84ec41Andreas Huber}
14272961230a5890071bcca436eb5630172ce84ec41Andreas Huber
14372961230a5890071bcca436eb5630172ce84ec41Andreas Huber}  // namespace android
144