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