[Specification] Rename structs to blocks for consistency

This commit is contained in:
2025-07-31 21:31:07 +01:00
parent 76b47e0db1
commit cf63690fdd
25 changed files with 23 additions and 23 deletions

View File

@@ -0,0 +1,84 @@
=== Bitstream Data Block (`BITS`)
The `BITS` block contains a list of all known bitstream captures.
A *bitstream* is derived by interpreting flux transitions using an encoding scheme timing table.
While bitstreams sit below sector-level data in the hierarchy, they are still a higher abstraction than raw flux transitions.
Storing bitstream data is valuable because multiple dumps from the same media often produce inconsistent and incomparable flux transitions.
However, once decoded into bitstreams—regardless of whether sector-level user data can be extracted—the results remain consistent and comparable.
Bitstream-level representations are also preferred in low-level emulation scenarios.
Emulators, such as floppy drive emulators, can reconstruct original media more effectively using bitstream data than flux data.
Bitstream data is stored in `DataBlocks` with the `bitstream` data type.
Each image must contain exactly one deduplication table of this data type, and that table must have a single level.
NOTE: Bitstream deduplication tables provide a reference for associating bitstream captures and their corresponding data blocks.
==== Structure Definition
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The flux data block identifier, always 'BITS'
|uint16_t
|2 bytes
|entries
|The number of entries following this header
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the data following this header
|===
==== Bitstream entries
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|head
|Head the data corresponds to.
|uint16_t
|2 bytes
|track
|Track the data corresponds to.
|uint8_t
|1 byte
|subtrack
|Substep of a track that the data corresponds to.
|uint64_t
|8 bytes
|tableEntry
|Entry number in the deduplication table where the data corresponding to this bitstream entry is stored
|===
To better understand the relationship between user data, bitstream data and flux data please refer to _Annex F_.

View File

@@ -0,0 +1,5 @@
== The Blocks
The blocks in AaruFormat serve as the building components of the image, containing both the data and metadata extracted from the media it represents.
include::index.adoc[]

View File

@@ -0,0 +1,74 @@
=== Compact Disc Indexes Block ('CDIX')
On CompactDisc and related media, tracks can contain multiple indexes.
These are used to mark separations in the data, such as distinct segments of a musical performance.
The table of contents always references index 1. All other indexes—including index 0 (the pregap)—are stored in the subchannel information.
This block holds a list of all known indexes for quick lookup.
==== Structure Definition
[source,c]
#define CD_INDEXES_MAGIC 0x58444943
/* TODO */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The compact disc indexes block identifier, always `CDIX`
|uint16_t
|2 bytes
|entries
|The number of entries following this header
|uint32_t
|4 bytes
|length
|The length in bytes of the data following this header.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the data following this header
|===
==== Index entries
[source,c]
/* TODO */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint16_t
|2 bytes
|track
|Track this index belongs to.
|uint16_t
|2 bytes
|index
|Index number.
|int32_t
|4 bytes
|lba
|LBA where this index starts.
|===

View File

@@ -0,0 +1,110 @@
=== Checksum Block (`CKSM`)
This block stores an array of checksums corresponding to the user data embedded in the image.
For media formats such as CompactDisc, the checksum is calculated over the complete sector—comprising the prefix, user data, and suffix—totaling 2352 bytes.
If the image is modified, the checksum block is considered outdated and should be either removed or excluded from the most recent index to ensure integrity.
==== Structure Definition
[source,c]
#define CHECKSUM_MAGIC 0x4D534B43
/**
* Checksum block, contains a checksum of all user data sectors (except for optical discs that is 2352 uint8_ts raw
* sector if available
* */
typedef struct ChecksumHeader
{
/**Identifier, <see cref="BlockType.ChecksumBlock" /> */
uint32_t identifier;
/**Length in uint8_ts of the block */
uint32_t length;
/**How many checksums follow */
uint8_t entries;
} ChecksumHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The tracks block identifier, always `CKSM`
|uint32_t
|4 bytes
|length
|The length in bytes of the data following this header.
|uint8_t
|1 byte
|entries
|The number of entries following this header
|===
==== Checksum entries
[source,c]
/**Checksum entry, followed by checksum data itself */
typedef struct ChecksumEntry
{
/**Checksum algorithm */
uint8_t type;
/**Length in uint8_ts of checksum that follows this structure */
uint32_t length;
} ChecksumEntry;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint8_t
|1 byte
|type
|Checksum algorithm.
|uint32_t
|4 bytes
|length
|Size in bytes of the checksum that immediately follows this entry.
|===
==== Checksum algorithms
[cols="2,2,6",options="header"]
|===
|Type
|Value
|Description
|Invalid
|0
|Invalid checksum entry, skip.
|Md5
|1
|MD5
|Sha1
|2
|SHA1
|Sha256
|3
|SHA-256
|SpamSum
|4
|SpamSum
|===

View File

@@ -0,0 +1,25 @@
=== CICM XML Metadata Block ('CICM')
This block header signifies the inclusion of an embedded CICM XML metadata sidecar.
The contents of the XML are preserved in their original form and are not parsed, interpreted, or validated by the format implementation.
==== Structure Definition
[source,c]
#define CICM_MAGIC 0x4D434943
/**Header for the CICM XML metadata block */
typedef struct CicmMetadataBlock
{
/**Identifier, <see cref="BlockType.CicmBlock" /> */
uint32_t identifier;
uint32_t length;
} CicmMetadataBlock;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type|Size|Name|Description
|uint32|4 bytes|identifier|The CICM XML metadata table identifier, always `CICM`
|uint32|4 bytes|length|The size in bytes of the embedded CICM XML metadata that follows this header.
|===

View File

