|
|
|
@ -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");
|
|
|
|
|
StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
|
|
|
|
|
if (!streamOrError.error.empty()) {
|
|
|
|
|
ThrowException(streamOrError.error);
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
char version[4] = { 0 };
|
|
|
|
|
file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
|
|
|
|
|
file.little = (stream->Read(version, 1, 1), version[0] == 'v');
|
|
|
|
|
|
|
|
|
|
LogDebug("Found no BLENDER magic word but a GZIP header, might be a compressed file");
|
|
|
|
|
if (magic[2] != 8) {
|
|
|
|
|
ThrowException("Unsupported GZIP compression method");
|
|
|
|
|
}
|
|
|
|
|
stream->Read(version, 3, 1);
|
|
|
|
|
version[3] = '\0';
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file.i64bit = (stream->Read(magic, 1, 1), magic[0] == '-');
|
|
|
|
|
file.little = (stream->Read(magic, 1, 1), magic[0] == 'v');
|
|
|
|
|
|
|
|
|
|
stream->Read(magic, 3, 1);
|
|
|
|
|
magic[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
|
|
|
|
|