Unify way to check readable blender files.
parent
03934128fc
commit
82d3f47432
|
@ -115,15 +115,12 @@ BlenderImporter::~BlenderImporter() {
|
||||||
delete modifier_cache;
|
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.
|
// Returns whether the class can handle the format of the given file.
|
||||||
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
|
||||||
// note: this won't catch compressed files
|
return ParseMagicToken(pFile, pIOHandler).error.empty();
|
||||||
static const char *tokens[] = { "<BLENDER", "blender" };
|
|
||||||
|
|
||||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -142,63 +139,21 @@ void BlenderImporter::SetupProperties(const Importer * /*pImp*/) {
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void BlenderImporter::InternReadFile(const std::string &pFile,
|
void BlenderImporter::InternReadFile(const std::string &pFile,
|
||||||
aiScene *pScene, IOSystem *pIOHandler) {
|
aiScene *pScene, IOSystem *pIOHandler) {
|
||||||
#ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
|
|
||||||
std::vector<char> uncompressed;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FileDatabase file;
|
FileDatabase file;
|
||||||
std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
StreamOrError streamOrError = ParseMagicToken(pFile, pIOHandler);
|
||||||
if (!stream) {
|
if (!streamOrError.error.empty()) {
|
||||||
ThrowException("Could not open file for reading");
|
ThrowException(streamOrError.error);
|
||||||
}
|
}
|
||||||
|
std::shared_ptr<IOStream> stream = std::move(streamOrError.stream);
|
||||||
|
|
||||||
char magic[8] = { 0 };
|
char version[4] = { 0 };
|
||||||
stream->Read(magic, 7, 1);
|
file.i64bit = (stream->Read(version, 1, 1), version[0] == '-');
|
||||||
if (strcmp(magic, Tokens[0])) {
|
file.little = (stream->Read(version, 1, 1), version[0] == 'v');
|
||||||
// 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");
|
stream->Read(version, 3, 1);
|
||||||
if (magic[2] != 8) {
|
version[3] = '\0';
|
||||||
ThrowException("Unsupported GZIP compression method");
|
|
||||||
}
|
|
||||||
|
|
||||||
// http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
|
LogInfo("Blender version is ", version[0], ".", version + 1,
|
||||||
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,
|
|
||||||
" (64bit: ", file.i64bit ? "true" : "false",
|
" (64bit: ", file.i64bit ? "true" : "false",
|
||||||
", little endian: ", file.little ? "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();
|
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
|
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
|
||||||
|
|
|
@ -180,6 +180,19 @@ private:
|
||||||
const Blender::MTex *tex,
|
const Blender::MTex *tex,
|
||||||
Blender::ConversionData &conv_data);
|
Blender::ConversionData &conv_data);
|
||||||
|
|
||||||
|
// TODO: Move to a std::variant, once c++17 is supported.
|
||||||
|
struct StreamOrError {
|
||||||
|
std::shared_ptr<IOStream> stream;
|
||||||
|
std::shared_ptr<std::vector<char>> input;
|
||||||
|
std::string error;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns either a stream (and optional input data for the stream) or
|
||||||
|
// an error if it can't parse the magic token.
|
||||||
|
StreamOrError ParseMagicToken(
|
||||||
|
const std::string &pFile,
|
||||||
|
IOSystem *pIOHandler) const;
|
||||||
|
|
||||||
private: // static stuff, mostly logging and error reporting.
|
private: // static stuff, mostly logging and error reporting.
|
||||||
// --------------------
|
// --------------------
|
||||||
static void CheckActualType(const Blender::ElemBase *dt,
|
static void CheckActualType(const Blender::ElemBase *dt,
|
||||||
|
|
Loading…
Reference in New Issue