@@ -0,0 +1,83 @@
=== The data block (`DBLK`)
A data block encapsulates media-derived content and is composed of a header followed by either compressed or uncompressed data.
The contents of a data block may represent user data—such as media sectors—or auxiliary data elements, including media or sector-specific tags.
When a data block includes multiple items (e.g., sectors or sector tags), the `sectorSize` field specifies the size, in bytes, of each individual item.
Conversely, if the block contains a single item (e.g., media tags), `sectorSize` must be set to 0.
==== Structure Definition
[source,c]
#define DATABLOCK_MAGIC 0x4B4C4244
/**Block header, precedes block data */
typedef struct BlockHeader
{
/**Identifier, <see cref="BlockType.DataBlock" /> */
uint32_t identifier;
/**Type of data contained by this block */
uint32_t type;
/**Compression algorithm used to compress the block */
uint16_t compression;
/**Size in uint8_ts of each sector contained in this block */
uint32_t sectorSize;
/**Compressed length for the block */
uint32_t cmpLength;
/**Uncompressed length for the block */
uint32_t length;
/**CRC64-ECMA of the compressed block */
uint64_t cmpCrc64;
/**CRC64-ECMA of the uncompressed block */
uint64_t crc64;
} BlockHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The data block identifier, always `DBLK`
|uint16_t
|2 bytes
|type
|The data type contained in this block. See Annex B.
|uint16_t
|2 bytes
|compression
|The compression algorithm used in the data. See Annex C.
|uint32_t
|4 bytes
|sectorSize
|The size in bytes of the sectors contained in this data block if applicable.
|uint32_t
|4 bytes
|cmpLength
|The size in bytes of the compressed data that follows this header.
|uint32_t
|4 bytes
|length
|The size in bytes of the data block when decompressed.
|uint64_t
|8 bytes
|cmpCrc64
|The CRC64-ECMA checksum of the compressed data that follows this header.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the decompressed data.
|===

146
docs/spec/blocks/ddt.adoc Normal file
View File

@@ -0,0 +1,146 @@
=== The deduplication table (`DDT*`) *_DEPRECATED_*
The deduplication table is a sequential array of pointers, with each entry corresponding to a sector on the storage media.
These pointers map sector data to logical content blocks, enabling efficient elimination of duplicate data.
Every image must include at least one deduplication table of type `UserData`.
*Deprecation Notice*: This block is deprecated and *MUST NOT* be used in new image files.
==== Structure Definition
[source,c]
#define DDT_MAGIC 0X2A544444
/**Header for a deduplication table. Table follows it */
typedef struct DdtHeader
{
/**Identifier, <see cref="BlockType.DeDuplicationTable" /> */
uint32_t identifier;
/**Type of data pointed by this DDT */
uint32_t type;
/**Compression algorithm used to compress the DDT */
uint16_t compression;
/**Each entry is ((uint8_t offset in file) &lt;&lt; shift) + (sector offset in block) */
uint8_t shift;
/**How many entries are in the table */
uint64_t entries;
/**Compressed length for the DDT */
uint64_t cmpLength;
/**Uncompressed length for the DDT */
uint64_t length;
/**CRC64-ECMA of the compressed DDT */
uint64_t cmpCrc64;
/**CRC64-ECMA of the uncompressed DDT */
uint64_t crc64;
} DdtHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The deduplication table identifier, always 'DDT*'
|uint16_t
|2 bytes
|type
|The data type pointed by this table. See Annex B.
|uint16_t
|2 bytes
|compression
|The compression algorithm used in the table. See Annex C.
|uint8_t
|1 byte
|shift
|The shift used to calculate the position of a sector in a data block pointed by this table.
|uint64_t
|8 bytes
|entries
|How many pointers follow this header.
|uint32_t
|4 bytes
|cmpLength
|The size in bytes of the compressed table that follows this header.
|uint32_t
|4 bytes
|length
|The size in bytes of the table block when decompressed.
|uint64_t
|8 bytes
|cmpCrc64
|The CRC64-ECMA checksum of the compressed table that follows this header.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the decompressed table.
|===
==== Deduplication Table Entries
Each entry in the deduplication table references a specific data block and a particular item within that block.
===== Mapping Logic
- Entry 0 corresponds to data associated with LBA 0 of the media; subsequent entries map sequentially.
- The pointer value for an entry is computed using the formula:
+
[source]
pointer = (byte_offset_of_block << shift) + item_index_in_block
+
For example, a raw pointer value of `0x8003` in a table with a `shift` of 5 resolves as follows:
- Byte offset: `0x400` → `1024`
- Item index: `0x3` → `3`
- Therefore, the pointer targets item 3 within the data block located at byte offset `1024` in the file.
==== Special Case Corrected Sector Tables
Deduplication tables of type `CdSectorPrefixCorrected` and `CdSectorSuffixCorrected` split the entry value using bitmasking:
- Pointer component: `entry & 0x00FFFFFF`
- Flags component: `entry & 0xFF000000`
===== Flags
[cols="2,1,6",options="header"]
|===
|Flag
|Value
|Description
|None
|`0x00000000`
|The suffix or prefix cannot be regenerated as is stored in the pointed data block.
|NotDumped
|`0x10000000`
|The sector has not been dumped. Ignore the pointer.
|Correct
|`0x20000000`
|The suffix (only for MODE 1 sectors) or prefix is correct and can be regenerated. Ignore the pointer.
|Mode2Form1Ok
|`0x30000000`
|The suffix for MODE 2 sectors is correct, can be regenerated, and corresponds to a MODE 2 Form 1 sector.
|Mode2Form2Ok
|`0x40000000`
|The suffix for MODE 2 sectors is correct, can be regenerated, and corresponds to a MODE 2 Form 2 sector with a valid CRC.
|Mode2Form2NoCrc
|`0x50000000`
|The suffix for MODE 2 sectors is correct, can be regenerated, and corresponds to a MODE 2 Form 2 sector with an empty CRC.
|===

224
docs/spec/blocks/ddt2.adoc Normal file
View File

