/src/assimp/code/AssetLib/FBX/FBXExportProperty.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef ASSIMP_BUILD_NO_EXPORT |
42 | | #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER |
43 | | |
44 | | #include "FBXExportProperty.h" |
45 | | |
46 | | #include <assimp/StreamWriter.h> // StreamWriterLE |
47 | | #include <assimp/Exceptional.h> // DeadlyExportError |
48 | | |
49 | | #include <string> |
50 | | #include <vector> |
51 | | #include <ostream> |
52 | | #include <locale> |
53 | | #include <sstream> // ostringstream |
54 | | |
55 | | namespace Assimp { |
56 | | namespace FBX { |
57 | | |
58 | | // constructors for single element properties |
59 | | |
60 | | FBXExportProperty::FBXExportProperty(bool v) |
61 | 39.9k | : type('C') |
62 | 39.9k | , data(1, uint8_t(v)) {} |
63 | | |
64 | | FBXExportProperty::FBXExportProperty(int16_t v) |
65 | 0 | : type('Y') |
66 | 0 | , data(2) { |
67 | 0 | uint8_t* d = data.data(); |
68 | 0 | (reinterpret_cast<int16_t*>(d))[0] = v; |
69 | 0 | } |
70 | | |
71 | | FBXExportProperty::FBXExportProperty(int32_t v) |
72 | 196k | : type('I') |
73 | 196k | , data(4) { |
74 | 196k | uint8_t* d = data.data(); |
75 | 196k | (reinterpret_cast<int32_t*>(d))[0] = v; |
76 | 196k | } |
77 | | |
78 | | FBXExportProperty::FBXExportProperty(float v) |
79 | 0 | : type('F') |
80 | 0 | , data(4) { |
81 | 0 | uint8_t* d = data.data(); |
82 | 0 | (reinterpret_cast<float*>(d))[0] = v; |
83 | 0 | } |
84 | | |
85 | | FBXExportProperty::FBXExportProperty(double v) |
86 | 39.3k | : type('D') |
87 | 39.3k | , data(8) { |
88 | 39.3k | uint8_t* d = data.data(); |
89 | 39.3k | (reinterpret_cast<double*>(d))[0] = v; |
90 | 39.3k | } |
91 | | |
92 | | FBXExportProperty::FBXExportProperty(int64_t v) |
93 | 219k | : type('L') |
94 | 219k | , data(8) { |
95 | 219k | uint8_t* d = data.data(); |
96 | 219k | (reinterpret_cast<int64_t*>(d))[0] = v; |
97 | 219k | } |
98 | | |
99 | | // constructors for array-type properties |
100 | | |
101 | | FBXExportProperty::FBXExportProperty(const char* c, bool raw) |
102 | 640k | : FBXExportProperty(std::string(c), raw) { |
103 | | // empty |
104 | 640k | } |
105 | | |
106 | | // strings can either be saved as "raw" (R) data, or "string" (S) data |
107 | | FBXExportProperty::FBXExportProperty(const std::string& s, bool raw) |
108 | 910k | : type(raw ? 'R' : 'S') |
109 | 910k | , data(s.size()) { |
110 | 7.74M | for (size_t i = 0; i < s.size(); ++i) { |
111 | 6.83M | data[i] = uint8_t(s[i]); |
112 | 6.83M | } |
113 | 910k | } |
114 | | |
115 | | FBXExportProperty::FBXExportProperty(const std::vector<uint8_t>& r) |
116 | 271 | : type('R') |
117 | 271 | , data(r) { |
118 | | // empty |
119 | 271 | } |
120 | | |
121 | | FBXExportProperty::FBXExportProperty(const std::vector<int32_t>& va) |
122 | 11.2k | : type('i') |
123 | 11.2k | , data(4 * va.size() ) { |
124 | 11.2k | int32_t* d = reinterpret_cast<int32_t*>(data.data()); |
125 | 385k | for (size_t i = 0; i < va.size(); ++i) { |
126 | 374k | d[i] = va[i]; |
127 | 374k | } |
128 | 11.2k | } |
129 | | |
130 | | FBXExportProperty::FBXExportProperty(const std::vector<int64_t>& va) |
131 | 342 | : type('l') |
132 | 342 | , data(8 * va.size()) { |
133 | 342 | int64_t* d = reinterpret_cast<int64_t*>(data.data()); |
134 | 879 | for (size_t i = 0; i < va.size(); ++i) { |
135 | 537 | d[i] = va[i]; |
136 | 537 | } |
137 | 342 | } |
138 | | |
139 | | FBXExportProperty::FBXExportProperty(const std::vector<float>& va) |
140 | 684 | : type('f') |
141 | 684 | , data(4 * va.size()) { |
142 | 684 | float* d = reinterpret_cast<float*>(data.data()); |
143 | 2.58k | for (size_t i = 0; i < va.size(); ++i) { |
144 | 1.90k | d[i] = va[i]; |
145 | 1.90k | } |
146 | 684 | } |
147 | | |
148 | | FBXExportProperty::FBXExportProperty(const std::vector<double>& va) |
149 | 10.1k | : type('d') |
150 | 10.1k | , data(8 * va.size()) { |
151 | 10.1k | double* d = reinterpret_cast<double*>(data.data()); |
152 | 10.4k | for (size_t i = 0; i < va.size(); ++i) { |
153 | 350 | d[i] = va[i]; |
154 | 350 | } |
155 | 10.1k | } |
156 | | |
157 | | FBXExportProperty::FBXExportProperty(const aiMatrix4x4& vm) |
158 | 20.2k | : type('d') |
159 | 20.2k | , data(8 * 16) { |
160 | 20.2k | double* d = reinterpret_cast<double*>(data.data()); |
161 | 101k | for (unsigned int c = 0; c < 4; ++c) { |
162 | 404k | for (unsigned int r = 0; r < 4; ++r) { |
163 | 323k | d[4 * c + r] = vm[r][c]; |
164 | 323k | } |
165 | 80.9k | } |
166 | 20.2k | } |
167 | | |
168 | | // public member functions |
169 | | |
170 | 0 | size_t FBXExportProperty::size() { |
171 | 0 | switch (type) { |
172 | 0 | case 'C': |
173 | 0 | case 'Y': |
174 | 0 | case 'I': |
175 | 0 | case 'F': |
176 | 0 | case 'D': |
177 | 0 | case 'L': |
178 | 0 | return data.size() + 1; |
179 | 0 | case 'S': |
180 | 0 | case 'R': |
181 | 0 | return data.size() + 5; |
182 | 0 | case 'i': |
183 | 0 | case 'd': |
184 | 0 | return data.size() + 13; |
185 | 0 | default: |
186 | 0 | throw DeadlyExportError("Requested size on property of unknown type"); |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | 1.44M | void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) { |
191 | 1.44M | s.PutU1(type); |
192 | 1.44M | uint8_t* d = data.data(); |
193 | 1.44M | size_t N; |
194 | 1.44M | switch (type) { |
195 | 39.9k | case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return; |
196 | 0 | case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return; |
197 | 196k | case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return; |
198 | 0 | case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return; |
199 | 39.3k | case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return; |
200 | 218k | case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return; |
201 | 910k | case 'S': |
202 | 910k | case 'R': |
203 | 910k | s.PutU4(uint32_t(data.size())); |
204 | 7.75M | for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); } |
205 | 910k | return; |
206 | 11.2k | case 'i': |
207 | 11.2k | N = data.size() / 4; |
208 | 11.2k | s.PutU4(uint32_t(N)); // number of elements |
209 | 11.2k | s.PutU4(0); // no encoding (1 would be zip-compressed) |
210 | | // TODO: compress if large? |
211 | 11.2k | s.PutU4(uint32_t(data.size())); // data size |
212 | 385k | for (size_t i = 0; i < N; ++i) { |
213 | 374k | s.PutI4((reinterpret_cast<int32_t*>(d))[i]); |
214 | 374k | } |
215 | 11.2k | return; |
216 | 342 | case 'l': |
217 | 342 | N = data.size() / 8; |
218 | 342 | s.PutU4(uint32_t(N)); // number of elements |
219 | 342 | s.PutU4(0); // no encoding (1 would be zip-compressed) |
220 | | // TODO: compress if large? |
221 | 342 | s.PutU4(uint32_t(data.size())); // data size |
222 | 879 | for (size_t i = 0; i < N; ++i) { |
223 | 537 | s.PutI8((reinterpret_cast<int64_t*>(d))[i]); |
224 | 537 | } |
225 | 342 | return; |
226 | 684 | case 'f': |
227 | 684 | N = data.size() / 4; |
228 | 684 | s.PutU4(uint32_t(N)); // number of elements |
229 | 684 | s.PutU4(0); // no encoding (1 would be zip-compressed) |
230 | | // TODO: compress if large? |
231 | 684 | s.PutU4(uint32_t(data.size())); // data size |
232 | 2.58k | for (size_t i = 0; i < N; ++i) { |
233 | 1.90k | s.PutF4((reinterpret_cast<float*>(d))[i]); |
234 | 1.90k | } |
235 | 684 | return; |
236 | 30.3k | case 'd': |
237 | 30.3k | N = data.size() / 8; |
238 | 30.3k | s.PutU4(uint32_t(N)); // number of elements |
239 | 30.3k | s.PutU4(0); // no encoding (1 would be zip-compressed) |
240 | | // TODO: compress if large? |
241 | 30.3k | s.PutU4(uint32_t(data.size())); // data size |
242 | 354k | for (size_t i = 0; i < N; ++i) { |
243 | 323k | s.PutF8((reinterpret_cast<double*>(d))[i]); |
244 | 323k | } |
245 | 30.3k | return; |
246 | 0 | default: |
247 | 0 | std::ostringstream err; |
248 | 0 | err << "Tried to dump property with invalid type '"; |
249 | 0 | err << type << "'!"; |
250 | 0 | throw DeadlyExportError(err.str()); |
251 | 1.44M | } |
252 | 1.44M | } |
253 | | |
254 | 0 | void FBXExportProperty::DumpAscii(Assimp::StreamWriterLE& outstream, int indent) { |
255 | 0 | std::ostringstream ss; |
256 | 0 | ss.imbue(std::locale::classic()); |
257 | 0 | ss.precision(15); // this seems to match official FBX SDK exports |
258 | 0 | DumpAscii(ss, indent); |
259 | 0 | outstream.PutString(ss.str()); |
260 | 0 | } |
261 | | |
262 | 0 | void FBXExportProperty::DumpAscii(std::ostream& s, int indent) { |
263 | | // no writing type... or anything. just shove it into the stream. |
264 | 0 | uint8_t* d = data.data(); |
265 | 0 | size_t N; |
266 | 0 | size_t swap = data.size(); |
267 | 0 | size_t count = 0; |
268 | 0 | switch (type) { |
269 | 0 | case 'C': |
270 | 0 | if (*(reinterpret_cast<uint8_t*>(d))) { s << 'T'; } |
271 | 0 | else { s << 'F'; } |
272 | 0 | return; |
273 | 0 | case 'Y': s << *(reinterpret_cast<int16_t*>(d)); return; |
274 | 0 | case 'I': s << *(reinterpret_cast<int32_t*>(d)); return; |
275 | 0 | case 'F': s << *(reinterpret_cast<float*>(d)); return; |
276 | 0 | case 'D': s << *(reinterpret_cast<double*>(d)); return; |
277 | 0 | case 'L': s << *(reinterpret_cast<int64_t*>(d)); return; |
278 | 0 | case 'S': |
279 | | // first search to see if it has "\x00\x01" in it - |
280 | | // which separates fields which are reversed in the ascii version. |
281 | | // yeah. |
282 | | // FBX, yeah. |
283 | 0 | for (size_t i = 0; i < data.size(); ++i) { |
284 | 0 | if (data[i] == '\0') { |
285 | 0 | swap = i; |
286 | 0 | break; |
287 | 0 | } |
288 | 0 | } |
289 | | // assimp issue #6112; fallthrough confirmed by @mesilliac |
290 | 0 | [[fallthrough]]; |
291 | 0 | case 'R': |
292 | 0 | s << '"'; |
293 | | // we might as well check this now, |
294 | | // probably it will never happen |
295 | 0 | for (size_t i = 0; i < data.size(); ++i) { |
296 | 0 | char c = data[i]; |
297 | 0 | if (c == '"') { |
298 | 0 | throw runtime_error("can't handle quotes in property string"); |
299 | 0 | } |
300 | 0 | } |
301 | | // first write the SWAPPED member (if any) |
302 | 0 | for (size_t i = swap + 2; i < data.size(); ++i) { |
303 | 0 | char c = data[i]; |
304 | 0 | s << c; |
305 | 0 | } |
306 | | // then a separator |
307 | 0 | if (swap != data.size()) { |
308 | 0 | s << "::"; |
309 | 0 | } |
310 | | // then the initial member |
311 | 0 | for (size_t i = 0; i < swap; ++i) { |
312 | 0 | char c = data[i]; |
313 | 0 | s << c; |
314 | 0 | } |
315 | 0 | s << '"'; |
316 | 0 | return; |
317 | 0 | case 'i': |
318 | 0 | N = data.size() / 4; // number of elements |
319 | 0 | s << '*' << N << " {\n"; |
320 | 0 | for (int i = 0; i < indent + 1; ++i) { s << '\t'; } |
321 | 0 | s << "a: "; |
322 | 0 | for (size_t i = 0; i < N; ++i) { |
323 | 0 | if (i > 0) { s << ','; } |
324 | 0 | if (count++ > 120) { s << '\n'; count = 0; } |
325 | 0 | s << (reinterpret_cast<int32_t*>(d))[i]; |
326 | 0 | } |
327 | 0 | s << '\n'; |
328 | 0 | for (int i = 0; i < indent; ++i) { s << '\t'; } |
329 | 0 | s << "} "; |
330 | 0 | return; |
331 | 0 | case 'l': |
332 | 0 | N = data.size() / 8; |
333 | 0 | s << '*' << N << " {\n"; |
334 | 0 | for (int i = 0; i < indent + 1; ++i) { s << '\t'; } |
335 | 0 | s << "a: "; |
336 | 0 | for (size_t i = 0; i < N; ++i) { |
337 | 0 | if (i > 0) { s << ','; } |
338 | 0 | if (count++ > 120) { s << '\n'; count = 0; } |
339 | 0 | s << (reinterpret_cast<int64_t*>(d))[i]; |
340 | 0 | } |
341 | 0 | s << '\n'; |
342 | 0 | for (int i = 0; i < indent; ++i) { s << '\t'; } |
343 | 0 | s << "} "; |
344 | 0 | return; |
345 | 0 | case 'f': |
346 | 0 | N = data.size() / 4; |
347 | 0 | s << '*' << N << " {\n"; |
348 | 0 | for (int i = 0; i < indent + 1; ++i) { s << '\t'; } |
349 | 0 | s << "a: "; |
350 | 0 | for (size_t i = 0; i < N; ++i) { |
351 | 0 | if (i > 0) { s << ','; } |
352 | 0 | if (count++ > 120) { s << '\n'; count = 0; } |
353 | 0 | s << (reinterpret_cast<float*>(d))[i]; |
354 | 0 | } |
355 | 0 | s << '\n'; |
356 | 0 | for (int i = 0; i < indent; ++i) { s << '\t'; } |
357 | 0 | s << "} "; |
358 | 0 | return; |
359 | 0 | case 'd': |
360 | 0 | N = data.size() / 8; |
361 | 0 | s << '*' << N << " {\n"; |
362 | 0 | for (int i = 0; i < indent + 1; ++i) { s << '\t'; } |
363 | 0 | s << "a: "; |
364 | | // set precision to something that can handle doubles |
365 | 0 | s.precision(15); |
366 | 0 | for (size_t i = 0; i < N; ++i) { |
367 | 0 | if (i > 0) { s << ','; } |
368 | 0 | if (count++ > 120) { s << '\n'; count = 0; } |
369 | 0 | s << (reinterpret_cast<double*>(d))[i]; |
370 | 0 | } |
371 | 0 | s << '\n'; |
372 | 0 | for (int i = 0; i < indent; ++i) { s << '\t'; } |
373 | 0 | s << "} "; |
374 | 0 | return; |
375 | 0 | default: |
376 | 0 | std::ostringstream err; |
377 | 0 | err << "Tried to dump property with invalid type '"; |
378 | 0 | err << type << "'!"; |
379 | 0 | throw runtime_error(err.str()); |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | | } // Namespace FBX |
384 | | } // Namespace Assimp |
385 | | |
386 | | #endif // ASSIMP_BUILD_NO_FBX_EXPORTER |
387 | | #endif // ASSIMP_BUILD_NO_EXPORT |