diff --git a/patterns/fbx.hexpat b/patterns/fbx.hexpat index 13d8a8d..0e898d6 100644 --- a/patterns/fbx.hexpat +++ b/patterns/fbx.hexpat @@ -1,6 +1,12 @@ #pragma description Kaydara FBX Binary +#pragma magic [4B 61 79 64 61 72 61 20 46 42 58 20 42 69 6E 61 72 79 20 20 00 1A 00] @ 0x00 -// Based on Blenders implementation of FBX import/export +/* + * Based on Blenders implementation of FBX import/export, see: + * (incomplete) https://code.blender.org/2013/08/fbx-binary-file-format-specification/ + * https://projects.blender.org/blender/blender/src/branch/main/scripts/addons_core/io_scene_fbx/parse_fbx.py + * https://projects.blender.org/blender/blender/src/branch/main/scripts/addons_core/io_scene_fbx/encode_bin.py + */ #pragma endian little @@ -17,9 +23,9 @@ struct Array { u32 arrayLength; u32 encoding; u32 compressedLength; - + std::assert(encoding < 2, "Invalid array encoding!"); - + if (encoding == 0) { // Uncompressed E contents[arrayLength]; @@ -31,7 +37,11 @@ struct Array { #ifdef __IMHEX__ std::mem::Section contentsSection = std::mem::create_section(std::format("contentsSection @ {:#x}", pos)); hex::dec::zlib_decompress(compressedContents, contentsSection, 15); - E contents[] @ 0x00 in contentsSection; + auto contentsSectionSize = std::mem::get_section_size(contentsSection); + auto contentsElementSize = sizeof(E); + std::assert_warn((contentsSectionSize % contentsElementSize) == 0, + "The size of the contentsSection must be an integer multiple of sizeof(E) !"); + E contents[contentsSectionSize / contentsElementSize] @ 0x00 in contentsSection; #endif } }; @@ -57,7 +67,7 @@ enum PropertyTypeCode : char { struct PropertyRecord { PropertyTypeCode typeCode; - + match (typeCode) { (PropertyTypeCode::BYTE): s8 data; (PropertyTypeCode::SHORT): s16 data; @@ -90,15 +100,15 @@ struct NodeRecord32 { u32 numProperties; u32 propertyListLen; u8 nameLen; - + // Detect sentinel record which marks the end of a list of node records - if (endOffset == 0 - && numProperties == 0 - && propertyListLen == 0 + if (endOffset == 0 + && numProperties == 0 + && propertyListLen == 0 && nameLen == 0) { break; } - + char name[nameLen]; auto posBeforePropertyRecords = $; auto posAfterPropertyRecords = posBeforePropertyRecords + propertyListLen; @@ -113,15 +123,15 @@ struct NodeRecord64 { u64 numProperties; u64 propertyListLen; u8 nameLen; - + // Detect sentinel record which marks the end of a list of node records - if (endOffset == 0 - && numProperties == 0 - && propertyListLen == 0 + if (endOffset == 0 + && numProperties == 0 + && propertyListLen == 0 && nameLen == 0) { break; } - + char name[nameLen]; auto posBeforePropertyRecords = $; auto posAfterPropertyRecords = posBeforePropertyRecords + propertyListLen; @@ -133,27 +143,27 @@ struct NodeRecord64 { fn assertZero (auto array, u128 size, auto message) { bool nonzeroPadding = false; - + for (u8 i = 0, i < size, i = i + 1) { if (array[i] != 0) { nonzeroPadding = true; } } - + std::assert_warn(!nonzeroPadding, message); }; -struct Footer{ +struct Footer { type::Magic<"\xFA\xBC\xAB\x09\xD0\xC8\xD4\x66\xB1\x76\xFB\x83\x1C\xF7\x26\x7E"> footerId; char zeroes[4]; assertZero(zeroes, 4, "Found non-zero values in footer after footerId!"); u128 ofs = $; u8 alignmentPaddingSize = ((ofs + 15) & ~15) - ofs; - + if (alignmentPaddingSize == 0) { alignmentPaddingSize = 16; } - + char alignmentPadding[alignmentPaddingSize]; assertZero(alignmentPadding, alignmentPaddingSize, "Found non-zero bytes in alignmentPadding!"); u32 version; @@ -162,7 +172,6 @@ struct Footer{ type::Magic<"\xF8\x5A\x8C\x6A\xDE\xF5\xD9\x7E\xEC\xE9\x0C\xE3\x75\x8F\x29\x0B"> footerMagic; }; - struct Header { type::Magic<"Kaydara FBX Binary \x00\x1A\x00"> magic; u32 version; @@ -170,15 +179,15 @@ struct Header { struct FBX { Header header; - - if (header.version < 7500) { + + if (header.version < 7500) { NodeRecord32 rootRecords[while(true)]; } else { NodeRecord64 rootRecords[while(true)]; } - + Footer footer; std::assert_warn(header.version == footer.version, "Version numbers in header and footer do not match!"); }; -FBX fbx @ 0x00; +FBX fbx @ 0x00; \ No newline at end of file