@@ -0,0 +1,224 @@
=== The deduplication table (`DDT2`)
The deduplication table is a multi-level table of pointers to LBAs contained in the image.
It starts with the following header.
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The deduplication table identifier, always `DDT2` or `DDTS`. The first level of a table is always `DDT2` and its presence is mandatory. Subtables will have `DDTS`
|uint16_t
|2 bytes
|type
|The data type pointed by this table. See Annex B.
|uint16_t
|2 bytes
|compression
|The compression algorithm used in the table. See Annex C.
|uint8_t
|1 byte
|levels
|How many levels of subtables are present. 1 means this is the only level.
|uint8_t
|1 byte
|tableLevel
|What level does this table correspond to
|uint64_t
|8 bytes
|previousLevel
|Pointer to absolute byte offset in the image file where the previous table level resides
|uint16_t
|2 bytes
|negative
|The negative displacement of LBA numbers. For media that can have negative LBAs, this establishes the number to substract to the table entry number
|uint64_t
|8 bytes
|start
|The first LBA contained in this table. It must be 0 for DDT2 blocks and can be other number for subtables DDTS
|uint8_t
|1 byte
|alignment
|Shift of alignment of all blocks in the image. This must be the same in all deduplication tables and subtables.
|uint8_t
|1 byte
|shift
|The shift used to calculate the position of a sector in a data block pointed by this table, or how many sectors are pointed by the next level.
|uint8_t
|1 byte
|sizeType
|Size type (see table below)
|uint64_t
|8 bytes
|entries
|How many pointers follow this header.
|uint32_t
|4 bytes
|cmpLength
|The size in bytes of the compressed table that follows this header.
|uint32_t
|4 bytes
|length
|The size in bytes of the table block when decompressed.
|uint64_t
|8 bytes
|cmpCrc64
|The CRC64-ECMA checksum of the compressed table that follows this header.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the decompressed table.
|===
The size type defines the following type of entries:
[cols="1,1,6",options="header"]
|===
|Type
|Value
|Description
|Mini
|0
|Each entry uses two bytes, with the leftmost byte (mask 0xFF00) used for flags, and the rightmost byte used as a pointer to the sector or next level.
|Small
|1
|Each entry uses three bytes, with the leftmost byte used for flags and the next two bytes used as a pointer to the sector or next level.
|Medium
|2
|Each entry uses four bytes, with the leftmost byte (mask 0xFF000000) used for flags and the next three bytes used as a pointer to the sector or next level.
|Big
|3
|Each entry uses five bytes, with the leftmost byte used for flags and the next three bytes used as a pointer to the sector or next level.
|===
==== Sector Pointer Resolution and Table Levels
When `levels` is equal to 1—indicating a single-level deduplication table—each entry in the table corresponds directly to a media sector.
The pointer value is resolved using the following procedure:
- Right-shift the raw pointer value by the `shift` value.
- Multiply the result by the `alignment` to compute the absolute byte offset of the target data block.
- The remainder of the original pointer value modulo `(1 << shift)` yields the item index within the block.
Each data block stores a fixed number of bytes per sector, allowing compact and efficient sector addressing.
_For example_:
Given a pointer value of `0x8003`, a `shift` of 5, and an `alignment` of 9:
- `0x8003 >> 5 = 0x400 = 1024`
- `1024 * 9 = 9216`
- The sector index within the block is `0x8003 & 0x1F = 3`
Thus, the sector is located at byte offset `9216`, and it is the 3rd item in the block.
===== Multi-Level Tables
When `levels > 1`, the interpretation of pointer entries changes substantially.
Although typical usage involves no more than two levels, implementations **MUST** be capable of handling an arbitrary number of levels to ensure forward compatibility.
At each level—except the final—the table entry functions as an address to the next-level table.
The range of LBAs covered by each entry is calculated as:
[source]
range = entry_index * (1 << shift)^(levels - 1)
_For example_, with a `shift` value of 9 and two levels:
- Entry `0` spans LBAs `0511`
- Entry `1` spans LBAs `5121023`
With three levels:
- Entry `0` at level 0 spans LBAs `0262143`
- Entry `0` at level 1 within that region spans LBAs `0511`, and so on recursively.
===== Resolution Example
To locate sector `1012` using a two-level table with `shift = 9` and `alignment = 9`:
1. **Level 0**:
- Sector `1012` falls within entry `1` (covers `5121023`)
- Entry `1` contains the value `0x12000`
- Multiply by `alignment` → `0x12000 * 9 = 0x225000 = 37,748,736`
- Read the next-level table at byte offset `37,748,736`, marked with the identifier `DDTS`
2. **Level 1**:
- The relevant entry is `500` (`1012 - 512 = 500`)
- Entry `500` contains `0x35006`
- Right-shift `0x35006 >> 9 = 0x6A = 106`
- Multiply by `alignment`: `106 * 9 = 954`
- Sector resides at byte offset `217,088` and is the 6th item in the block (`0x35006 & 0x1FF = 6`)
===== Deduplication table flags
[cols="2,1,6",options="header"]
|===
|Flag
|Value
|Description
|NotDumped
|`0x00`
|The sector(s) have not been dumped
|Dumped
|`0x01`
|The sector(s) have been dumped without errors
|Errored
|`0x02`
|The sector(s) returned an error on dumping
|Mode1Correct
|`0x03`
|The sector is MODE 1 and the suffix or prefix is correct and can be regenerated. Must only appear on deduplications tables with types CdSectorPrefixCorrected or CdSectorSuffixCorrected
|Mode2Form1Ok
|`0x04`
|The suffix for MODE 2 sectors is correct, can be regenerated, and corresponds to a MODE 2 Form 1 sector. Must only appear on deduplications tables with type CdSectorSuffixCorrected
|Mode2Form2Ok
|`0x05`
|The suffix for MODE 2 sectors is correct, can be regenerated, and corresponds to a MODE 2 Form 2 sector with a valid CRC. Must only appear on deduplications tables with type CdSectorSuffixCorrected
|Mode2Form2NoCrc
|`0x06`
|The suffix for MODE 2 sectors is correct, can be regenerated, and corresponds to a MODE 2 Form 2 sector with an empty CRC. Must only appear on deduplications tables with type CdSectorSuffixCorrected
|Twin
|`0x07`
|The pointer contains a “twin” sector table (see below)
|Unrecorded
|`0x08`
|The sector was unrecorded and each re-read returns random data
|===
When flags are present in a table that has sublevels it applies to all the sectors that shall be present in the subtable, unless the flag specify something else.

