|
@@ -115,15 +115,12 @@ BlenderImporter::~BlenderImporter() {
|
|
|
delete modifier_cache;
|
|
|
}
|
|
|
|
|
|
-static const char * const Tokens[] = { "BLENDER" };
|
|
|
+static const char Token[] = "BLENDER";
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
|
// Returns whether the class can handle the format of the given file.
|
|
|
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
|
|
- // note: this won't catch compressed files
|
|
|
- static const char *tokens[] = { "<BLENDER", "blender" };
|
|
|
-
|
|
|
- return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
|
|
+ return ParseMagicToken(pFile, pIOHandler).error.empty();
|
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
@@ -142,63 +139,21 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
|
|
|
// Imports the given file into the given scene structure.
|
|
|
void BlenderImporter::InternReadFile(const std::string &pFile,
|
|
|
aiScene *pScene, IOSystem *pIOHandler) {
|
|
|
-#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
|
|
- std::vector<char> uncompressed;
|
|
|
-#endif
|
|
|
-
|
|
|
FileDatabase file;
|
|
|
- std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
|
|
- if (!stream) {
|
|
|
- ThrowException("Could not open file for reading");
|
|
|
- }
|
|
|
-
|
|
|
- char magic[8] = { 0 };
|
|
|
- stream->Read(magic, 7, 1);
|
|
|
- if (strcmp(magic, Tokens[0])) {
|
|
|
- // Check for presence of the gzip header. If yes, assume it is a
|
|
|
- // compressed blend file and try uncompressing it, else fail. This is to
|
|
|
- // avoid uncompressing random files which our loader might end up with.
|
|
|
-#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
|
|
- ThrowException("BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?");
|
|
|
-#else
|
|
|
- if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
|
|
|
- ThrowException("BLENDER magic bytes are missing, couldn't find GZIP header either");
|
|
|
- }
|
|
|
-
|
|
|
- LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
|
|
|
- if (magic[2] != 8) {
|
|
|
- ThrowException("Unsupported GZIP compression method");
|
|
|
- }
|
|
|
-
|
|
|
- // http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
|
|
|
- stream->Seek(0L, aiOrigin_SET);
|
|
|
- std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
|
|
|
-
|
|
|
- size_t total = 0;
|
|
|
- Compression compression;
|
|
|
- if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
|
|
|
- total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), uncompressed);
|
|
|
- compression.close();
|
|
|
- }
|
|
|
-
|
|
|
- // replace the input stream with a memory stream
|
|
|
- stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed.data()), total);
|
|
|
-
|
|
|
- // .. and retry
|
|
|
- stream->Read(magic, 7, 1);
|
|
|
- if (strcmp(magic, "BLENDER")) {
|
|
|
- ThrowException("Found no BLENDER magic word in decompressed GZIP file");
|
|
|
- }
|
|
|
-#endif
|
|
|
+ StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
|
|
|
+ if (!streamOrError.error.empty()) {
|
|
|
+ ThrowException(streamOrError.error);
|
|
|
}
|
|
|
+ std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
|
|
|
|
|
|
- file.i64bit = (stream->Read(magic, 1, 1), magic[0] == '-');
|
|
|
- file.little = (stream->Read(magic, 1, 1), magic[0] == 'v');
|
|
|
+ char version[4] = { 0 };
|
|
|
+ file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
|
|
|
+ file.little = (stream->Read(version, 1, 1), version[0] == 'v');
|
|
|
|
|
|
- stream->Read(magic, 3, 1);
|
|
|
- magic[3] = '\0';
|
|
|
+ stream->Read(version, 3, 1);
|
|
|
+ version[3] = '\0';
|
|
|
|
|
|
- LogInfo("Blender version is ", magic[0], ".", magic + 1,
|
|
|
+ LogInfo("Blender version is ", version[0], ".", version + 1,
|
|
|
" (64bit: ", file.i64bit ? "true" : "false",
|
|
|
", little endian: ", file.little ? "true" : "false", ")");
|
|
|
|
|
@@ -1338,4 +1293,55 @@ aiNode *BlenderImporter::ConvertNode(const Scene &in, const Object *obj, Convers
|
|
|
return node.release();
|
|
|
}
|
|
|
|
|
|
+BlenderImporter::StreamOrError BlenderImporter::ParseMagicToken(const std::string &pFile, IOSystem *pIOHandler) const {
|
|
|
+ std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
|
|
+ if (stream == nullptr) {
|
|
|
+ return {{}, {}, "Could not open file for reading"};
|
|
|
+ }
|
|
|
+
|
|
|
+ char magic[8] = { 0 };
|
|
|
+ stream->Read(magic, 7, 1);
|
|
|
+ if (strcmp(magic, Token) == 0) {
|
|
|
+ return {stream, {}, {}};
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check for presence of the gzip header. If yes, assume it is a
|
|
|
+ // compressed blend file and try uncompressing it, else fail. This is to
|
|
|
+ // avoid uncompressing random files which our loader might end up with.
|
|
|
+#ifdef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
|
|
+ return {{}, {}, "BLENDER magic bytes are missing, is this file compressed (Assimp was built without decompression support)?"};
|
|
|
+#else
|
|
|
+ if (magic[0] != 0x1f || static_cast<uint8_t>(magic[1]) != 0x8b) {
|
|
|
+ return {{}, {}, "BLENDER magic bytes are missing, couldn't find GZIP header either"};
|
|
|
+ }
|
|
|
+
|
|
|
+ LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
|
|
|
+ if (magic[2] != 8) {
|
|
|
+ return {{}, {}, "Unsupported GZIP compression method"};
|
|
|
+ }
|
|
|
+
|
|
|
+ // http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
|
|
|
+ stream->Seek(0L, aiOrigin_SET);
|
|
|
+ std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream));
|
|
|
+
|
|
|
+ size_t total = 0;
|
|
|
+ Compression compression;
|
|
|
+ auto uncompressed = std::make_shared<std::vector<char>>();
|
|
|
+ if (compression.open(Compression::Format::Binary, Compression::FlushMode::NoFlush, 16 + Compression::MaxWBits)) {
|
|
|
+ total = compression.decompress((unsigned char *)reader->GetPtr(), reader->GetRemainingSize(), *uncompressed);
|
|
|
+ compression.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ // replace the input stream with a memory stream
|
|
|
+ stream = std::make_shared<MemoryIOStream>(reinterpret_cast<uint8_t *>(uncompressed->data()), total);
|
|
|
+
|
|
|
+ // .. and retry
|
|
|
+ stream->Read(magic, 7, 1);
|
|
|
+ if (strcmp(magic, Token) == 0) {
|
|
|
+ return {stream, uncompressed, {}};
|
|
|
+ }
|
|
|
+ return {{}, {}, "Found no BLENDER magic word in decompressed GZIP file"};
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|