mirror of
https://github.com/WerWolv/ImHex-Patterns.git
synced 2026-03-27 23:37:04 -05:00
177 lines
4.5 KiB
Rust
177 lines
4.5 KiB
Rust
#pragma description ADTFDAT File
|
|
|
|
#pragma magic [ 49 46 48 44 ] @ 0x00
|
|
#pragma endian little
|
|
|
|
import std.io;
|
|
import std.mem;
|
|
import type.time;
|
|
|
|
enum FileVersion : u32 {
|
|
with_history_end_offset = 0x00000301,
|
|
v500 = 0x00000500
|
|
};
|
|
|
|
bitfield ChunkFlags {
|
|
key : 1;
|
|
info : 1;
|
|
marker : 1;
|
|
type : 1;
|
|
trigger : 1;
|
|
reserved: 11;
|
|
};
|
|
|
|
struct Extension
|
|
{
|
|
char identifier[384];
|
|
u16 stream_id;
|
|
u8 reserved1[2];
|
|
u32 user_id;
|
|
u32 type_id;
|
|
u32 version_id;
|
|
u64 data_pos;
|
|
u64 data_size;
|
|
u8 reserved[96];
|
|
u8 payload[data_size] @ data_pos;
|
|
};
|
|
|
|
struct ChunkHeader {
|
|
u64 time_stamp [[format("format_timestamp_with_offset")]];;
|
|
u32 ref_master_table_index;
|
|
u32 offset_to_last;
|
|
u32 size;
|
|
u16 stream_id;
|
|
ChunkFlags flags;
|
|
u64 stream_index;
|
|
};
|
|
|
|
struct SampleInfo {
|
|
u8 memory_layout_version;
|
|
u32 size;
|
|
u8 payload[size];
|
|
};
|
|
|
|
struct Sample {
|
|
s64 timestamp [[format("format_timestamp")]];;
|
|
s32 flags;
|
|
u64 buffer_size;
|
|
u8 payload[buffer_size];
|
|
if (flags & 0x100) {
|
|
SampleInfo sample_info;
|
|
}
|
|
if (flags & 0x200) {
|
|
u32 substream_id;
|
|
} else {
|
|
u32 substream_id = 0 [[export]];
|
|
}
|
|
};
|
|
|
|
struct Chunk {
|
|
auto start_address = $;
|
|
|
|
ChunkHeader header;
|
|
|
|
if (header.size < 32 || start_address + header.size > std::mem::size()) {
|
|
std::warning(std::format("Invalid header size {} in chunk {} at offset 0x{:X}, last valid chunk at 0x{:X}.", header.size, chunk_index, start_address, last_valid_chunk_offset));
|
|
break;
|
|
}
|
|
|
|
last_valid_chunk_offset = start_address;
|
|
|
|
u8 payload[header.size - 32];
|
|
|
|
if (!skip_valid_chunks) {
|
|
if (!header.flags.info && !header.flags.marker && !header.flags.type && !header.flags.trigger) {
|
|
try {
|
|
Sample sample @ addressof(payload);
|
|
} catch {
|
|
std::warning(std::format("Invalid sample payload at chunk {} at 0x{:X}", chunk_index, start_address));
|
|
}
|
|
}
|
|
}
|
|
|
|
chunk_index += 1;
|
|
|
|
// Padding with 0xEE to the next chunk header
|
|
std::mem::AlignTo<16>;
|
|
|
|
if (skip_valid_chunks) {
|
|
continue;
|
|
}
|
|
};
|
|
|
|
struct Header {
|
|
u32 file_id;
|
|
u32 version_id;
|
|
u32 flags;
|
|
u32 extension_count;
|
|
u64 extension_offset;
|
|
u64 data_offset;
|
|
u64 data_size;
|
|
u64 chunk_count;
|
|
u64 max_chunk_size;
|
|
u64 duration;
|
|
type::time64_t filetime;
|
|
u8 header_byte_order;
|
|
u64 time_offset [[format("format_timestamp")]];
|
|
u8 patch_number;
|
|
u64 first_chunk_offset;
|
|
u64 continuous_offset;
|
|
u64 ring_buffer_end_offset;
|
|
u8 reserved[30];
|
|
char description[1912];
|
|
};
|
|
|
|
struct IndexedFile {
|
|
Header header;
|
|
Extension extensions[header.extension_count] @ header.extension_offset;
|
|
|
|
if (header.version_id >= FileVersion::with_history_end_offset &&
|
|
header.continuous_offset != header.data_offset) {
|
|
try {
|
|
Chunk ring_front[while($ < header.continuous_offset)] @ header.first_chunk_offset;
|
|
Chunk ring_back[while($ < header.ring_buffer_end_offset)] @ header.data_offset;
|
|
Chunk continueous[header.chunk_count - chunk_index] @ header.continuous_offset;
|
|
} catch {
|
|
std::warning("Too many chunks. Performing check only.");
|
|
skip_valid_chunks = true;
|
|
chunk_index = 0;
|
|
Chunk ring_front[while($ < header.continuous_offset)] @ header.first_chunk_offset;
|
|
Chunk ring_back[while($ < header.ring_buffer_end_offset)] @ header.data_offset;
|
|
Chunk continueous[while(chunk_index < header.chunk_count)] @ header.continuous_offset;
|
|
}
|
|
} else {
|
|
try {
|
|
Chunk chunks[header.chunk_count] @ header.data_offset;
|
|
} catch {
|
|
std::warning("Too many chunks. Performing check only.");
|
|
skip_valid_chunks = true;
|
|
chunk_index = 0;
|
|
Chunk chunks[while(chunk_index < header.chunk_count)] @ header.data_offset;
|
|
}
|
|
}
|
|
};
|
|
|
|
fn format_timestamp(u64 data) {
|
|
double seconds = 0;
|
|
if (file.header.version_id < FileVersion::v500) {
|
|
// microseconds
|
|
seconds = data / double(1000000);
|
|
} else {
|
|
// nanoseconds
|
|
seconds = data / double(1000000000);
|
|
}
|
|
|
|
std::time::Time time64 = std::time::to_utc(seconds);
|
|
return std::time::format(time64);
|
|
};
|
|
|
|
fn format_timestamp_with_offset(u64 data) {
|
|
return format_timestamp(data + file.header.time_offset);
|
|
};
|
|
|
|
bool skip_valid_chunks = false;
|
|
u64 last_valid_chunk_offset = 0;
|
|
u64 chunk_index = 0;
|
|
IndexedFile file @ 0x00;
|