View File

@@ -0,0 +1,6 @@
=== Data Position Measurement Block (`DPM*`)
This block captures measurements of each sectors position, providing insights into the physical structure of the disc.
It is designed to facilitate analysis of disc geometry and sector layout.
The formal definition of this blocks format is reserved for a future revision of the specification.

View File

@@ -0,0 +1,178 @@
=== Dump Hardware Block (`DMP*`)
This block defines the set of hardware components involved in capturing the media content.
It includes an array listing each device used during the dumping process, along with the specific extents each device recorded.
This structure allows implementations to trace data provenance and associate dumped regions with their corresponding hardware sources, ensuring accountability and reproducibility in the dumping workflow.
==== Structure Definition
[source,c]
/**Dump hardware block, contains a list of hardware used to dump the media on this image */
typedef struct DumpHardwareHeader
{
/**Identifier, <see cref="BlockType.DumpHardwareBlock" /> */
uint32_t identifier;
/**How many entries follow this header */
uint16_t entries;
/**Size of the whole block, not including this header, in uint8_ts */
uint32_t length;
/**CRC64-ECMA of the block */
uint64_t crc64;
} DumpHardwareHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The dump hardware block identifier, always `DMP*`
|uint16_t
|2 bytes
|entries
|The number of entries following this header
|uint32_t
|4 bytes
|length
|The length in bytes of the data following this header.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the data following this header
|===
==== Dump hardware entries
[source,c]
/**Dump hardware entry, contains length of strings that follow, in the same order as the length, this structure */
typedef struct DumpHardwareEntry
{
/**Length of UTF-8 manufacturer string */
uint32_t manufacturerLength;
/**Length of UTF-8 model string */
uint32_t modelLength;
/**Length of UTF-8 revision string */
uint32_t revisionLength;
/**Length of UTF-8 firmware version string */
uint32_t firmwareLength;
/**Length of UTF-8 serial string */
uint32_t serialLength;
/**Length of UTF-8 software name string */
uint32_t softwareNameLength;
/**Length of UTF-8 software version string */
uint32_t softwareVersionLength;
/**Length of UTF-8 software operating system string */
uint32_t softwareOperatingSystemLength;
/**How many extents are after the strings */
uint32_t extents;
} DumpHardwareEntry;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|manufacturerLength
|Length of UTF-8 manufacturer string.
|uint32_t
|4 bytes
|modelLength
|Length of UTF-8 model string.
|uint32_t
|4 bytes
|revisionLength
|Length of UTF-8 revision string.
|uint32_t
|4 bytes
|firmwareLength
|Length of UTF-8 firmware version string.
|uint32_t
|4 bytes
|serialLength
|Length of UTF-8 serial number string.
|uint32_t
|4 bytes
|softwareNameLength
|Length of UTF-8 software name string.
|uint32_t
|4 bytes
|softwareVersionLength
|Length of UTF-8 software version string.
|uint32_t
|4 bytes
|softwareOperatingSystemLength
|Length of UTF-8 software operating system string.
|uint32_t
|4 bytes
|extents
|How many extents are after the strings.
|===
==== Extents
[source,c]
/**Dump hardware extent, contains the start and end of the extent in the media */
typedef struct DumpHardwareExtent
{
/**Start of the extent in the media */
uint64_t start;
/**End of the extent in the media */
uint64_t end;
} DumpHardwareExtent;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint64_t
|8 bytes
|start
|Starting LBA of the extent (inclusive).
|uint64_t
|8 bytes
|end
|Ending LBA of the extent (inclusive).
|===
Each dump hardware entry is followed by a sequence of string fields in the following fixed order:
. Manufacturer
. Model
. Revision
. Firmware Version
. Serial Number
. Software Name
. Software Version
. Software Operating System
Immediately after the final string (`Software Operating System`), the list of extents associated with that hardware entry begins.

View File

@@ -0,0 +1,88 @@
=== Flux Data Block (`FLUX`)
This block lists all known flux captures.
Certain hardware devices, such as Kryoflux, Pauline, and Applesauce, read magnetic media at the flux transition level.
Flux transition reads are digital representations of the analog properties of the media, and cannot be reliably interpreted on a sector-by-sector basis without further processing.
Instead, the data is accessed through capture blocks whose size varies based on the medium and imaging hardware.
For example, floppy disk captures typically represent one full track revolution; Applesauce may capture 1¼ revolutions.
For Quick Disks, the minimum capture is often an entire side of the media.
Each capture block includes two flux data streams: one for user data and one for the indexing signal.
Flux data is represented as an array of `uint8_t` bytes.
Each byte stores the tick count since the last flux transition.
If no transition is detected within a byte's range, the value `0xFF` is used, and counting resumes in the next byte with ticks accumulated.
Flux data is stored in `DataBlocks` of the flux data type, referenced from a deduplication table of the same type.
Only one flux-type deduplication table is allowed per image, and it must have exactly one level.
==== Structure Definition
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The flux data block identifier, always 'FLUX'
|uint16_t
|2 bytes
|entries
|The number of entries following this header
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the data following this header
|===
==== Flux entries
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|head
|Head the data corresponds to.
|uint16_t
|2 bytes
|track
|Track the data corresponds to.
|uint8_t
|1 byte
|subtrack
|Substep of a track that the data corresponds to.
|uint64_t
|8 bytes
|resolution
|Number of picoseconds at which the sampling was performed.
|uint64_t
|8 bytes
|tableEntry
|Entry number in the deduplication table where the data corresponding to this flux entry is stored
|===

View File

@@ -0,0 +1,48 @@
=== The geometry block (`GEOM`)
The geometry block encapsulates metadata that defines the disks geometry, primarily to support transformations between CHS (Cylinder-Head-Sector) and LBA (Logical Block Addressing) addressing schemes.
Note that the stored geometry may not reflect the medias actual physical layout.
Instead, it typically represents the translation parameters active at the time the drive image was acquired.
[source,c]
#define GEOM_MAGIC 0x4D4F4547
/**Geometry block, contains physical geometry information */
typedef struct GeometryBlockHeader
{
/**Identifier, <see cref="BlockType.GeometryBlock" /> */
uint32_t identifier;
uint32_t cylinders;
uint32_t heads;
uint32_t sectorsPerTrack;
} GeometryBlockHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The geometry table identifier, always `GEOM`
|uint32_t
|4 bytes
|cylinders
|The number of cylinders.
|uint32_t
|4 bytes
|heads
|The number of heads.
|uint32_t
|4 bytes
|sectorsPerTrack
|The number of sectors per track.
|===

