| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- // .blend file parser
- // Reference:
- // https://github.com/fschutt/mystery-of-the-blend-backup
- // https://web.archive.org/web/20170630054951/http://www.atmind.nl/blender/mystery_ot_blend.html
- // Usage:
- // let bl: blend_t = parser_blend_init(blob: buffer_view_t);
- // krom_log(parser_blend_dir(bl, "Scene"));
- // let scenes: any = parser_blend_get(bl, "Scene");
- // krom_log(get(get(scenes[0], "id"), "name"));
- type blend_t = {
- pos?: i32;
- view?: buffer_view_t;
- // Header
- version?: string;
- pointer_size?: i32;
- little_endian?: bool;
- // Data
- blocks?: block_t[];
- dna?: dna_t;
- map?: map_t<any, block_t>; // Map blocks by memory address
- };
- function parser_blend_init(buffer: buffer_t): blend_t {
- let raw: blend_t = {};
- raw.blocks = [];
- raw.map = map_create();
- raw.view = buffer_view_create(buffer);
- raw.pos = 0;
- if (parser_blend_read_chars(raw, 7) != "BLENDER") {
- raw.view = buffer_view_create(krom_inflate(buffer, false));
- raw.pos = 0;
- if (parser_blend_read_chars(raw, 7) != "BLENDER") {
- return null;
- }
- }
- parser_blend_parse(raw);
- return raw;
- }
- function parser_blend_dir(raw: blend_t, type: string): string[] {
- // Return structure fields
- let type_index: i32 = parser_blend_get_type_index(raw.dna, type);
- if (type_index == -1) {
- return null;
- }
- let ds: dna_struct_t = parser_blend_get_struct(raw.dna, type_index);
- let fields: string[] = [];
- for (let i: i32 = 0; i < ds.field_names.length; ++i) {
- let name_index: i32 = ds.field_names[i];
- let type_index: i32 = ds.field_types[i];
- array_push(fields, raw.dna.types[type_index] + " " + raw.dna.names[name_index]);
- }
- return fields;
- }
- function parser_blend_get(raw: blend_t, type: string): bl_handle_t[] {
- if (raw.dna == null) {
- return null;
- }
- // Return all structures of type
- let type_index: i32 = parser_blend_get_type_index(raw.dna, type);
- if (type_index == -1) {
- return null;
- }
- let ds: dna_struct_t = parser_blend_get_struct(raw.dna, type_index);
- let handles: bl_handle_t[] = [];
- for (let i: i32 = 0; i < raw.blocks.length; ++i) {
- let b: block_t = raw.blocks[i];
- if (raw.dna.structs[b.sdna_index].type == type_index) {
- let h: bl_handle_t = {};
- h.offset = 0;
- array_push(handles, h);
- h.block = b;
- h.ds = ds;
- }
- }
- return handles;
- }
- function parser_blend_get_struct(dna: dna_t, type_index: i32): dna_struct_t {
- for (let i: i32 = 0; i < dna.structs.length; ++i) {
- let ds: dna_struct_t = dna.structs[i];
- if (ds.type == type_index) {
- return ds;
- }
- }
- return null;
- }
- function parser_blend_get_type_index(dna: dna_t, type: string): i32 {
- for (let i: i32 = 0; i < dna.types.length; ++i) {
- if (type == dna.types[i]) {
- return i;
- }
- }
- return -1;
- }
- function parser_blend_parse(raw: blend_t) {
- // Pointer size: _ 32bit, - 64bit
- raw.pointer_size = parser_blend_read_char(raw) == "_" ? 4 : 8;
- // v - little endian, V - big endian
- raw.little_endian = parser_blend_read_char(raw) == "v";
- raw.version = parser_blend_read_chars(raw, 3);
- // Reading file blocks
- // Header - data
- while (raw.pos < buffer_view_size(raw.view)) {
- parser_blend_align(raw);
- let b: block_t = {};
- // Block type
- b.code = parser_blend_read_chars(raw, 4);
- if (b.code == "ENDB") {
- break;
- }
- array_push(raw.blocks, b);
- b.blend = raw;
- // Total block length
- b.size = parser_blend_read_i32(raw);
- // Memory address
- let addr: any = parser_blend_read_pointer(raw);
- if (map_get(raw.map, addr) == null) {
- map_set(raw.map, addr, b);
- }
- // Index of dna struct contained in this block
- b.sdna_index = parser_blend_read_i32(raw);
- // Number of dna structs in this block
- b.count = parser_blend_read_i32(raw);
- b.pos = raw.pos;
- // This block stores dna structures
- if (b.code == "DNA1") {
- raw.dna = {};
- raw.dna.names = [];
- raw.dna.types = [];
- raw.dna.types_length = [];
- raw.dna.structs = [];
- parser_blend_read_chars(raw, 4); // SDNA
- parser_blend_read_chars(raw, 4); // NAME
- let names_count: i32 = parser_blend_read_i32(raw);
- for (let i: i32 = 0; i < names_count; ++i) {
- array_push(raw.dna.names, parser_blend_read_string(raw));
- }
- parser_blend_align(raw);
- parser_blend_read_chars(raw, 4); // TYPE
- let types_count: i32 = parser_blend_read_i32(raw);
- for (let i: i32 = 0; i < types_count; ++i) {
- array_push(raw.dna.types, parser_blend_read_string(raw));
- }
- parser_blend_align(raw);
- parser_blend_read_chars(raw, 4); // TLEN
- for (let i: i32 = 0; i < types_count; ++i) {
- array_push(raw.dna.types_length, parser_blend_read_i16(raw));
- }
- parser_blend_align(raw);
- parser_blend_read_chars(raw, 4); // STRC
- let struct_count: i32 = parser_blend_read_i32(raw);
- for (let i: i32 = 0; i < struct_count; ++i) {
- let ds: dna_struct_t = {};
- array_push(raw.dna.structs, ds);
- ds.dna = raw.dna;
- ds.type = parser_blend_read_i16(raw);
- let field_count: i32 = parser_blend_read_i16(raw);
- if (field_count > 0) {
- ds.field_types = [];
- ds.field_names = [];
- for (let j: i32 = 0; j < field_count; ++j) {
- array_push(ds.field_types, parser_blend_read_i16(raw));
- array_push(ds.field_names, parser_blend_read_i16(raw));
- }
- }
- }
- }
- else {
- raw.pos += b.size;
- }
- }
- }
- function parser_blend_align(raw: blend_t) {
- // 4 bytes aligned
- let mod: i32 = raw.pos % 4;
- if (mod > 0) {
- raw.pos += 4 - mod;
- }
- }
- function parser_blend_read_i8(raw: blend_t): i32 {
- let i: i32 = buffer_view_get_u8(raw.view, raw.pos);
- raw.pos += 1;
- return i;
- }
- function parser_blend_read_i16(raw: blend_t): i32 {
- let i: i32 = buffer_view_get_i16(raw.view, raw.pos); //, raw.little_endian
- raw.pos += 2;
- return i;
- }
- function parser_blend_read_i32(raw: blend_t): i32 {
- let i: i32 = buffer_view_get_i32(raw.view, raw.pos); //, raw.little_endian
- raw.pos += 4;
- return i;
- }
- function parser_blend_read_i64(raw: blend_t): any {
- let aview: any = raw.view;
- let i: i32 = aview.getBigInt64(raw.pos, raw.little_endian);
- raw.pos += 8;
- return i;
- }
- function parser_blend_read_f32(raw: blend_t): f32 {
- let f: f32 = buffer_view_get_f32(raw.view, raw.pos); //, raw.little_endian
- raw.pos += 4;
- return f;
- }
- function parser_blend_read_i8array(raw: blend_t, len: i32): i32_array_t {
- let ar: i32_array_t = i32_array_create(len);
- for (let i: i32 = 0; i < len; ++i) {
- ar[i] = parser_blend_read_i8(raw);
- }
- return ar;
- }
- function parser_blend_read_i16array(raw: blend_t, len: i32): i32_array_t {
- let ar: i32_array_t = i32_array_create(len);
- for (let i: i32 = 0; i < len; ++i) {
- ar[i] = parser_blend_read_i16(raw);
- }
- return ar;
- }
- function parser_blend_read_i32array(raw: blend_t, len: i32): i32_array_t {
- let ar: i32_array_t = i32_array_create(len);
- for (let i: i32 = 0; i < len; ++i) {
- ar[i] = parser_blend_read_i32(raw);
- }
- return ar;
- }
- function parser_blend_read_f32array(raw: blend_t, len: i32): f32_array_t {
- let ar: f32_array_t = f32_array_create(len);
- for (let i: i32 = 0; i < len; ++i) {
- ar[i] = parser_blend_read_f32(raw);
- }
- return ar;
- }
- function parser_blend_read_string(raw: blend_t): string {
- let s: string = "";
- while (true) {
- let ch: i32 = parser_blend_read_i8(raw);
- if (ch == 0) {
- break;
- }
- s += string_from_char_code(ch);
- }
- return s;
- }
- function parser_blend_read_chars(raw: blend_t, len: i32): string {
- let s: string = "";
- for (let i: i32 = 0; i < len; ++i) {
- s += parser_blend_read_char(raw);
- }
- return s;
- }
- function parser_blend_read_char(raw: blend_t): string {
- return string_from_char_code(parser_blend_read_i8(raw));
- }
- function parser_blend_read_pointer(raw: blend_t): any {
- return raw.pointer_size == 4 ? parser_blend_read_i32(raw) : parser_blend_read_i64(raw);
- }
- type block_t = {
- blend?: blend_t;
- code?: string;
- size?: i32;
- sdna_index?: i32;
- count?: i32;
- pos?: i32; // Byte pos of data start in blob
- };
- type dna_t = {
- names?: string[];
- types?: string[];
- types_length?: i32[];
- structs?: dna_struct_t[];
- };
- type dna_struct_t = {
- dna?: dna_t;
- type?: i32; // Index in dna.types
- field_types?: i32[]; // Index in dna.types
- field_names?: i32[]; // Index in dna.names
- };
- type bl_handle_t = {
- block?: block_t;
- offset?: i32; // Block data bytes offset
- ds?: dna_struct_t;
- };
- function bl_handle_get_size(raw: bl_handle_t, index: i32): i32 {
- let name_index: i32 = raw.ds.field_names[index];
- let type_index: i32 = raw.ds.field_types[index];
- let dna: dna_t = raw.ds.dna;
- let n: string = dna.names[name_index];
- let size: i32 = 0;
- if (string_index_of(n, "*") >= 0) {
- size = raw.block.blend.pointer_size;
- }
- else {
- size = dna.types_length[type_index];
- }
- if (string_index_of(n, "[") > 0) {
- size *= bl_handle_get_array_len(n);
- }
- return size;
- }
- function bl_handle_base_name(s: string): string {
- while (char_at(s, 0) == "*") {
- s = substring(s, 1, s.length);
- }
- if (char_at(s, s.length - 1) == "]") {
- s = substring(s, 0, string_index_of(s, "["));
- }
- return s;
- }
- function bl_handle_get_array_len(s: string): i32 {
- return parse_int(substring(s, string_index_of(s, "[") + 1, string_index_of(s, "]")));
- }
- function bl_handle_get(raw: bl_handle_t, name: string, index: i32 = 0, as_type: string = null, array_len: i32 = 0): any {
- // Return raw type or structure
- let dna: dna_t = raw.ds.dna;
- for (let i: i32 = 0; i < raw.ds.field_names.length; ++i) {
- let name_index: i32 = raw.ds.field_names[i];
- let dna_name: string = dna.names[name_index];
- if (name == bl_handle_base_name(dna_name)) {
- let type_index: i32 = raw.ds.field_types[i];
- let type: string = dna.types[type_index];
- let new_offset: i32 = raw.offset;
- for (let j: i32 = 0; j < i; ++j) {
- new_offset += bl_handle_get_size(raw, j);
- }
- // Cast void * to type
- if (as_type != null) {
- for (let i: i32 = 0; i < dna.types.length; ++i) {
- if (dna.types[i] == as_type) {
- type_index = i;
- break;
- }
- }
- }
- // Raw type
- if (type_index < 12) {
- let blend: blend_t = raw.block.blend;
- blend.pos = raw.block.pos + new_offset;
- let is_array: bool = char_at(dna_name, dna_name.length - 1) == "]";
- let len: i32 = is_array ? (array_len > 0 ? array_len : bl_handle_get_array_len(dna_name)) : 1;
- if (type == "int") {
- return is_array ? parser_blend_read_i32array(blend, len) : parser_blend_read_i32(blend);
- }
- else if (type == "char") {
- return is_array ? parser_blend_read_string(blend) : parser_blend_read_i8(blend);
- }
- else if (type == "uchar") {
- return is_array ? parser_blend_read_i8array(blend, len) : parser_blend_read_i8(blend);
- }
- else if (type == "short") {
- return is_array ? parser_blend_read_i16array(blend, len) : parser_blend_read_i16(blend);
- }
- else if (type == "ushort") {
- return is_array ? parser_blend_read_i16array(blend, len) : parser_blend_read_i16(blend);
- }
- else if (type == "float") {
- return is_array ? parser_blend_read_f32array(blend, len) : parser_blend_read_f32(blend);
- }
- else if (type == "double") {
- return 0; //readf64(blend);
- }
- else if (type == "long") {
- return is_array ? parser_blend_read_i32array(blend, len) : parser_blend_read_i32(blend);
- }
- else if (type == "ulong") {
- return is_array ? parser_blend_read_i32array(blend, len) : parser_blend_read_i32(blend);
- }
- else if (type == "int64_t") {
- return parser_blend_read_i64(blend);
- }
- else if (type == "uint64_t") {
- return parser_blend_read_i64(blend);
- }
- else if (type == "void") {
- if (char_at(dna_name, 0) == "*") {
- return parser_blend_read_i64(blend);
- }
- }
- }
- // Structure
- let h: bl_handle_t = {};
- h.offset = 0;
- h.ds = parser_blend_get_struct(dna, type_index);
- let is_pointer: bool = char_at(dna_name, 0) == "*";
- if (is_pointer) {
- raw.block.blend.pos = raw.block.pos + new_offset;
- let addr: any = parser_blend_read_pointer(raw.block.blend);
- if (map_get(raw.block.blend.map, addr) != null) {
- h.block = map_get(raw.block.blend.map, addr);
- }
- else h.block = raw.block;
- h.offset = 0;
- }
- else {
- h.block = raw.block;
- h.offset = new_offset;
- }
- h.offset += dna.types_length[type_index] * index;
- return h;
- }
- }
- return null;
- }
|