//------------------------------------------------ //--- 010 Editor v7.0 Binary Template // // File: OVL.bt // Author: Andrew McRae // Version: 0.3 // Purpose: Parse Elite Dangerous ovl files // Category: Archive // File Mask: *.ovl // ID Bytes: 46 52 45 53 // FRES // History: // 0.3 2016-03-30 Andrew McRae: Updated header for repo // 0.2 2015-08-03 Andrew McRae: Merge changes // 0.1 2015-03-10 Andrew McRae: Initial revision //------------------------------------------------ typedef uint64 u8; typedef uint32 u4; typedef uint16 u2; typedef ubyte u1; typedef int64 s8; typedef int32 s4; typedef int16 s2; typedef byte s1; local u4 zlib_length = 0; local u4 zlib_uncomp_length = 0; typedef struct { char sig[4]; // 1575F48 u1 flags; // 1575F4C u1 version; // 1575F4D u1 need_bswap; // 1575F4E u1 unknown07 ; // 1575F4F u4 flags2; // 1575F50 u4 unknown0C ; // 1575F54 u4 names_length; // 1575F58 u4 unknown2_count ; // 1575F5C u4 other_count ; // 1575F60 u2 dir_count ; // 1575F64 u2 type_count ; // 1575F66 u4 file_count ; // 1575F68 u4 file_count2 ; // 1575F6C u4 part_count ; // 1575F70 u4 archive_count ; // 1575F74 u4 unknown30 ; // 1575F78 u4 unknown34 ; // 1575F7C u4 unknown38 ; // 1575F80 u4 unknown3C ; // 1575F84 u4 unknown_count ; // 1575F88 u4 unknown44 ; // 1575F8C u4 unknown48 ; // 1575F90 u4 unknown4C ; // 1575F94 //Assert((flags == 0) || (flags == 0x08), "HEADER flags not 0 or 0x08"); Assert((version == 0x12) || (version == 0x13), "HEADER version not 0x12 or 0x13"); Assert(file_count2 == file_count, "HEADER file_count2 mismatch"); Assert((file_count == 0) || (names_length > 0), "HEADER names_length is 0"); //Assert(dir_count == 0, "HEADER dir_count not 0"); //Assert(part_count == 0, "HEADER part_count not 0"); //Assert(other_count == 0, "HEADER other_count not 0"); //Assert(archive_count == 1, "HEADER archive_count not 1"); Assert(unknown2_count == 0, "HEADER unknown2_count not 0"); //Assert(!(dir_count != 0 && part_count != 0), "HEADER dir and part"); Assert(!(dir_count != 0 && other_count != 0), "HEADER dir and other"); Assert(!(part_count != 0 && other_count != 0), "HEADER part and other"); //Assert(flags2 == 0x00006094, "HEADER flags2 not 0x00006094"); } HEADER; typedef struct { u4 archive_names_length; u4 file_count3 ; u4 type_names_length; u4 zero0C ; u4 zero10 ; u4 zero14 ; u4 zero18 ; u4 zero1C ; u4 zero20 ; u4 zero24 ; u4 zero28 ; u4 zero2C ; u4 zero30 ; u4 zero34 ; u4 zero38 ; u4 zero3C ; Assert((h.archive_count == 0) || (archive_names_length > 0), "HEADER archive_names_length is 0"); Assert((h.file_count == 0) || (type_names_length > 0), "HEADER2 type_names_length is 0"); Assert(file_count3 == h.file_count, "HEADER2 file_count3 mismatch"); Assert(zero0C == 0, "HEADER2 zero0C"); Assert(zero10 == 0, "HEADER2 zero10"); Assert(zero14 == 0, "HEADER2 zero14"); Assert(zero18 == 0, "HEADER2 zero18"); Assert(zero1C == 0, "HEADER2 zero1C"); Assert(zero20 == 0, "HEADER2 zero20"); Assert(zero24 == 0, "HEADER2 zero24"); Assert(zero28 == 0, "HEADER2 zero28"); Assert(zero2C == 0, "HEADER2 zero2C"); Assert(zero30 == 0, "HEADER2 zero30"); Assert(zero34 == 0, "HEADER2 zero34"); Assert(zero38 == 0, "HEADER2 zero38"); Assert(zero3C == 0, "HEADER2 zero3C"); } HEADER2; typedef struct { u4 name_offset; if (is64bit) { u4 zero04 ;; } u4 hash; u2 unknown08 ; u2 unknown0A ; u4 unknown0C ; u4 count ; Assert(name_offset < h.names_length, "TYPE name_offset too high"); if (is64bit) { Assert(zero04 == 0, "TYPE zero60"); } local quad o = FTell(); FSeek(name_offset + full_names_offset); string name ; FSeek(o); } TYPE ; string read_TYPE(TYPE &in) { local string out; SPrintf(out, "\"%s\" %08Xh %Xh %Xh %Xh %d", in.name, in.hash, in.unknown08, in.unknown0A, in.unknown0C, in.count); return out; } typedef struct { TYPE t[h.type_count]; } TYPES ; string read_TYPES(TYPES &in) { local string out; SPrintf(out, "%u", h.type_count); return out; } typedef struct { u4 name_offset; u4 hash; u2 unknown08 ; u2 type ; Assert(type < h.type_count, "FILE type too high"); Assert(name_offset < h.names_length, "FILE name_offset too high"); local quad o = FTell(); FSeek(name_offset + full_names_offset); string name ; FSeek(o); } FILE ; string read_FILE(FILE &in) { local string out; SPrintf(out, "\"%s\" \"%s\" %08Xh %Xh", in.name, t.t[in.type].name, in.hash, in.unknown08); return out; } typedef struct { FILE f[h.file_count]; } FILES ; string read_FILES(FILES &in) { local string out; SPrintf(out, "%u", h.file_count); return out; } typedef struct { u4 name_offset; u4 unknown04 ; u4 unknown08 ; u4 fh2_count ; u2 fh3_count ; u2 fh1_count ; u4 zero14 ; u4 unknown18 ; u4 fh6_count ; u4 fh5_count ; u4 zero24 ; u4 unknown28 ; u4 comp_size; u4 uncomp_size; u4 zero34 ; u4 unknown38 ; u4 header2_size; u4 unknown40 ; Assert(name_offset < h2.archive_names_length, "FILE name_offset too high"); local quad o = FTell(); FSeek(name_offset + full_archive_names_offset); string name ; FSeek(o); // check if STATIC archive if (name == "STATIC") { zlib_length = comp_size; zlib_uncomp_length = uncomp_size; } //Assert(unknown04 == 0, "ARCHIVE unknown04"); //Assert(unknown08 == 0, "ARCHIVE unknown08"); Assert(zero14 == 0, "ARCHIVE zero14"); Assert(zero24 == 0, "ARCHIVE zero24"); Assert(zero34 == 0, "ARCHIVE zero34"); //Assert(unknown38 == 0, "ARCHIVE unknown38"); //Assert(unknown40 == 0, "ARCHIVE unknown40"); } ARCHIVE ; string read_ARCHIVE(ARCHIVE &in) { local string out; SPrintf(out, "\"%s\" %Xh %Xh", in.name, in.comp_size, in.uncomp_size); return out; } typedef struct { ARCHIVE a[h.archive_count]; } ARCHIVES ; string read_ARCHIVES(ARCHIVES &in) { local string out; SPrintf(out, "%u", h.archive_count); return out; } typedef struct { u4 name_offset; Assert(name_offset < h.names_length, "DIR name_offset too high"); local quad o = FTell(); FSeek(name_offset + full_names_offset); string name ; FSeek(o); } DIR ; string read_DIR(DIR &in) { local string out; SPrintf(out, "\"%s\"", in.name); return out; } typedef struct { DIR d[h.dir_count]; } DIRS ; string read_DIRS(DIRS &in) { local string out; SPrintf(out, "%u", h.dir_count); return out; } typedef struct { u4 hash; u4 name_offset; u4 unknown08 ; u4 unknown0C ; u4 unknown10 ; Assert(name_offset < h.names_length, "PART name_offset too high"); local quad o = FTell(); FSeek(name_offset + full_names_offset); string name ; FSeek(o); } PART ; string read_PART(PART &in) { local string file_name; SPrintf(file_name, "%08Xh", in.hash); local int i; for (i = 0; i < h.file_count; i++) { if (f.f[i].hash == in.hash) { SPrintf(file_name, "\"%s\"", f.f[i].name); break; } } local string out; SPrintf(out, "%s \"%s\" %Xh %Xh %Xh", file_name, in.name, in.unknown08, in.unknown0C, in.unknown10); return out; } typedef struct { PART p[h.part_count]; } PARTS ; string read_PARTS(PARTS &in) { local string out; SPrintf(out, "%u", h.part_count); return out; } typedef struct { u4 unknown00 ; u4 name_offset; u4 unknown08 ; Assert(name_offset < h.names_length, "OTHER name_offset too high"); local quad o = FTell(); FSeek(name_offset + full_names_offset); string name ; FSeek(o); } OTHER ; string read_OTHER(OTHER &in) { local string out; SPrintf(out, "\"%s\" %Xh %08Xh", in.name, in.unknown00, in.unknown08); return out; } typedef struct { OTHER o[h.other_count]; } OTHERS ; string read_OTHERS(OTHERS &in) { local string out; SPrintf(out, "%u", h.other_count); return out; } typedef struct { u4 unknown00 ; u4 unknown04 ; u4 unknown08 ; } UNKNOWN ; string read_UNKNOWN(UNKNOWN &in) { local string out; SPrintf(out, "%Xh %Xh %Xh", in.unknown00, in.unknown04, in.unknown08); return out; } typedef struct { UNKNOWN u[h.unknown_count]; } UNKNOWNS ; string read_UNKNOWNS(UNKNOWNS &in) { local string out; SPrintf(out, "%u", h.unknown_count); return out; } typedef struct { u4 unknown00 ; u4 data_size ; } ARCHIVE2 ; string read_ARCHIVE2(ARCHIVE2 &in) { local string out; SPrintf(out, "%Xh %Xh", in.unknown00, in.data_size); return out; } typedef struct { ARCHIVE2 a2[h.archive_count]; } ARCHIVES2 ; string read_ARCHIVES2(ARCHIVES2 &in) { local string out; SPrintf(out, "%u", h.archive_count); return out; } typedef struct { Assert(zlib_length > 0, "ZLIB zlib_length is 0"); Assert(ReadUShort() == 0x9c78, "ZLIB bad zlib header"); u1 data[zlib_length]; Assert(FTell() == FileSize(), "ZLIB trailing data"); } ZLIB ; string read_ZLIB(ZLIB &in) { local string out; SPrintf(out, "%Xh %Xh", zlib_length, zlib_uncomp_length); return out; } DisplayFormatHex(); LittleEndian(); local int i; Assert(ReadString(0, 4) == "FRES", "Bad sig!"); local u4 full_names_offset = 0x90; SetBackColor(0xb0b0b0); HEADER h; HEADER2 h2; local int is64bit = h.flags & 0x08; // skip main name table local u4 full_types_offset = h.names_length + full_names_offset; FSeek(full_types_offset); SetBackColor(0xffb0b0); if (h.type_count) { TYPES t; } SetBackColor(0xb0ffb0); if (h.file_count) { FILES f; } // skip archive name table local u4 full_archive_names_offset; local u4 full_archives_offset; if (is64bit) { full_archive_names_offset = h.file_count * 0x0C + h.type_count * 0x18 + full_types_offset; } else { full_archive_names_offset = h.file_count * 0x0C + h.type_count * 0x14 + full_types_offset; } full_archives_offset = h2.archive_names_length + full_archive_names_offset; FSeek(full_archives_offset); SetBackColor(0xb0b0ff); if (h.archive_count) { ARCHIVES a; } SetBackColor(0xb0ffff); if (h.dir_count) { DIRS d; } SetBackColor(0xffb0ff); if (h.part_count) { PARTS p; } SetBackColor(0xffffb0); if (h.other_count) { OTHERS o; } SetBackColor(0x48a0ff); if (h.unknown_count) { UNKNOWNS u; } SetBackColor(0xffa048); if (h.archive_count) { ARCHIVES2 a2; } SetBackColor(0x909090); ZLIB z; if (h.archive_count) { for (i = 0; i < h.archive_count; i++) { Printf("\nname: %s, comp_size: %Xh, uncomp_size: %Xh\n", a.a[i].name, a.a[i].comp_size, a.a[i].uncomp_size); Printf("header2_size: %Xh, data_size: %Xh\n", a.a[i].header2_size, a2.a2[i].data_size); Printf("(%d, %d, %d, ?, %d, %d, ?)\n", a.a[i].fh1_count, a.a[i].fh2_count, a.a[i].fh3_count, a.a[i].fh5_count, a.a[i].fh6_count); } }