View File

@@ -0,0 +1,79 @@
== Master Header Structure
The AaruHeaderV2 is the fundamental header present at the beginning of every AaruFormat file.
It defines the image's versioning, metadata, layout offset, feature compatibility, and structural alignment.
All subsequent parsing and interpretation of the file depends on the contents of this header.
=== Structure Definition
[source,c]
#define HEADER_APP_NAME_LEN 64
#define GUID_SIZE 16
/**Header, at start of file */
typedef struct AaruHeaderV2
{
/**Header identifier, see AARU_MAGIC */
uint64_t identifier;
/**UTF-16LE name of the application that created the image */
uint8_t application[HEADER_APP_NAME_LEN];
/**Image format major version. A new major version means a possibly incompatible change of format */
uint8_t imageMajorVersion;
/**Image format minor version. A new minor version indicates a compatible change of format */
uint8_t imageMinorVersion;
/**Major version of the application that created the image */
uint8_t applicationMajorVersion;
/**Minor version of the application that created the image */
uint8_t applicationMinorVersion;
/**Type of media contained on image */
uint32_t mediaType;
/**Offset to index */
uint64_t indexOffset;
/**Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image creation time */
int64_t creationTime;
/**Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image last written time */
int64_t lastWrittenTime;
/**Unique identifier that allows children images to recognize and find this image */
uint8_t guid[GUID_SIZE];
/**Block alignment shift. All blocks in the image are aligned at 2 << blockAlignmentShift bytes */
uint8_t blockAlignmentShift;
/**Data shift. All data blocks in the image contain 2 << dataShift items at most */
uint8_t dataShift;
/**Table shift. All deduplication tables in the image use this shift to calculate the position of an item */
uint8_t tableShift;
/**Features used in this image that if unsupported are still compatible for reading and writing implementations */
uint64_t featureCompatible;
/**Features used in this image that if unsupported are still compatible for reading implementations but not for writing */
uint64_t featureCompatibleRo;
/**Features used in this image that if unsupported prevent reading or writing the image */
uint64_t featureIncompatible;
} AaruHeaderV2;
=== Field Descriptions
[cols="2,3,6",options="header"]
|===
| Name | Type | Description
| identifier | uint64_t | Header identifier constant. Must match the predefined `AARU_MAGIC` value to validate the format.
| application | uint8_t[HEADER_APP_NAME_LEN] | UTF-16LE encoded name of the application responsible for creating the image.
Length is defined by `HEADER_APP_NAME_LEN`.
| imageMajorVersion | uint8_t | Major version of the AaruFormat structure.
A bump indicates potential breaking changes.
| imageMinorVersion | uint8_t | Minor version of the format, for backward-compatible structural updates.
| applicationMajorVersion | uint8_t | Major version of the creating application.
| applicationMinorVersion | uint8_t | Minor version of the application.
| mediaType | uint32_t | Media type identifier denoting the nature of the captured content (e.g., floppy, optical disc, tape).
| indexOffset | uint64_t | Absolute file offset to the beginning of the index structure, used to locate blocks throughout the image.
| creationTime | int64_t | Timestamp (Windows filetime) representing when the image was first created.
| lastWrittenTime | int64_t | Timestamp (Windows filetime) of the last modification made to the image.
| guid | uint8_t[GUID_SIZE] | Globally Unique Identifier (GUID) that allows linking of related image derivatives and child snapshots.
Length is defined by `GUID_SIZE`.
| blockAlignmentShift | uint8_t | Determines block alignment boundaries using the formula 2 << blockAlignmentShift.
| featureCompatible | uint64_t | Bitmask of features that, even if not implemented, still allow reading and writing the image.
| featureCompatibleRo | uint64_t | Bitmask of features that allow read-only processing of the image if unsupported.
| featureIncompatible | uint64_t | Bitmask of features that must be supported to read or write the image at all.
|===

View File

@@ -0,0 +1,87 @@
=== The index block (`INDX`) *_DEPRECATED_*
The index block stores references to all blocks present in the file.
It is composed of a header, followed by a sequence of entries, the count of which is defined within the header.
Multiple index blocks may exist within a file to represent previous states or historical versions; however, only the final index block must be referenced by the main file header.
*Deprecation Notice*: This block is deprecated and *MUST NOT* be used in new image files.
==== Structure Definition
[source,c]
#define INDEX_MAGIC 0x58444E49
/**Header for the index, followed by entries */
typedef struct IndexHeader
{
/**Identifier, <see cref="BlockType.Index" /> */
uint32_t identifier;
/**How many entries follow this header */
uint16_t entries;
/**CRC64-ECMA of the index */
uint64_t crc64;
} IndexHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The index block identifier, always `INDX`
|uint16_t
|2 bytes
|entries
|The number of entries following this header
|uint64_t
|8 bytes
|crc64
|CRC64-ECMA checksum of the entries following this header
|===
==== Index entries
[source,c]
/**Index entry */
typedef struct IndexEntry
{
/**Type of item pointed by this entry */
uint32_t blockType;
/**Type of data contained by the block pointed by this entry */
uint32_t dataType;
/**Offset in file where item is stored */
uint64_t offset;
} IndexEntry;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|blockType
|The type of block this entry points to.
|uint32_t
|4 bytes
|dataType
|The type of data the block pointed by this entry contains.
|uint64_t
|8 bytes
|offset
|The offset in bytes from the start of the file where the block pointed by this entry starts.
|===

View File

