xref: /aosp_15_r20/frameworks/av/media/module/foundation/base64.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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 
decodeBase64(const AString & s)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 
decodeBase64(uint8_t * out,size_t * inOutBufSize,const char * s)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 
encode6Bit(unsigned x)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 
encodeBase64(const void * _data,size_t size,AString * out)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 
encodeBase64Url(const void * _data,size_t size,AString * out)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