1 | /* |
2 | Open Asset Import Library (assimp) |
3 | ---------------------------------------------------------------------- |
4 | |
5 | Copyright (c) 2006-2024, 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 FBXParser.h |
43 | * @brief FBX parsing code |
44 | */ |
45 | #ifndef INCLUDED_AI_FBX_PARSER_H |
46 | #define INCLUDED_AI_FBX_PARSER_H |
47 | |
48 | #include <stdint.h> |
49 | #include <map> |
50 | #include <memory> |
51 | #include <vector> |
52 | #include <assimp/LogAux.h> |
53 | #include <assimp/fast_atof.h> |
54 | |
55 | #include "Common/StackAllocator.h" |
56 | #include "FBXCompileConfig.h" |
57 | #include "FBXTokenizer.h" |
58 | |
59 | namespace Assimp { |
60 | namespace FBX { |
61 | |
62 | class Scope; |
63 | class Parser; |
64 | class Element; |
65 | |
66 | using ScopeList = std::vector<Scope*>; |
67 | using ElementMap = std::fbx_unordered_multimap< std::string, Element*>; |
68 | using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>; |
69 | |
70 | #define new_Scope new (allocator.Allocate(sizeof(Scope))) Scope |
71 | #define new_Element new (allocator.Allocate(sizeof(Element))) Element |
72 | #define delete_Scope(_p) (_p)->~Scope() |
73 | #define delete_Element(_p) (_p)->~Element() |
74 | |
75 | /** FBX data entity that consists of a key:value tuple. |
76 | * |
77 | * Example: |
78 | * @verbatim |
79 | * AnimationCurve: 23, "AnimCurve::", "" { |
80 | * [..] |
81 | * } |
82 | * @endverbatim |
83 | * |
84 | * As can be seen in this sample, elements can contain nested #Scope |
85 | * as their trailing member. |
86 | **/ |
87 | class Element |
88 | { |
89 | public: |
90 | Element(const Token& key_token, Parser& parser); |
91 | ~Element(); |
92 | |
93 | const Scope* Compound() const { |
94 | return compound; |
95 | } |
96 | |
97 | const Token& KeyToken() const { |
98 | return key_token; |
99 | } |
100 | |
101 | const TokenList& Tokens() const { |
102 | return tokens; |
103 | } |
104 | |
105 | private: |
106 | const Token& key_token; |
107 | TokenList tokens; |
108 | Scope* compound; |
109 | }; |
110 | |
111 | /** FBX data entity that consists of a 'scope', a collection |
112 | * of not necessarily unique #Element instances. |
113 | * |
114 | * Example: |
115 | * @verbatim |
116 | * GlobalSettings: { |
117 | * Version: 1000 |
118 | * Properties70: |
119 | * [...] |
120 | * } |
121 | * @endverbatim */ |
122 | class Scope |
123 | { |
124 | public: |
125 | Scope(Parser& parser, bool topLevel = false); |
126 | ~Scope(); |
127 | |
128 | const Element* operator[] (const std::string& index) const { |
129 | ElementMap::const_iterator it = elements.find(x: index); |
130 | return it == elements.end() ? nullptr : (*it).second; |
131 | } |
132 | |
133 | const Element* FindElementCaseInsensitive(const std::string& elementName) const { |
134 | const char* elementNameCStr = elementName.c_str(); |
135 | for (auto element = elements.begin(); element != elements.end(); ++element) |
136 | { |
137 | if (!ASSIMP_strincmp(s1: element->first.c_str(), s2: elementNameCStr, n: AI_MAXLEN)) { |
138 | return element->second; |
139 | } |
140 | } |
141 | return nullptr; |
142 | } |
143 | |
144 | ElementCollection GetCollection(const std::string& index) const { |
145 | return elements.equal_range(x: index); |
146 | } |
147 | |
148 | const ElementMap& Elements() const { |
149 | return elements; |
150 | } |
151 | |
152 | private: |
153 | ElementMap elements; |
154 | }; |
155 | |
156 | /** FBX parsing class, takes a list of input tokens and generates a hierarchy |
157 | * of nested #Scope instances, representing the fbx DOM.*/ |
158 | class Parser |
159 | { |
160 | public: |
161 | /** Parse given a token list. Does not take ownership of the tokens - |
162 | * the objects must persist during the entire parser lifetime */ |
163 | Parser(const TokenList &tokens, StackAllocator &allocator, bool is_binary); |
164 | ~Parser(); |
165 | |
166 | const Scope& GetRootScope() const { |
167 | return *root; |
168 | } |
169 | |
170 | bool IsBinary() const { |
171 | return is_binary; |
172 | } |
173 | |
174 | StackAllocator &GetAllocator() { |
175 | return allocator; |
176 | } |
177 | |
178 | private: |
179 | friend class Scope; |
180 | friend class Element; |
181 | |
182 | TokenPtr AdvanceToNextToken(); |
183 | TokenPtr LastToken() const; |
184 | TokenPtr CurrentToken() const; |
185 | |
186 | private: |
187 | const TokenList& tokens; |
188 | StackAllocator &allocator; |
189 | TokenPtr last, current; |
190 | TokenList::const_iterator cursor; |
191 | Scope *root; |
192 | |
193 | const bool is_binary; |
194 | }; |
195 | |
196 | |
197 | /* token parsing - this happens when building the DOM out of the parse-tree*/ |
198 | uint64_t ParseTokenAsID(const Token& t, const char*& err_out); |
199 | size_t ParseTokenAsDim(const Token& t, const char*& err_out); |
200 | |
201 | float ParseTokenAsFloat(const Token& t, const char*& err_out); |
202 | int ParseTokenAsInt(const Token& t, const char*& err_out); |
203 | int64_t ParseTokenAsInt64(const Token& t, const char*& err_out); |
204 | std::string ParseTokenAsString(const Token& t, const char*& err_out); |
205 | |
206 | /* wrapper around ParseTokenAsXXX() with DOMError handling */ |
207 | uint64_t ParseTokenAsID(const Token& t); |
208 | size_t ParseTokenAsDim(const Token& t); |
209 | float ParseTokenAsFloat(const Token& t); |
210 | int ParseTokenAsInt(const Token& t); |
211 | int64_t ParseTokenAsInt64(const Token& t); |
212 | std::string ParseTokenAsString(const Token& t); |
213 | |
214 | /* read data arrays */ |
215 | void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el); |
216 | void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el); |
217 | void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el); |
218 | void ParseVectorDataArray(std::vector<int>& out, const Element& el); |
219 | void ParseVectorDataArray(std::vector<float>& out, const Element& el); |
220 | void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el); |
221 | void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e); |
222 | void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el); |
223 | |
224 | bool HasElement( const Scope& sc, const std::string& index ); |
225 | |
226 | // extract a required element from a scope, abort if the element cannot be found |
227 | const Element &GetRequiredElement(const Scope &sc, const std::string &index, const Element *element = nullptr); |
228 | |
229 | // extract required compound scope |
230 | const Scope& GetRequiredScope(const Element& el); |
231 | // get token at a particular index |
232 | const Token& GetRequiredToken(const Element& el, unsigned int index); |
233 | |
234 | // read a 4x4 matrix from an array of 16 floats |
235 | aiMatrix4x4 ReadMatrix(const Element& element); |
236 | |
237 | } // ! FBX |
238 | } // ! Assimp |
239 | |
240 | #endif // ! INCLUDED_AI_FBX_PARSER_H |
241 | |