@@ -0,0 +1,85 @@
=== The index block version 2 (`IDX2`)
The index block stores references to all blocks present in the file.
It is composed of a header, followed by a sequence of entries, the count of which is defined within the header.
Multiple index blocks may exist within a file to represent previous states or historical versions; however, only the final index block must be referenced by the main file header.
==== Structure Definition
[source,c]
#define INDEX2_MAGIC 0x32584449
/**Header for the index, followed by entries */
typedef struct IndexHeader2
{
/**Identifier, <see cref="BlockType.Index" /> */
uint32_t identifier;
/**How many entries follow this header */
uint64_t entries;
/**CRC64-ECMA of the index */
uint64_t crc64;
} IndexHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The index block identifier, always `IDX2`
|uint64_t
|8 bytes
|entries
|The number of entries following this header
|uint64_t
|8 bytes
|crc64
|CRC64-ECMA checksum of the entries following this header
|===
==== Index entries
[source,c]
/**Index entry */
typedef struct IndexEntry
{
/**Type of item pointed by this entry */
uint32_t blockType;
/**Type of data contained by the block pointed by this entry */
uint32_t dataType;
/**Offset in file where item is stored */
uint64_t offset;
} IndexEntry;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|blockType
|The type of block this entry points to.
|uint32_t
|4 bytes
|dataType
|The type of data the block pointed by this entry contains.
|uint64_t
|8 bytes
|offset
|The offset in bytes from the start of the file where the block pointed by this entry starts.
|===

View File

@@ -0,0 +1,45 @@
=== The index block continuation (`IDXC`)
The index block continuation follows the same structure and semantics as the index block version 2, with the exception that it includes a pointer to the preceding index block or index block continuation.
At most, a single index block continuation may appear within any index block structure.
The purpose of this block is to enable incremental indexing prior to finalizing the image file.
This allows new blocks to be indexed as they are written, facilitating partial recovery in the event of application failure.
The block is immediately followed by index entries formatted identically to those defined in index block version 2.
==== Structure Definition
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32
|4 bytes
|identifier
|The index block identifier, always `IDXC`
|uint64
|8 bytes
|entries
|The number of entries following this header
|uint64
|8 bytes
|crc64
|CRC64-ECMA checksum of the entries following this header
|uint64
|8 bytes
|previous
|Pointer in image file to previous index block
|===

View File

@@ -0,0 +1,219 @@
=== The metadata block (`META`)
The metadata block contains descriptive information related to the media source, which is not part of the original media data itself.
Typical fields may include the manufacturer name, device model, acquisition sequence identifiers, and other contextual attributes.
All string values within this block are encoded as little-endian UTF-16 and terminated with a null character.
[source,c]
#define META_MAGIC 0x4154454D
/**Metadata block, contains metadata */
typedef struct MetadataBlockHeader
{
/**Identifier, <see cref="BlockType.MetadataBlock" /> */
uint32_t identifier;
/**Size in uint8_ts of this whole metadata block */
uint32_t blockSize;
/**Sequence of media set this media beint64_ts to */
int32_t mediaSequence;
/**Total number of media on the media set this media beint64_ts to */
int32_t lastMediaSequence;
/**Offset to start of creator string from start of this block */
uint32_t creatorOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t creatorLength;
/**Offset to start of creator string from start of this block */
uint32_t commentsOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t commentsLength;
/**Offset to start of creator string from start of this block */
uint32_t mediaTitleOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t mediaTitleLength;
/**Offset to start of creator string from start of this block */
uint32_t mediaManufacturerOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t mediaManufacturerLength;
/**Offset to start of creator string from start of this block */
uint32_t mediaModelOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t mediaModelLength;
/**Offset to start of creator string from start of this block */
uint32_t mediaSerialNumberOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t mediaSerialNumberLength;
/**Offset to start of creator string from start of this block */
uint32_t mediaBarcodeOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t mediaBarcodeLength;
/**Offset to start of creator string from start of this block */
uint32_t mediaPartNumberOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t mediaPartNumberLength;
/**Offset to start of creator string from start of this block */
uint32_t driveManufacturerOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t driveManufacturerLength;
/**Offset to start of creator string from start of this block */
uint32_t driveModelOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t driveModelLength;
/**Offset to start of creator string from start of this block */
uint32_t driveSerialNumberOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t driveSerialNumberLength;
/**Offset to start of creator string from start of this block */
uint32_t driveFirmwareRevisionOffset;
/**Length in uint8_ts of the null-terminated UTF-16LE creator string */
uint32_t driveFirmwareRevisionLength;
} MetadataBlockHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The metadata table identifier, always 'META'
|uint32_t
|4 bytes
|blockSize
|The size of this block including all of its data.
|int32_t
|4 bytes
|mediaSequence
|The number of heads.
|int32_t
|4 bytes
|lastMediaSequence
|The number of sectors per track.
|uint32_t
|4 bytes
|creatorOffset
|Offset to start of creator string from start of this block.
|uint32_t
|4 bytes
|creatorLength
|Length in bytes of the creator string.
|uint32_t
|4 bytes
|commentsOffset
|Offset to start of comments string from start of this block.
|uint32_t
|4 bytes
|commentsLength
|Length in bytes of the comments string.
|uint32_t
|4 bytes
|mediaTitleOffset
|Offset to start of media title string from start of this block.
|uint32_t
|4 bytes
|mediaTitleLength
|Length in bytes of the media title string.
|uint32_t
|4 bytes
|mediaManufacturerOffset
|Offset to start of media manufacturer string from start of this block.
|uint32_t
|4 bytes
|mediaManufacturerLength
|Length in bytes of the media manufacturer string.
|uint32_t
|4 bytes
|mediaModelOffset
|Offset to start of media model string from start of this block.
|uint32_t
|4 bytes
|mediaModelLength
|Length in bytes of the media model string.
|uint32_t
|4 bytes
|mediaSerialNumberOffset
|Offset to start of media serial number string from start of this block.
|uint32_t
|4 bytes
|mediaSerialNumberLength
|Length in bytes of the media serial number string.
|uint32_t
|4 bytes
|mediaBarcodeOffset
|Offset to start of media barcode string from start of this block.
|uint32_t
|4 bytes
|mediaBarcodeLength
|Length in bytes of the media barcode string.
|uint32_t
|4 bytes
|mediaPartNumberOffset
|Offset to start of media part number string from start of this block.
|uint32_t
|4 bytes
|mediaPartNumberLength
|Length in bytes of the media part number string.
|uint32_t
|4 bytes
|driveManufacturerOffset
|Offset to start of drive manufacturer string from start of this block.
|uint32_t
|4 bytes
|driveManufacturerLength
|Length in bytes of the drive manufacturer string.
|uint32_t
|4 bytes
|driveModelOffset
|Offset to start of drive model string from start of this block.
|uint32_t
|4 bytes
|driveModelLength
|Length in bytes of the drive model string.
|uint32_t
|4 bytes
|driveSerialNumberOffset
|Offset to start of drive serial number string from start of this block.
|uint32_t
|4 bytes
|driveSerialNumberLength
|Length in bytes of the drive serial number string.
|uint32_t
|4 bytes
|driveFirmwareRevisionOffset
|Offset to start of drive firmware revision string from start of this block.
|uint32_t
|4 bytes
|driveFirmwareRevisionLength
|Length in bytes of the drive firmware revision string.
|===

