/src/assimp/code/Common/Base64.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | --------------------------------------------------------------------------- |
3 | | Open Asset Import Library (assimp) |
4 | | --------------------------------------------------------------------------- |
5 | | |
6 | | Copyright (c) 2006-2025, assimp team |
7 | | |
8 | | All rights reserved. |
9 | | |
10 | | Redistribution and use of this software in source and binary forms, |
11 | | with or without modification, are permitted provided that the following |
12 | | conditions are met: |
13 | | |
14 | | * Redistributions of source code must retain the above |
15 | | copyright notice, this list of conditions and the |
16 | | following disclaimer. |
17 | | |
18 | | * Redistributions in binary form must reproduce the above |
19 | | copyright notice, this list of conditions and the |
20 | | following disclaimer in the documentation and/or other |
21 | | materials provided with the distribution. |
22 | | |
23 | | * Neither the name of the assimp team, nor the names of its |
24 | | contributors may be used to endorse or promote products |
25 | | derived from this software without specific prior |
26 | | written permission of the assimp team. |
27 | | |
28 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
29 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
30 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
31 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
32 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
33 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
34 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
35 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
36 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
37 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
38 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
39 | | --------------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | #include <assimp/Base64.hpp> |
43 | | #include <assimp/Exceptional.h> |
44 | | |
45 | | namespace Assimp { |
46 | | |
47 | | namespace Base64 { |
48 | | |
49 | | static constexpr uint8_t tableDecodeBase64[128] = { |
50 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
51 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
52 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, |
53 | | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, |
54 | | 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
55 | | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, |
56 | | 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
57 | | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 |
58 | | }; |
59 | | |
60 | | static constexpr char tableEncodeBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; |
61 | | |
62 | 0 | static inline char EncodeChar(uint8_t b) { |
63 | 0 | return tableEncodeBase64[size_t(b)]; |
64 | 0 | } |
65 | | |
66 | 0 | inline uint8_t DecodeChar(char c) { |
67 | 0 | if (c & 0x80) { |
68 | 0 | throw DeadlyImportError("Invalid base64 char value: ", size_t(c)); |
69 | 0 | } |
70 | 0 | return tableDecodeBase64[size_t(c & 0x7F)]; // TODO faster with lookup table or ifs? |
71 | 0 | } |
72 | | |
73 | 0 | void Encode(const uint8_t *in, size_t inLength, std::string &out) { |
74 | 0 | if (in == nullptr || inLength==0) { |
75 | 0 | out.clear(); |
76 | 0 | return; |
77 | 0 | } |
78 | | |
79 | 0 | size_t outLength = ((inLength + 2) / 3) * 4; |
80 | |
|
81 | 0 | size_t j = out.size(); |
82 | 0 | out.resize(j + outLength); |
83 | |
|
84 | 0 | for (size_t i = 0; i < inLength; i += 3) { |
85 | 0 | uint8_t b = (in[i] & 0xFC) >> 2; |
86 | 0 | out[j++] = EncodeChar(b); |
87 | |
|
88 | 0 | b = (in[i] & 0x03) << 4; |
89 | 0 | if (i + 1 < inLength) { |
90 | 0 | b |= (in[i + 1] & 0xF0) >> 4; |
91 | 0 | out[j++] = EncodeChar(b); |
92 | |
|
93 | 0 | b = (in[i + 1] & 0x0F) << 2; |
94 | 0 | if (i + 2 < inLength) { |
95 | 0 | b |= (in[i + 2] & 0xC0) >> 6; |
96 | 0 | out[j++] = EncodeChar(b); |
97 | |
|
98 | 0 | b = in[i + 2] & 0x3F; |
99 | 0 | out[j++] = EncodeChar(b); |
100 | 0 | } else { |
101 | 0 | out[j++] = EncodeChar(b); |
102 | 0 | out[j++] = '='; |
103 | 0 | } |
104 | 0 | } else { |
105 | 0 | out[j++] = EncodeChar(b); |
106 | 0 | out[j++] = '='; |
107 | 0 | out[j++] = '='; |
108 | 0 | } |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | 0 | void Encode(const std::vector<uint8_t> &in, std::string &out) { |
113 | 0 | Encode(in.data(), in.size(), out); |
114 | 0 | } |
115 | | |
116 | 0 | std::string Encode(const std::vector<uint8_t> &in) { |
117 | 0 | std::string encoded; |
118 | 0 | Encode(in, encoded); |
119 | 0 | return encoded; |
120 | 0 | } |
121 | | |
122 | 0 | size_t Decode(const char *in, size_t inLength, uint8_t *&out) { |
123 | 0 | if (in == nullptr) { |
124 | 0 | out = nullptr; |
125 | 0 | return 0; |
126 | 0 | } |
127 | | |
128 | 0 | if (inLength % 4 != 0) { |
129 | 0 | throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), |
130 | 0 | "\", length:", inLength); |
131 | 0 | } |
132 | | |
133 | 0 | if (inLength < 4) { |
134 | 0 | out = nullptr; |
135 | 0 | return 0; |
136 | 0 | } |
137 | | |
138 | 0 | int nEquals = int(in[inLength - 1] == '=') + |
139 | 0 | int(in[inLength - 2] == '='); |
140 | |
|
141 | 0 | size_t outLength = (inLength * 3) / 4 - nEquals; |
142 | 0 | out = new uint8_t[outLength]; |
143 | 0 | memset(out, 0, outLength); |
144 | |
|
145 | 0 | size_t i, j = 0; |
146 | |
|
147 | 0 | for (i = 0; i + 4 < inLength; i += 4) { |
148 | 0 | uint8_t b0 = DecodeChar(in[i]); |
149 | 0 | uint8_t b1 = DecodeChar(in[i + 1]); |
150 | 0 | uint8_t b2 = DecodeChar(in[i + 2]); |
151 | 0 | uint8_t b3 = DecodeChar(in[i + 3]); |
152 | |
|
153 | 0 | out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); |
154 | 0 | out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); |
155 | 0 | out[j++] = (uint8_t)((b2 << 6) | b3); |
156 | 0 | } |
157 | |
|
158 | 0 | { |
159 | 0 | uint8_t b0 = DecodeChar(in[i]); |
160 | 0 | uint8_t b1 = DecodeChar(in[i + 1]); |
161 | 0 | uint8_t b2 = DecodeChar(in[i + 2]); |
162 | 0 | uint8_t b3 = DecodeChar(in[i + 3]); |
163 | |
|
164 | 0 | out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); |
165 | 0 | if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); |
166 | 0 | if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); |
167 | 0 | } |
168 | |
|
169 | 0 | return outLength; |
170 | 0 | } |
171 | | |
172 | 0 | size_t Decode(const std::string &in, std::vector<uint8_t> &out) { |
173 | 0 | uint8_t *outPtr = nullptr; |
174 | 0 | size_t decodedSize = Decode(in.data(), in.size(), outPtr); |
175 | 0 | if (outPtr == nullptr) { |
176 | 0 | return 0; |
177 | 0 | } |
178 | 0 | out.assign(outPtr, outPtr + decodedSize); |
179 | 0 | delete[] outPtr; |
180 | 0 | return decodedSize; |
181 | 0 | } |
182 | | |
183 | 0 | std::vector<uint8_t> Decode(const std::string &in) { |
184 | 0 | std::vector<uint8_t> result; |
185 | 0 | Decode(in, result); |
186 | 0 | return result; |
187 | 0 | } |
188 | | |
189 | | } // namespace Base64 |
190 | | } // namespace Assimp |