/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 | | #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER |
54 | | |
55 | | namespace Assimp { |
56 | | namespace FBX { |
57 | | namespace Util { |
58 | | |
59 | | // ------------------------------------------------------------------------------------------------ |
60 | | const char* TokenTypeString(TokenType t) |
61 | 0 | { |
62 | 0 | switch(t) { |
63 | 0 | case TokenType_OPEN_BRACKET: |
64 | 0 | return "TOK_OPEN_BRACKET"; |
65 | | |
66 | 0 | case TokenType_CLOSE_BRACKET: |
67 | 0 | return "TOK_CLOSE_BRACKET"; |
68 | | |
69 | 0 | case TokenType_DATA: |
70 | 0 | return "TOK_DATA"; |
71 | | |
72 | 0 | case TokenType_COMMA: |
73 | 0 | return "TOK_COMMA"; |
74 | | |
75 | 0 | case TokenType_KEY: |
76 | 0 | return "TOK_KEY"; |
77 | | |
78 | 0 | case TokenType_BINARY_DATA: |
79 | 0 | return "TOK_BINARY_DATA"; |
80 | 0 | } |
81 | | |
82 | 0 | ai_assert(false); |
83 | 0 | return ""; |
84 | 0 | } |
85 | | |
86 | | |
87 | | // ------------------------------------------------------------------------------------------------ |
88 | | std::string GetOffsetText(size_t offset) |
89 | 0 | { |
90 | 0 | return static_cast<std::string>( Formatter::format() << " (offset 0x" << std::hex << offset << ") " ); |
91 | 0 | } |
92 | | |
93 | | // ------------------------------------------------------------------------------------------------ |
94 | | std::string GetLineAndColumnText(unsigned int line, unsigned int column) |
95 | 0 | { |
96 | 0 | return static_cast<std::string>( Formatter::format() << " (line " << line << " << col " << column << ") " ); |
97 | 0 | } |
98 | | |
99 | | // ------------------------------------------------------------------------------------------------ |
100 | | std::string GetTokenText(const Token* tok) |
101 | 0 | { |
102 | 0 | if(tok->IsBinary()) { |
103 | 0 | return static_cast<std::string>( Formatter::format() << |
104 | 0 | " (" << TokenTypeString(tok->Type()) << |
105 | 0 | ", offset 0x" << std::hex << tok->Offset() << ") " ); |
106 | 0 | } |
107 | | |
108 | 0 | return static_cast<std::string>( Formatter::format() << |
109 | 0 | " (" << TokenTypeString(tok->Type()) << |
110 | 0 | ", line " << tok->Line() << |
111 | 0 | ", col " << tok->Column() << ") " ); |
112 | 0 | } |
113 | | |
114 | | // Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; |
115 | | static const uint8_t base64DecodeTable[128] = { |
116 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
117 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, |
118 | | 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, |
119 | | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, |
120 | | 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
121 | | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, |
122 | | 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
123 | | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 |
124 | | }; |
125 | | |
126 | | uint8_t DecodeBase64(char ch) |
127 | 0 | { |
128 | 0 | const auto idx = static_cast<uint8_t>(ch); |
129 | 0 | if (idx > 127) |
130 | 0 | return 255; |
131 | 0 | return base64DecodeTable[idx]; |
132 | 0 | } |
133 | | |
134 | | size_t ComputeDecodedSizeBase64(const char* in, size_t inLength) |
135 | 0 | { |
136 | 0 | if (inLength < 2) |
137 | 0 | { |
138 | 0 | return 0; |
139 | 0 | } |
140 | 0 | const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '='); |
141 | 0 | const size_t full_length = (inLength * 3) >> 2; // div by 4 |
142 | 0 | if (full_length < equals) |
143 | 0 | { |
144 | 0 | return 0; |
145 | 0 | } |
146 | 0 | return full_length - equals; |
147 | 0 | } |
148 | | |
149 | | size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength) |
150 | 0 | { |
151 | 0 | if (maxOutLength == 0 || inLength < 2) { |
152 | 0 | return 0; |
153 | 0 | } |
154 | 0 | const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '='); |
155 | 0 | size_t dst_offset = 0; |
156 | 0 | int val = 0, valb = -8; |
157 | 0 | for (size_t src_offset = 0; src_offset < realLength && dst_offset < maxOutLength; ++src_offset) |
158 | 0 | { |
159 | 0 | const uint8_t table_value = Util::DecodeBase64(in[src_offset]); |
160 | 0 | if (table_value == 255) |
161 | 0 | { |
162 | 0 | return 0; |
163 | 0 | } |
164 | 0 | val = (val << 6) + table_value; |
165 | 0 | valb += 6; |
166 | 0 | if (valb >= 0) |
167 | 0 | { |
168 | 0 | out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF); |
169 | 0 | valb -= 8; |
170 | 0 | val &= 0xFFF; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | return dst_offset; |
174 | 0 | } |
175 | | |
176 | | static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
177 | | char EncodeBase64(char byte) |
178 | 0 | { |
179 | 0 | return to_base64_string[(size_t)byte]; |
180 | 0 | } |
181 | | |
182 | | /** Encodes a block of 4 bytes to base64 encoding |
183 | | * |
184 | | * @param bytes Bytes to encode. |
185 | | * @param out_string String to write encoded values to. |
186 | | * @param string_pos Position in out_string.*/ |
187 | | void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos) |
188 | 0 | { |
189 | 0 | char b0 = (bytes[0] & 0xFC) >> 2; |
190 | 0 | char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4); |
191 | 0 | char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6); |
192 | 0 | char b3 = (bytes[2] & 0x3F); |
193 | |
|
194 | 0 | out_string[string_pos + 0] = EncodeBase64(b0); |
195 | 0 | out_string[string_pos + 1] = EncodeBase64(b1); |
196 | 0 | out_string[string_pos + 2] = EncodeBase64(b2); |
197 | 0 | out_string[string_pos + 3] = EncodeBase64(b3); |
198 | 0 | } |
199 | | |
200 | | std::string EncodeBase64(const char* data, size_t length) |
201 | 0 | { |
202 | | // calculate extra bytes needed to get a multiple of 3 |
203 | 0 | size_t extraBytes = 3 - length % 3; |
204 | | |
205 | | // number of base64 bytes |
206 | 0 | size_t encodedBytes = 4 * (length + extraBytes) / 3; |
207 | |
|
208 | 0 | std::string encoded_string(encodedBytes, '='); |
209 | | |
210 | | // read blocks of 3 bytes |
211 | 0 | for (size_t ib3 = 0; ib3 < length / 3; ib3++) |
212 | 0 | { |
213 | 0 | const size_t iByte = ib3 * 3; |
214 | 0 | const size_t iEncodedByte = ib3 * 4; |
215 | 0 | const char* currData = &data[iByte]; |
216 | |
|
217 | 0 | EncodeByteBlock(currData, encoded_string, iEncodedByte); |
218 | 0 | } |
219 | | |
220 | | // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed) |
221 | 0 | if (extraBytes > 0) |
222 | 0 | { |
223 | 0 | char finalBytes[4] = { 0,0,0,0 }; |
224 | 0 | memcpy(&finalBytes[0], &data[length - length % 3], length % 3); |
225 | |
|
226 | 0 | const size_t iEncodedByte = encodedBytes - 4; |
227 | 0 | EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); |
228 | | |
229 | | // add '=' at the end |
230 | 0 | for (size_t i = 0; i < 4 * extraBytes / 3; i++) |
231 | 0 | encoded_string[encodedBytes - i - 1] = '='; |
232 | 0 | } |
233 | 0 | return encoded_string; |
234 | 0 | } |
235 | | |
236 | | } // !Util |
237 | | } // !FBX |
238 | | } // !Assimp |
239 | | |
240 | | #endif |