View File

@@ -0,0 +1,58 @@
=== Parent File Block (`PRNT`)
The parent file block provides metadata required to locate the image file from which the current image is derived.
Its primary purpose is to enable hierarchical composition, where non-written sectors in the current image are transparently resolved by referencing their counterparts in the parent image.
All sectors marked as unwritten must be read from the associated parent image, ensuring data completeness and consistency across derivative images.
==== Structure Definition
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The parent block identifier, always `PRNT`
|uint32_t
|4 bytes
|length
|The length in bytes of the data following this header.
|GUID
|16 bytes
|parentId
|The unique identifier of the parent.
|uint16_t
|2 bytes
|parentClueLength
|The size in bytes of the clue string following this field.
|String
|N bytes
|parentClue
|A clue, be it a path, filename, UNC, etc., to find the parent. If not valid or not found implementations shall try the directory where the image resides first and the current working directory if not found there.
|===
This block contains metadata essential for locating the corresponding parent image.
All sectors flagged as undumped in the current image must be retrieved from the parent image to ensure completeness.
The parent may also store supplementary blocks—such as media tags or metadata—that are not duplicated in the current image.
However, any correctly defined data blocks or deduplication tables present in this image will override those found in the parent.
A clue field assists implementations in locating the parent, while a unique parent ID confirms its validity.
If the clue fails to resolve the location, the implementation must first scan the directory containing the current image for files with a matching AaruFormat header and expected ID.
If unsuccessful, the fallback should be the current working directory.
If this block is present but the parent image cannot be located, the implementation must terminate the open operation, as reconstructing the complete media content depends on the parents data.

View File

@@ -0,0 +1,54 @@
=== Snapshot block (`SNAP`)
The snapshot block holds a list of historical indexes, representing earlier versions of the media captured within the image.
This feature enables users to manually preserve a specific media state, allowing reversion to previous versions or comparison between multiple data capture attempts.
The active index used by the image must always be the one referenced by the image header.
If any snapshot block references the current index, it must be ignored and treated as non-existent during image save operations.
Generation 0 refers to the initial image state, where only a single index—pointed to by the header—is present.
The latest image header should reference all available snapshots, unless individual blocks have been explicitly discarded by the user.
Once discarded, such blocks become orphaned and are no longer reachable within the image structure.
During conversion from AaruFormat, only one snapshot (or the latest index) should be included, based on user selection.
==== Structure Definition
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The snapshot block identifier, always 'SNAP'
|uint32_t
|4 bytes
|length
|The length in bytes of the data following this header.
|uint16_t
|2 bytes
|generation
|The generation, starting from 1, of this snapshot. Every snapshot gets a generation incremented in one from the lastest recorded one.
|int64_t
|8 bytes
|creationTime
|Creation time of this snapshot.
|uint64_t
|8 bytes
|index
|Offset in bytes where the index marked by this snapshot resides.
|===

View File

@@ -0,0 +1,75 @@
=== Tape File Block ('TFLE')
Lists all tape files.
Tape files are separations written to media, usually digital tapes, and are marked by filemarks.
==== Structure Definition
[source,c]
#define TAPE_FILE_MAGIC 0x454C4654
/* TODO */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The tape file block identifier, always `TFLE`
|uint16_t
|2 bytes
|entries
|The number of entries following this header
|uint32_t
|4 bytes
|length
|The length in bytes of the data following this header.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the data following this header
|===
==== Tape file entries
[source,c]
/* TODO */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32
|4 bytes
|file
|File number.
|uint8
|1 byte
|partition
|Partition number this file belongs to.
|uint64
|8 bytes
|firstBlock
|First block number, inclusive, of the file.
|uint64
|8 bytes
|lastBlock
|Last block number, inclusive, of the file.
|===

View File

@@ -0,0 +1,72 @@
=== Tape Partition Block (`TPBT`)
This block lists all tape partitions.
Tape partitions are separations written to media.
They are used to distinguish two sets of related data that are distant enough to warrant separation but still belong on the same tape.
A well-known example is the LTFS filesystem.
==== Structure Definition
[source,c]
#define TAPE_PARTITION_MAGIC 0x54504254
/* TODO */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The tape partition block identifier, always `TPBT`
|uint16_t
|2 bytes
|entries
|The number of entries following this header
|uint32_t
|4 bytes
|length
|The length in bytes of the data following this header.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the data following this header
|===
==== Tape partition entries
[source,c]
/* TODO */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint8_t
|1 byte
|number
|Partition number.
|uint64_t
|8 bytes
|firstBlock
|First block number, inclusive, of the partition.
|uint64_t
|8 bytes
|lastBlock
|Last block number, inclusive, of the partition.
|===

View File

