=== Flux Data Block (`FLUX`)

This block contains metadata for all flux captures in the image.
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.

The flux capture system uses two block types:
* `FluxDataBlock` (`FLUX` / `0x58554C46`): Contains metadata entries that describe all flux captures in the image
* `DataStreamPayloadBlock` (`DSPL` / `0x4C505344`): Contains the actual flux data payload (data and index buffers) for individual captures. This is a generic block type that can also be used for other data streams.

Each flux capture has one entry in the `FluxDataBlock` and one corresponding `DataStreamPayloadBlock` containing its data.
The `FluxEntry` structure in the data block contains a `payloadOffset` field that points to the file offset where the corresponding `DataStreamPayloadBlock` is stored. The offset is stored divided by the block alignment (as indicated by `blockAlignmentShift` in the `FluxHeader`), consistent with DDT table offset storage.

==== Structure Definition

[source,c]
#define FLUX_DATA_MAGIC 0x58554C46
/** Flux data block header */
typedef struct FluxHeader
{
    uint32_t identifier;          ///< Block identifier, must be BlockType::FluxDataBlock (0x58554C46).
    uint16_t entries;             ///< Number of FluxEntry records following this header.
    uint8_t  blockAlignmentShift; ///< Block alignment shift: 2^blockAlignmentShift = block alignment boundary in bytes.
    uint64_t crc64;               ///< CRC64-ECMA checksum of the FluxEntry array (header excluded).
} FluxHeader;

==== 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` (`0x58554C46`)

|uint16_t
|2 bytes
|entries
|The number of flux entry records following this header

|uint8_t
|1 byte
|blockAlignmentShift
|Block alignment shift: 2^blockAlignmentShift = block alignment boundary in bytes. Used to decode payloadOffset values in FluxEntry structures, which are stored divided by this alignment. Stored in the header to make the block self-contained, similar to DDT headers.

|uint64_t
|8 bytes
|crc64
|The CRC64-ECMA checksum of the FluxEntry array following this header
|===

==== Flux entries

[source,c]
/** Flux capture entry, describes one flux capture in the image */
typedef struct FluxEntry
{
    uint32_t head;          ///< Head number the capture corresponds to.
    uint16_t track;          ///< Track number the capture corresponds to.
    uint8_t  subtrack;      ///< Subtrack number the capture corresponds to.
    uint32_t captureIndex;  ///< Capture index, allows multiple captures for the same location.
    uint64_t indexResolution; ///< Resolution in picoseconds for the index stream.
    uint64_t dataResolution;  ///< Resolution in picoseconds for the data stream.
    uint64_t indexOffset;      ///< Byte offset within the payload where the index buffer starts.
    uint64_t payloadOffset;   ///< File offset where the DataStreamPayloadBlock for this capture is stored.
} FluxEntry;

==== Field Descriptions

[cols="2,2,2,6",options="header"]
|===
|Type
|Size
|Name
|Description

|uint32_t
|4 bytes
|head
|Head number the flux capture corresponds to.

|uint16_t
|2 bytes
|track
|Track number the flux capture corresponds to.

|uint8_t
|1 byte
|subtrack
|Subtrack number the flux capture corresponds to.

|uint32_t
|4 bytes
|captureIndex
|Capture index, allows multiple captures for the same head/track/subtrack combination.

|uint64_t
|8 bytes
|indexResolution
|Resolution in picoseconds at which the index stream was sampled.

|uint64_t
|8 bytes
|dataResolution
|Resolution in picoseconds at which the data stream was sampled.

|uint64_t
|8 bytes
|indexOffset
|Byte offset within the payload block where the index buffer starts (equals data_length).

|uint64_t
|8 bytes
|payloadOffset
|Block-aligned file offset where the DataStreamPayloadBlock containing this capture's data is stored, divided by (1 << blockAlignmentShift). To get the absolute file offset, multiply by (1 << blockAlignmentShift) using the blockAlignmentShift value from FluxHeader. This storage method is consistent with DDT table offset storage.
|===