diff --git a/external/openfbx/ofbx.cpp b/external/openfbx/ofbx.cpp index b160cf2f9..f14444e6e 100644 --- a/external/openfbx/ofbx.cpp +++ b/external/openfbx/ofbx.cpp @@ -80,6 +80,7 @@ struct Allocator { struct Video { + IElementProperty* base64_property = nullptr; DataView filename; DataView content; DataView media; @@ -1957,6 +1958,10 @@ struct Scene : IScene return m_videos[index].is_base_64; } + const IElementProperty* getEmbeddedBase64Data(int index) const override { + return m_videos[index].base64_property; + } + DataView getEmbeddedFilename(int index) const override { return m_videos[index].filename; } @@ -2256,16 +2261,6 @@ void parseVideo(Scene& scene, const Element& element, Allocator& allocator) if (!content_element->first_property) return; const Property* content_property = content_element->first_property; if (content_element->first_property->getType() != IElementProperty::BINARY) { - /* - if this happens in text format: - Content: , - "iVBORw0KGgoA... - this is not a proper solution, but keep doing this until it become an issue - */ - if (content_element->first_property->getType() != IElementProperty::NONE) return; - if (!content_element->first_property->next) return; - if (content_element->first_property->next->getType() != IElementProperty::STRING) return; - content_property = content_element->first_property->next; is_base64 = true; } @@ -2276,7 +2271,8 @@ void parseVideo(Scene& scene, const Element& element, Allocator& allocator) Video video; video.is_base_64 = is_base64; - video.content = content_property->value; + video.base64_property = is_base64 ? content_element->first_property->next : nullptr; + video.content = is_base64 ? DataView{} : content_element->first_property->value; video.filename = filename_element->first_property->value; video.media = element.first_property->next->value; scene.m_videos.push_back(video); diff --git a/external/openfbx/ofbx.h b/external/openfbx/ofbx.h index 4b61598b6..ae97a03c6 100644 --- a/external/openfbx/ofbx.h +++ b/external/openfbx/ofbx.h @@ -737,6 +737,8 @@ struct IScene virtual DataView getEmbeddedData(int index) const = 0; virtual DataView getEmbeddedFilename(int index) const = 0; virtual bool isEmbeddedBase64(int index) const = 0; + // data are encoded in returned property and all ->next properties + virtual const IElementProperty* getEmbeddedBase64Data(int index) const = 0; // Scene Misc virtual const TakeInfo* getTakeInfo(const char* name) const = 0; diff --git a/src/renderer/editor/fbx_importer.cpp b/src/renderer/editor/fbx_importer.cpp index aebbf4d4f..b421f0568 100644 --- a/src/renderer/editor/fbx_importer.cpp +++ b/src/renderer/editor/fbx_importer.cpp @@ -142,14 +142,15 @@ void decodeBase64(const void* data, const u32 len, OutputMemoryStream& str) unsigned char* p = (unsigned char*)data; int pad = len > 0 && (len % 4 || p[len - 1] == '='); const u32 L = ((len + 3) / 4 - pad) * 4; - str.resize(L / 4 * 3 + pad); + const u32 offset = (u32)str.size(); + str.resize(L / 4 * 3 + pad + offset); for (u32 i = 0, j = 0; i < L; i += 4) { int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | B64index[p[i + 2]] << 6 | B64index[p[i + 3]]; - str[j++] = n >> 16; - str[j++] = n >> 8 & 0xFF; - str[j++] = n & 0xFF; + str[offset + j++] = n >> 16; + str[offset + j++] = n >> 8 & 0xFF; + str[offset + j++] = n & 0xFF; } if (pad) { @@ -174,7 +175,7 @@ static void extractEmbedded(const ofbx::IScene& m_scene, StringView src_dir, IAl const PathInfo pi(filename); const StaticString fullpath(src_dir, pi.basename, ".", pi.extension); - if (os::fileExists(fullpath)) return; + if (os::fileExists(fullpath)) continue; os::OutputFile file; if (!file.open(fullpath)) { @@ -184,10 +185,21 @@ static void extractEmbedded(const ofbx::IScene& m_scene, StringView src_dir, IAl if (m_scene.isEmbeddedBase64(i)) { OutputMemoryStream tmp(allocator); - decodeBase64(embedded.begin, u32(embedded.end - embedded.begin), tmp); - if (!file.write(tmp.data(), tmp.size())) { - logError("Failed to write ", fullpath); + const ofbx::IElementProperty* prop = m_scene.getEmbeddedBase64Data(i); + if (prop) { + if (prop->getNext()) { + for (const auto* j = prop; j; j = j->getNext()) { + decodeBase64(j->getValue().begin, u32(j->getValue().end - j->getValue().begin), tmp); + } + } + else { + decodeBase64(prop->getValue().begin, u32(prop->getValue().end - prop->getValue().begin), tmp); + } + if (!file.write(tmp.data(), tmp.size())) { + logError("Failed to write ", fullpath); + } } + else logError("Invalid data ", fullpath); } else { if (!file.write(embedded.begin + 4, embedded.end - embedded.begin - 4)) {