@@ -0,0 +1,96 @@
=== Track Layout Block (`TKLY`)
The `TKLY` block defines the mapping between physical tracks and logical sectors, as referenced by the deduplication table.
Magnetic media such as floppies and hard disks may exhibit complex physical layouts that do not cleanly translate to logical block addresses.
This block enables accurate sector location resolution by maintaining explicit layout information.
Each `TKLY` block corresponds to a unique combination of (sub)track and head, and is followed by a series of sector mapping entries.
If known, sectors should be listed in physical order to preserve potential interleaving.
Sector numbers may be duplicated.
NOTE: This block must not be used for optical or other logically addressable block-based media.
If a referenced LBA is marked as undumped and a `FLUX` block is present, it indicates the corresponding sector could not be decoded (e.g., damaged or unreadable), and should be considered undumped unless flags state otherwise.
If a `FLUX` block exists for a given (sub)track but no corresponding `TKLY` block is present, the entire (sub)track is considered not decoded.
==== Structure Definition
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The flux data block identifier, always `TKLY`
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the data following this header
|uint32_t
|4 bytes
|head
|Head the block corresponds to
|uint16_t
|2 bytes
|track
|Track the block corresponds to
|uint8_t
|1 byte
|subtrack
|Substep of a track the data corresponds to
|uint16_t
|2 bytes
|sectors
|Number of sectors in this (sub)track, and therefore, number of entries following this header
|uint64_t
|8 bytes
|flux
|Pointer to the flux data block that contains the flux information for this (sub)track
|uint64_t
|8 bytes
|bitstream
|Pointer to the bitstream data block that contains the flux information for this (sub)track
|===
==== Sector Mapping Entries
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint16_t
|2 bytes
|sector
|Sector number as present in the appropriate media sector header or equivalent
|uint64_t
|8 bytes
|block
|Position in the deduplication table this sector and its flags is stored
|===

View File

@@ -0,0 +1,81 @@
=== The tracks block (`TRKS`)
The tracks block holds a structured list of track entries, typically aligned with the layout specified in the table of contents or a similar indexing schema.
This format is common in optical media such as CDs, DVDs, and related disc-based formats.
==== Structure Definition
[source,c]
#define TRACKS_MAGIC 0x534B5254
/**Contains list of optical disc tracks */
typedef struct TracksHeader
{
/**Identifier, <see cref="BlockType.TracksBlock" /> */
uint32_t identifier;
/**How many entries follow this header */
uint16_t entries;
/**CRC64-ECMA of the block */
uint64_t crc64;
} TracksHeader;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type|Size|Name|Description
|uint32_t|4 bytes|identifier|The tracks block identifier, always `TRKS`
|uint16_t|2 bytes|entries|The number of entries following this header
|uint64_t|8 bytes|crc64|CRC64-ECMA checksum of the entries following this header
|===
==== Track entries
[source,c]
/**Optical disc track */
typedef struct TrackEntry
{
/**Track sequence */
uint8_t sequence;
/**Track type */
uint8_t type;
/**Track starting LBA */
int64_t start;
/**Track last LBA */
int64_t end;
/**Track pregap in sectors */
int64_t pregap;
/**Track session */
uint8_t session;
/**Track's ISRC in ASCII */
uint8_t isrc[13];
/**Track flags */
uint8_t flags;
} TrackEntry;
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type|Size|Name|Description
|uint8|1 byte|sequence|Track number.
|uint8|1 byte|type|Track type (see table below).
|int64|8 bytes|start|Track starting LBA (including pregap).
|int64|8 bytes|end|Track ending LBA.
|int64|8 bytes|pregap|Size of tracks pregap in sectors.
|uint8|1 byte|session|Session the track belongs to.
|StringA|13 bytes|isrc|Tracks ISRC in ASCIIZ.
|uint8|1 byte|flags|Track flags as indicated in TOC if applicable.
|===
==== Track Types
[cols="2,1,8",options="header"]
|===
|Type|Value|Description
|Audio|0|All sectors in the track contain audio as defined by the Red Book.
|Data|1|All sectors in the track contain user data that is not defined by any of the following types.
|CdMode1|2|All sectors in the track contain user data according to MODE 1 as defined by the Yellow Book.
|CdMode2Formless|3|All sectors in the track contain user data according to MODE 2 as defined by the Yellow and Green Books. Not all sectors belong to the same Form.
|CdMode2Form1|4|All sectors in the track contain user data according to MODE 2 Form 1 as defined by the Yellow and Green Books. All sectors belong to the same Form.
|CdMode2Form2|5|All sectors in the track contain user data according to MODE 2 Form 2 as defined by the Yellow and Green Books. All sectors belong to the same Form.
|===

View File

@@ -0,0 +1,85 @@
=== The twin sector table (`TWTB`)
This table enumerates hardware sectors that share an identical sector number.
Such sectors are referred to as “twin sectors,” although the grouping may consist of more than two instances.
The associated pointer is resolved following the same logic applied in a last-level deduplication table.
[source,c]
/* Undefined */
==== Field Descriptions
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|4 bytes
|identifier
|The twin sector table identifier, always `TWTB`
|uint8_t
|1 byte
|alignment
|Shift of alignment of all blocks in the image. This must be the same in all deduplication tables and subtables.
|uint8_t
|1 byte
|shift
|The shift used to calculate the position of a sector in a data block pointed by this table, or how many sectors are pointed by the next level.
|uint64_t
|8 bytes
|entries
|How many pointers follow this header.
|uint32_t
|4 bytes
|length
|The size in bytes of the table block.
|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the decompressed table.
|===
==== Twin sector entries
[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description
|uint32_t
|8 bytes
|pointer
|Pointer to the sector.
|===
==== Pointer-Based Data Block Resolution
To determine the corresponding data block:
. Right-shift the pointer value using the specified `shift` parameter.
. Multiply the result by the `alignment` value.
. The remainder from this operation indicates the sector's offset within the target data block.
Each data block contains a fixed number of bytes per sector, which remains constant across blocks.
This invariant size allows for more efficient storage of pointer values.
===== Example
Given the following parameters:
* Pointer Value: `0x8003`
* Shift Value: `5`
* Alignment: `9`
The data block is located at byte offset `524288`.
The sector referenced by the pointer is the **third entry** within this block.