1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following 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
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42/** @file Definition of the base class for all importer worker classes. */
43#ifndef INCLUDED_AI_BASEIMPORTER_H
44#define INCLUDED_AI_BASEIMPORTER_H
45
46#include "Exceptional.h"
47
48#include <vector>
49#include <set>
50#include <assimp/types.h>
51#include <assimp/ProgressHandler.hpp>
52
53struct aiScene;
54struct aiImporterDesc;
55
56namespace Assimp {
57
58class Importer;
59class IOSystem;
60class BaseProcess;
61class SharedPostProcessInfo;
62class IOStream;
63
64// utility to do char4 to uint32 in a portable manner
65#define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
66 (string[1] << 16) + (string[2] << 8) + string[3]))
67
68
69// ---------------------------------------------------------------------------
70/** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface
71 * for all importer worker classes.
72 *
73 * The interface defines two functions: CanRead() is used to check if the
74 * importer can handle the format of the given file. If an implementation of
75 * this function returns true, the importer then calls ReadFile() which
76 * imports the given file. ReadFile is not overridable, it just calls
77 * InternReadFile() and catches any ImportErrorException that might occur.
78 */
79class ASSIMP_API BaseImporter
80{
81 friend class Importer;
82
83public:
84
85 /** Constructor to be privately used by #Importer */
86 BaseImporter();
87
88 /** Destructor, private as well */
89 virtual ~BaseImporter();
90
91public:
92 // -------------------------------------------------------------------
93 /** Returns whether the class can handle the format of the given file.
94 *
95 * The implementation should be as quick as possible. A check for
96 * the file extension is enough. If no suitable loader is found with
97 * this strategy, CanRead() is called again, the 'checkSig' parameter
98 * set to true this time. Now the implementation is expected to
99 * perform a full check of the file structure, possibly searching the
100 * first bytes of the file for magic identifiers or keywords.
101 *
102 * @param pFile Path and file name of the file to be examined.
103 * @param pIOHandler The IO handler to use for accessing any file.
104 * @param checkSig Set to true if this method is called a second time.
105 * This time, the implementation may take more time to examine the
106 * contents of the file to be loaded for magic bytes, keywords, etc
107 * to be able to load files with unknown/not existent file extensions.
108 * @return true if the class can read this file, false if not.
109 */
110 virtual bool CanRead(
111 const std::string& pFile,
112 IOSystem* pIOHandler,
113 bool checkSig
114 ) const = 0;
115
116 // -------------------------------------------------------------------
117 /** Imports the given file and returns the imported data.
118 * If the import succeeds, ownership of the data is transferred to
119 * the caller. If the import fails, NULL is returned. The function
120 * takes care that any partially constructed data is destroyed
121 * beforehand.
122 *
123 * @param pImp #Importer object hosting this loader.
124 * @param pFile Path of the file to be imported.
125 * @param pIOHandler IO-Handler used to open this and possible other files.
126 * @return The imported data or NULL if failed. If it failed a
127 * human-readable error description can be retrieved by calling
128 * GetErrorText()
129 *
130 * @note This function is not intended to be overridden. Implement
131 * InternReadFile() to do the import. If an exception is thrown somewhere
132 * in InternReadFile(), this function will catch it and transform it into
133 * a suitable response to the caller.
134 */
135 aiScene* ReadFile(
136 const Importer* pImp,
137 const std::string& pFile,
138 IOSystem* pIOHandler
139 );
140
141 // -------------------------------------------------------------------
142 /** Returns the error description of the last error that occurred.
143 * @return A description of the last error that occurred. An empty
144 * string if there was no error.
145 */
146 const std::string& GetErrorText() const {
147 return m_ErrorText;
148 }
149
150 // -------------------------------------------------------------------
151 /** Called prior to ReadFile().
152 * The function is a request to the importer to update its configuration
153 * basing on the Importer's configuration property list.
154 * @param pImp Importer instance
155 */
156 virtual void SetupProperties(
157 const Importer* pImp
158 );
159
160 // -------------------------------------------------------------------
161 /** Called by #Importer::GetImporterInfo to get a description of
162 * some loader features. Importers must provide this information. */
163 virtual const aiImporterDesc* GetInfo() const = 0;
164
165 // -------------------------------------------------------------------
166 /** Called by #Importer::GetExtensionList for each loaded importer.
167 * Take the extension list contained in the structure returned by
168 * #GetInfo and insert all file extensions into the given set.
169 * @param extension set to collect file extensions in*/
170 void GetExtensionList(std::set<std::string>& extensions);
171
172protected:
173
174 // -------------------------------------------------------------------
175 /** Imports the given file into the given scene structure. The
176 * function is expected to throw an ImportErrorException if there is
177 * an error. If it terminates normally, the data in aiScene is
178 * expected to be correct. Override this function to implement the
179 * actual importing.
180 * <br>
181 * The output scene must meet the following requirements:<br>
182 * <ul>
183 * <li>At least a root node must be there, even if its only purpose
184 * is to reference one mesh.</li>
185 * <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives
186 * in the mesh are determined automatically in this case.</li>
187 * <li>the vertex data is stored in a pseudo-indexed "verbose" format.
188 * In fact this means that every vertex that is referenced by
189 * a face is unique. Or the other way round: a vertex index may
190 * not occur twice in a single aiMesh.</li>
191 * <li>aiAnimation::mDuration may be -1. Assimp determines the length
192 * of the animation automatically in this case as the length of
193 * the longest animation channel.</li>
194 * <li>aiMesh::mBitangents may be NULL if tangents and normals are
195 * given. In this case bitangents are computed as the cross product
196 * between normal and tangent.</li>
197 * <li>There needn't be a material. If none is there a default material
198 * is generated. However, it is recommended practice for loaders
199 * to generate a default material for yourself that matches the
200 * default material setting for the file format better than Assimp's
201 * generic default material. Note that default materials *should*
202 * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded
203 * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy)
204 * texture. </li>
205 * </ul>
206 * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul>
207 * <li> at least one mesh must be there</li>
208 * <li> there may be no meshes with 0 vertices or faces</li>
209 * </ul>
210 * This won't be checked (except by the validation step): Assimp will
211 * crash if one of the conditions is not met!
212 *
213 * @param pFile Path of the file to be imported.
214 * @param pScene The scene object to hold the imported data.
215 * NULL is not a valid parameter.
216 * @param pIOHandler The IO handler to use for any file access.
217 * NULL is not a valid parameter. */
218 virtual void InternReadFile(
219 const std::string& pFile,
220 aiScene* pScene,
221 IOSystem* pIOHandler
222 ) = 0;
223
224public: // static utilities
225
226 // -------------------------------------------------------------------
227 /** A utility for CanRead().
228 *
229 * The function searches the header of a file for a specific token
230 * and returns true if this token is found. This works for text
231 * files only. There is a rudimentary handling of UNICODE files.
232 * The comparison is case independent.
233 *
234 * @param pIOSystem IO System to work with
235 * @param file File name of the file
236 * @param tokens List of tokens to search for
237 * @param numTokens Size of the token array
238 * @param searchBytes Number of bytes to be searched for the tokens.
239 */
240 static bool SearchFileHeaderForToken(
241 IOSystem* pIOSystem,
242 const std::string& file,
243 const char** tokens,
244 unsigned int numTokens,
245 unsigned int searchBytes = 200,
246 bool tokensSol = false);
247
248 // -------------------------------------------------------------------
249 /** @brief Check whether a file has a specific file extension
250 * @param pFile Input file
251 * @param ext0 Extension to check for. Lowercase characters only, no dot!
252 * @param ext1 Optional second extension
253 * @param ext2 Optional third extension
254 * @note Case-insensitive
255 */
256 static bool SimpleExtensionCheck (
257 const std::string& pFile,
258 const char* ext0,
259 const char* ext1 = NULL,
260 const char* ext2 = NULL);
261
262 // -------------------------------------------------------------------
263 /** @brief Extract file extension from a string
264 * @param pFile Input file
265 * @return Extension without trailing dot, all lowercase
266 */
267 static std::string GetExtension (
268 const std::string& pFile);
269
270 // -------------------------------------------------------------------
271 /** @brief Check whether a file starts with one or more magic tokens
272 * @param pFile Input file
273 * @param pIOHandler IO system to be used
274 * @param magic n magic tokens
275 * @params num Size of magic
276 * @param offset Offset from file start where tokens are located
277 * @param Size of one token, in bytes. Maximally 16 bytes.
278 * @return true if one of the given tokens was found
279 *
280 * @note For convenience, the check is also performed for the
281 * byte-swapped variant of all tokens (big endian). Only for
282 * tokens of size 2,4.
283 */
284 static bool CheckMagicToken(
285 IOSystem* pIOHandler,
286 const std::string& pFile,
287 const void* magic,
288 unsigned int num,
289 unsigned int offset = 0,
290 unsigned int size = 4);
291
292 // -------------------------------------------------------------------
293 /** An utility for all text file loaders. It converts a file to our
294 * UTF8 character set. Errors are reported, but ignored.
295 *
296 * @param data File buffer to be converted to UTF8 data. The buffer
297 * is resized as appropriate. */
298 static void ConvertToUTF8(
299 std::vector<char>& data);
300
301 // -------------------------------------------------------------------
302 /** An utility for all text file loaders. It converts a file from our
303 * UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
304 *
305 * @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
306 * is resized as appropriate. */
307 static void ConvertUTF8toISO8859_1(
308 std::string& data);
309
310 // -------------------------------------------------------------------
311 /// @brief Enum to define, if empty files are ok or not.
312 enum TextFileMode {
313 ALLOW_EMPTY,
314 FORBID_EMPTY
315 };
316
317 // -------------------------------------------------------------------
318 /** Utility for text file loaders which copies the contents of the
319 * file into a memory buffer and converts it to our UTF8
320 * representation.
321 * @param stream Stream to read from.
322 * @param data Output buffer to be resized and filled with the
323 * converted text file data. The buffer is terminated with
324 * a binary 0.
325 * @param mode Whether it is OK to load empty text files. */
326 static void TextFileToBuffer(
327 IOStream* stream,
328 std::vector<char>& data,
329 TextFileMode mode = FORBID_EMPTY);
330
331 // -------------------------------------------------------------------
332 /** Utility function to move a std::vector into a aiScene array
333 * @param vec The vector to be moved
334 * @param out The output pointer to the allocated array.
335 * @param numOut The output count of elements copied. */
336 template<typename T>
337 AI_FORCE_INLINE
338 static void CopyVector(
339 std::vector<T>& vec,
340 T*& out,
341 unsigned int& outLength)
342 {
343 outLength = unsigned(vec.size());
344 if (outLength) {
345 out = new T[outLength];
346 std::swap_ranges(vec.begin(), vec.end(), out);
347 }
348 }
349
350protected:
351 /// Error description in case there was one.
352 std::string m_ErrorText;
353 /// Currently set progress handler.
354 ProgressHandler* m_progress;
355};
356
357
358
359} // end of namespace Assimp
360
361#endif // AI_BASEIMPORTER_H_INC
362