1e509ee18Sopenharmony_ci/*
2e509ee18Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3e509ee18Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e509ee18Sopenharmony_ci * you may not use this file except in compliance with the License.
5e509ee18Sopenharmony_ci * You may obtain a copy of the License at
6e509ee18Sopenharmony_ci *
7e509ee18Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e509ee18Sopenharmony_ci *
9e509ee18Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e509ee18Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e509ee18Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e509ee18Sopenharmony_ci * See the License for the specific language governing permissions and
13e509ee18Sopenharmony_ci * limitations under the License.
14e509ee18Sopenharmony_ci */
15e509ee18Sopenharmony_ci
16e509ee18Sopenharmony_ci#include "tooling/base/pt_base64.h"
17e509ee18Sopenharmony_ci
18e509ee18Sopenharmony_cinamespace panda::ecmascript::tooling {
19e509ee18Sopenharmony_cistatic const unsigned char DECODE_TABLE[] = {
20e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
21e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
22e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
23e509ee18Sopenharmony_ci    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
24e509ee18Sopenharmony_ci    255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
25e509ee18Sopenharmony_ci    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
26e509ee18Sopenharmony_ci    255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
27e509ee18Sopenharmony_ci    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255,
28e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
29e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
30e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
31e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
32e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
33e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
34e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
35e509ee18Sopenharmony_ci    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
36e509ee18Sopenharmony_ci};
37e509ee18Sopenharmony_ci
38e509ee18Sopenharmony_cistatic const char ENCODE_TABLE[] = {
39e509ee18Sopenharmony_ci    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
40e509ee18Sopenharmony_ci    "abcdefghijklmnopqrstuvwxyz"
41e509ee18Sopenharmony_ci    "0123456789+/"
42e509ee18Sopenharmony_ci};
43e509ee18Sopenharmony_ci
44e509ee18Sopenharmony_cistd::pair<std::size_t, bool> PtBase64::Decode(void *output, const char *input, std::size_t len)
45e509ee18Sopenharmony_ci{
46e509ee18Sopenharmony_ci    if (len < ENCODED_GROUP_BYTES || len % ENCODED_GROUP_BYTES != 0) {
47e509ee18Sopenharmony_ci        return {0, false};
48e509ee18Sopenharmony_ci    }
49e509ee18Sopenharmony_ci
50e509ee18Sopenharmony_ci    auto *src = reinterpret_cast<unsigned char const *>(input);
51e509ee18Sopenharmony_ci    char *dest = static_cast<char *>(output);
52e509ee18Sopenharmony_ci    char base64Chars[ENCODED_GROUP_BYTES];
53e509ee18Sopenharmony_ci    int8_t i = 0;
54e509ee18Sopenharmony_ci    while (len-- && *src != '=') {
55e509ee18Sopenharmony_ci        auto v = DECODE_TABLE[*src];
56e509ee18Sopenharmony_ci        if (v == INVAILD_VALUE) {
57e509ee18Sopenharmony_ci            break;
58e509ee18Sopenharmony_ci        }
59e509ee18Sopenharmony_ci        base64Chars[i++] = v;
60e509ee18Sopenharmony_ci
61e509ee18Sopenharmony_ci        if (i == ENCODED_GROUP_BYTES) {
62e509ee18Sopenharmony_ci            *dest++ = (base64Chars[0] << 2) | ((base64Chars[1] & 0x30) >> 4); // 2: shift 2bits, 4: shift 4bits
63e509ee18Sopenharmony_ci            *dest++ = (base64Chars[1] << 4) | ((base64Chars[2] & 0x3c) >> 2); // 2: shift 2bits, 4: shift 4bits
64e509ee18Sopenharmony_ci            *dest++ = (base64Chars[2] << 6) | base64Chars[3]; // 6: shift 6bits, 2: the second char, 3: the third char
65e509ee18Sopenharmony_ci            i = 0;
66e509ee18Sopenharmony_ci        }
67e509ee18Sopenharmony_ci        src++;
68e509ee18Sopenharmony_ci    }
69e509ee18Sopenharmony_ci
70e509ee18Sopenharmony_ci    if (i != 0) {
71e509ee18Sopenharmony_ci        char tmp[UNENCODED_GROUP_BYTES];
72e509ee18Sopenharmony_ci        tmp[0] = (base64Chars[0] << 2) | ((base64Chars[1] & 0x30) >> 4); // 2: shift 2bits, 4: shift 4bits
73e509ee18Sopenharmony_ci        tmp[1] = (base64Chars[1] << 4) | ((base64Chars[2] & 0x3c) >> 2); // 2: shift 2bits, 4: shift 4bits
74e509ee18Sopenharmony_ci        tmp[2] = (base64Chars[2] << 6) | base64Chars[3]; // 6: shift 6bits, 2: the second char, 3: the third char
75e509ee18Sopenharmony_ci        for (int8_t j = 0; j < i - 1; j++) {
76e509ee18Sopenharmony_ci            *dest++ = tmp[j];
77e509ee18Sopenharmony_ci        }
78e509ee18Sopenharmony_ci    }
79e509ee18Sopenharmony_ci
80e509ee18Sopenharmony_ci    len++; // get the remaining length and also avoid underflow
81e509ee18Sopenharmony_ci    size_t decodedLen = dest - static_cast<char *>(output);
82e509ee18Sopenharmony_ci    bool decodedDone = false;
83e509ee18Sopenharmony_ci    // 0: decodedDone, 1: =, 2: ==
84e509ee18Sopenharmony_ci    if (len == 0 || (len == 1 && *src == '=') || (len == 2 && *src == '=' && *(src + 1) == '=')) {
85e509ee18Sopenharmony_ci        decodedDone = true;
86e509ee18Sopenharmony_ci    }
87e509ee18Sopenharmony_ci
88e509ee18Sopenharmony_ci    return {decodedLen, decodedDone};
89e509ee18Sopenharmony_ci}
90e509ee18Sopenharmony_ci
91e509ee18Sopenharmony_cisize_t PtBase64::Encode(char *output, const void *input, std::size_t len)
92e509ee18Sopenharmony_ci{
93e509ee18Sopenharmony_ci    if (len == 0) {
94e509ee18Sopenharmony_ci        return 0;
95e509ee18Sopenharmony_ci    }
96e509ee18Sopenharmony_ci
97e509ee18Sopenharmony_ci    auto *src = static_cast<const unsigned char *>(input);
98e509ee18Sopenharmony_ci    char *dest = output;
99e509ee18Sopenharmony_ci    for (auto n = len / UNENCODED_GROUP_BYTES; n--;) {
100e509ee18Sopenharmony_ci        *dest++ = ENCODE_TABLE[src[0] >> 2]; // 2: shift 2bits
101e509ee18Sopenharmony_ci        *dest++ = ENCODE_TABLE[((src[0] & 0x03) << 4) | (src[1] >> 4)]; // 4: shift 4bits
102e509ee18Sopenharmony_ci        *dest++ = ENCODE_TABLE[((src[1] & 0x0f) << 2) | (src[2] >> 6)]; // 2: shift 2bits, 6: shift 6bits
103e509ee18Sopenharmony_ci        *dest++ = ENCODE_TABLE[src[2] & 0x3f]; // 2: the second char
104e509ee18Sopenharmony_ci
105e509ee18Sopenharmony_ci        src += UNENCODED_GROUP_BYTES;
106e509ee18Sopenharmony_ci    }
107e509ee18Sopenharmony_ci
108e509ee18Sopenharmony_ci    int8_t remainder = static_cast<int8_t>(len % UNENCODED_GROUP_BYTES);
109e509ee18Sopenharmony_ci    int8_t paddingCnt = (UNENCODED_GROUP_BYTES - remainder) % UNENCODED_GROUP_BYTES;
110e509ee18Sopenharmony_ci    switch (paddingCnt) {
111e509ee18Sopenharmony_ci        case 1:
112e509ee18Sopenharmony_ci            *dest++ = ENCODE_TABLE[src[0] >> 2]; // 2: shift 2bits
113e509ee18Sopenharmony_ci            *dest++ = ENCODE_TABLE[((src[0] & 0x03) << 4) | (src[1] >> 4)]; // 4: shift 4bits
114e509ee18Sopenharmony_ci            *dest++ = ENCODE_TABLE[((src[1] & 0x0f) << 2)]; // 2: shift 2bits
115e509ee18Sopenharmony_ci            *dest++ = '=';
116e509ee18Sopenharmony_ci            break;
117e509ee18Sopenharmony_ci        case 2: // 2: "=="
118e509ee18Sopenharmony_ci            *dest++ = ENCODE_TABLE[src[0] >> 2]; // 2: shift 2bits
119e509ee18Sopenharmony_ci            *dest++ = ENCODE_TABLE[((src[0] & 0x03) << 4)]; // 4: shift 4bits
120e509ee18Sopenharmony_ci            *dest++ = '=';
121e509ee18Sopenharmony_ci            *dest++ = '=';
122e509ee18Sopenharmony_ci            break;
123e509ee18Sopenharmony_ci        default:
124e509ee18Sopenharmony_ci            break;
125e509ee18Sopenharmony_ci    }
126e509ee18Sopenharmony_ci    return dest - output;
127e509ee18Sopenharmony_ci}
128e509ee18Sopenharmony_ci}  // namespace panda::ecmascript::tooling