From faa3caa627ff8e62b4bd6cfabe052691a14948ce Mon Sep 17 00:00:00 2001 From: Mikulas Florek Date: Sun, 15 Oct 2023 00:15:22 +0200 Subject: [PATCH] base64 encoded embedded data --- external/openfbx/ofbx.cpp | 26 +++++++++++--- external/openfbx/ofbx.h | 1 + src/renderer/editor/fbx_importer.cpp | 52 +++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/external/openfbx/ofbx.cpp b/external/openfbx/ofbx.cpp index 3a1e06d928..b160cf2f9c 100644 --- a/external/openfbx/ofbx.cpp +++ b/external/openfbx/ofbx.cpp @@ -78,13 +78,12 @@ struct Allocator { }; - - struct Video { DataView filename; DataView content; DataView media; + bool is_base_64; }; @@ -1954,6 +1953,10 @@ struct Scene : IScene return m_videos[index].content; } + bool isEmbeddedBase64(int index) const override { + return m_videos[index].is_base_64; + } + DataView getEmbeddedFilename(int index) const override { return m_videos[index].filename; } @@ -2248,9 +2251,23 @@ void parseVideo(Scene& scene, const Element& element, Allocator& allocator) const Element* content_element = findChild(element, "Content"); + bool is_base64 = false; if (!content_element) return; if (!content_element->first_property) return; - if (content_element->first_property->getType() != IElementProperty::BINARY) 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; + } const Element* filename_element = findChild(element, "Filename"); if (!filename_element) return; @@ -2258,7 +2275,8 @@ void parseVideo(Scene& scene, const Element& element, Allocator& allocator) if (filename_element->first_property->getType() != IElementProperty::STRING) return; Video video; - video.content = content_element->first_property->value; + video.is_base_64 = is_base64; + video.content = content_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 0908b73c48..4b61598b65 100644 --- a/external/openfbx/ofbx.h +++ b/external/openfbx/ofbx.h @@ -736,6 +736,7 @@ struct IScene virtual int getEmbeddedDataCount() const = 0; virtual DataView getEmbeddedData(int index) const = 0; virtual DataView getEmbeddedFilename(int index) const = 0; + virtual bool isEmbeddedBase64(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 4e35b4b612..aebbf4d4f6 100644 --- a/src/renderer/editor/fbx_importer.cpp +++ b/src/renderer/editor/fbx_importer.cpp @@ -129,7 +129,42 @@ static StringView toStringView(ofbx::DataView data) { ); } -static void extractEmbedded(const ofbx::IScene& m_scene, StringView src_dir) +static const int B64index[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, +56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, +7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, +0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, +41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; + +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); + + 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; + } + if (pad) + { + int n = B64index[p[L]] << 18 | B64index[p[L + 1]] << 12; + str[u32(str.size() - 1)] = n >> 16; + + if (len > L + 2 && p[L + 2] != '=') + { + n |= B64index[p[L + 2]] << 6; + str.write(u8(n >> 8 & 0xFF)); + } + } +} + +static void extractEmbedded(const ofbx::IScene& m_scene, StringView src_dir, IAllocator& allocator) { PROFILE_FUNCTION(); for (int i = 0, c = m_scene.getEmbeddedDataCount(); i < c; ++i) { @@ -147,8 +182,17 @@ static void extractEmbedded(const ofbx::IScene& m_scene, StringView src_dir) return; } - if (!file.write(embedded.begin + 4, embedded.end - embedded.begin - 4)) { - logError("Failed to write ", fullpath); + 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); + } + } + else { + if (!file.write(embedded.begin + 4, embedded.end - embedded.begin - 4)) { + logError("Failed to write ", fullpath); + } } file.close(); } @@ -1046,7 +1090,7 @@ bool FBXImporter::setSource(const Path& filename, bool ignore_geometry, bool for } StringView src_dir = Path::getDir(filename); - if (!ignore_geometry) extractEmbedded(*m_scene, src_dir); + if (!ignore_geometry) extractEmbedded(*m_scene, src_dir, m_allocator); gatherMeshes(); gatherAnimations();