/src/assimp/code/AssetLib/FBX/FBXUtil.cpp
Line | Count | Source |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | |
42 | | /** @file FBXUtil.cpp |
43 | | * @brief Implementation of internal FBX utility functions |
44 | | */ |
45 | | |
46 | | #include "FBXUtil.h" |
47 | | #include "FBXTokenizer.h" |
48 | | |
49 | | #include <assimp/TinyFormatter.h> |
50 | | #include <string> |
51 | | #include <cstring> |
52 | | |
53 | | namespace Assimp::FBX::Util { |
54 | | |
55 | | // ------------------------------------------------------------------------------------------------ |
56 | | const char* TokenTypeString(TokenType t) |
57 | 0 | { |
58 | 0 | switch(t) { |
59 | 0 | case TokenType_OPEN_BRACKET: |
60 | 0 | return "TOK_OPEN_BRACKET"; |
61 | | |
62 | 0 | case TokenType_CLOSE_BRACKET: |
63 | 0 | return "TOK_CLOSE_BRACKET"; |
64 | | |
65 | 0 | case TokenType_DATA: |
66 | 0 | return "TOK_DATA"; |
67 | | |
68 | 0 | case TokenType_COMMA: |
69 | 0 | return "TOK_COMMA"; |
70 | | |
71 | 0 | case TokenType_KEY: |
72 | 0 | return "TOK_KEY"; |
73 | | |
74 | 0 | case TokenType_BINARY_DATA: |
75 | 0 | return "TOK_BINARY_DATA"; |
76 | 0 | } |
77 | | |
78 | 0 | ai_assert(false); |
79 | 0 | return ""; |
80 | 0 | } |
81 | | |
82 | | |
83 | | // ------------------------------------------------------------------------------------------------ |
84 | | std::string GetOffsetText(size_t offset) |
85 | 0 | { |
86 | 0 | return static_cast<std::string>( Formatter::format() << " (offset 0x" << std::hex << offset << ") " ); |
87 | 0 | } |
88 | | |
89 | | // ------------------------------------------------------------------------------------------------ |
90 | | std::string GetLineAndColumnText(unsigned int line, unsigned int column) |
91 | 0 | { |
92 | 0 | return static_cast<std::string>( Formatter::format() << " (line " << line << " << col " << column << ") " ); |
93 | 0 | } |
94 | | |
95 | | // ------------------------------------------------------------------------------------------------ |
96 | | std::string GetTokenText(const Token* tok) |
97 | 0 | { |
98 | 0 | if(tok->IsBinary()) { |
99 | 0 | return static_cast<std::string>( Formatter::format() << |
100 | 0 | " (" << TokenTypeString(tok->Type()) << |
101 | 0 | ", offset 0x" << std::hex << tok->Offset() << ") " ); |
102 | 0 | } |
103 | | |
104 | 0 | return static_cast<std::string>( Formatter::format() << |
105 | 0 | " (" << TokenTypeString(tok->Type()) << |
106 | 0 | ", line " << tok->Line() << |
107 | 0 | ", col " << tok->Column() << ") " ); |
108 | 0 | } |
109 | | |
110 | | // Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; |
111 | | static const uint8_t base64DecodeTable[128] = { |
112 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
113 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
114 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, |
115 | | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, |
116 | | 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
117 | | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, |
118 | | 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
119 | | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 |
120 | | }; |
121 | | |
122 | | uint8_t DecodeBase64(char ch) |
123 | 0 | { |
124 | 0 | const auto idx = static_cast<uint8_t>(ch); |
125 | 0 | if (idx > 127) |
126 | 0 | return 255; |
127 | 0 | return base64DecodeTable[idx]; |
128 | 0 | } |
129 | | |
130 | | size_t ComputeDecodedSizeBase64(const char* in, size_t inLength) |
131 | 0 | { |
132 | 0 | if (inLength < 2) |
133 | 0 | { |
134 | 0 | return 0; |
135 | 0 | } |
136 | 0 | const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '='); |
137 | 0 | const size_t full_length = (inLength * 3) >> 2; // div by 4 |
138 | 0 | if (full_length < equals) |
139 | 0 | { |
140 | 0 | return 0; |
141 | 0 | } |
142 | 0 | return full_length - equals; |
143 | 0 | } |
144 | | |
145 | | size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength) |
146 | 0 | { |
147 | 0 | if (maxOutLength == 0 || inLength < 2) { |
148 | 0 | return 0; |
149 | 0 | } |
150 | 0 | const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '='); |
151 | 0 | size_t dst_offset = 0; |
152 | 0 | int val = 0, valb = -8; |
153 | 0 | for (size_t src_offset = 0; src_offset < realLength && dst_offset < maxOutLength; ++src_offset) |
154 | 0 | { |
155 | 0 | const uint8_t table_value = Util::DecodeBase64(in[src_offset]); |
156 | 0 | if (table_value == 255) |
157 | 0 | { |
158 | 0 | return 0; |
159 | 0 | } |
160 | 0 | val = (val << 6) + table_value; |
161 | 0 | valb += 6; |
162 | 0 | if (valb >= 0) |
163 | 0 | { |
164 | 0 | out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF); |
165 | 0 | valb -= 8; |
166 | 0 | val &= 0xFFF; |
167 | 0 | } |
168 | 0 | } |
169 | 0 | return dst_offset; |
170 | 0 | } |
171 | | |
172 | | static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
173 | | char EncodeBase64(char byte) |
174 | 0 | { |
175 | 0 | return to_base64_string[(size_t)byte]; |
176 | 0 | } |
177 | | |
178 | | /** Encodes a block of 4 bytes to base64 encoding |
179 | | * |
180 | | * @param bytes Bytes to encode. |
181 | | * @param out_string String to write encoded values to. |
182 | | * @param string_pos Position in out_string.*/ |
183 | | void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos) |
184 | 0 | { |
185 | 0 | char b0 = (bytes[0] & 0xFC) >> 2; |
186 | 0 | char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4); |
187 | 0 | char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6); |
188 | 0 | char b3 = (bytes[2] & 0x3F); |
189 | |
|
190 | 0 | out_string[string_pos + 0] = EncodeBase64(b0); |
191 | 0 | out_string[string_pos + 1] = EncodeBase64(b1); |
192 | 0 | out_string[string_pos + 2] = EncodeBase64(b2); |
193 | 0 | out_string[string_pos + 3] = EncodeBase64(b3); |
194 | 0 | } |
195 | | |
196 | | std::string EncodeBase64(const char* data, size_t length) |
197 | 0 | { |
198 | | // calculate extra bytes needed to get a multiple of 3 |
199 | 0 | size_t extraBytes = 3 - length % 3; |
200 | | |
201 | | // number of base64 bytes |
202 | 0 | size_t encodedBytes = 4 * (length + extraBytes) / 3; |
203 | |
|
204 | 0 | std::string encoded_string(encodedBytes, '='); |
205 | | |
206 | | // read blocks of 3 bytes |
207 | 0 | for (size_t ib3 = 0; ib3 < length / 3; ib3++) |
208 | 0 | { |
209 | 0 | const size_t iByte = ib3 * 3; |
210 | 0 | const size_t iEncodedByte = ib3 * 4; |
211 | 0 | const char* currData = &data[iByte]; |
212 | |
|
213 | 0 | EncodeByteBlock(currData, encoded_string, iEncodedByte); |
214 | 0 | } |
215 | | |
216 | | // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed) |
217 | 0 | if (extraBytes > 0) |
218 | 0 | { |
219 | 0 | char finalBytes[4] = { 0,0,0,0 }; |
220 | 0 | memcpy(&finalBytes[0], &data[length - length % 3], length % 3); |
221 | |
|
222 | 0 | const size_t iEncodedByte = encodedBytes - 4; |
223 | 0 | EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); |
224 | | |
225 | | // add '=' at the end |
226 | 0 | for (size_t i = 0; i < 4 * extraBytes / 3; i++) |
227 | 0 | encoded_string[encodedBytes - i - 1] = '='; |
228 | 0 | } |
229 | 0 | return encoded_string; |
230 | 0 | } |
231 | | |
232 | | } // namespace Assimp::FBX::Util |
233 | | |