From c412030a8bd65d9891e246c921e57378ebef8079 Mon Sep 17 00:00:00 2001 From: Rebecca Wallander Date: Thu, 1 Jan 2026 12:51:26 +0100 Subject: [PATCH] Use block alignment offset instead of absolute offset --- docs/spec/blocks/flux.adoc | 16 +++++++++++----- include/aaruformat/structs/flux.h | 24 +++++++++++++++++------- src/blocks/flux.c | 16 ++++++++++++---- src/close.c | 20 ++++++++++++-------- templates/aaruformat.hexpat | 1 + 5 files changed, 53 insertions(+), 24 deletions(-) diff --git a/docs/spec/blocks/flux.adoc b/docs/spec/blocks/flux.adoc index 8d0aab3..de9bfdf 100644 --- a/docs/spec/blocks/flux.adoc +++ b/docs/spec/blocks/flux.adoc @@ -19,7 +19,7 @@ The flux capture system uses two block types: * `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 `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 @@ -28,9 +28,10 @@ The `FluxEntry` structure in the data block contains a `payloadOffset` field tha /** 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. - uint64_t crc64; ///< CRC64-ECMA checksum of the FluxEntry array (header excluded). + 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 @@ -52,6 +53,11 @@ typedef struct FluxHeader |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 @@ -121,5 +127,5 @@ typedef struct FluxEntry |uint64_t |8 bytes |payloadOffset -|File offset where the DataStreamPayloadBlock containing this capture's data is stored. +|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. |=== \ No newline at end of file diff --git a/include/aaruformat/structs/flux.h b/include/aaruformat/structs/flux.h index f8f8f08..dff2fa7 100644 --- a/include/aaruformat/structs/flux.h +++ b/include/aaruformat/structs/flux.h @@ -103,14 +103,22 @@ * data integrity. The identifier field must match BlockType::FluxDataBlock * (0x58554C46, "FLUX" in ASCII). * + * The blockAlignmentShift field stores the block alignment shift value used to + * decode the payloadOffset values in FluxEntry structures. This makes the block + * self-contained, similar to DDT headers, allowing correct decoding of offsets + * without requiring access to the main image header. + * * @note Only one FluxDataBlock is allowed per image. * @note The entries field is limited to UINT16_MAX (65535) captures per image. + * @note The blockAlignmentShift field is stored in the header to support reliable + * decoding of payloadOffset values, which are stored divided by (1 << blockAlignmentShift). */ typedef struct FluxHeader { - uint32_t identifier; ///< Block identifier, must be BlockType::FluxDataBlock (0x58554C46, "FLUX"). - uint16_t entries; ///< Number of FluxEntry records following this header. Maximum value: 65535. - uint64_t crc64; ///< CRC64-ECMA checksum of the FluxEntry array (header excluded). + uint32_t identifier; ///< Block identifier, must be BlockType::FluxDataBlock (0x58554C46, "FLUX"). + uint16_t entries; ///< Number of FluxEntry records following this header. Maximum value: 65535. + 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; /** @@ -128,9 +136,11 @@ typedef struct FluxHeader * * **Payload Access:** * The payloadOffset field points to the file offset where the corresponding - * DataStreamPayloadBlock is stored. The indexOffset field indicates where the index - * buffer starts within the payload (the payload is stored as [data_buffer][index_buffer] - * concatenated). + * DataStreamPayloadBlock is stored. The offset is stored divided by the block alignment + * (blockAlignmentShift from FluxHeader), consistent with DDT table offset storage. + * To convert to an absolute file offset, multiply by (1 << blockAlignmentShift). + * The indexOffset field indicates where the index buffer starts within the payload + * (the payload is stored as [data_buffer][index_buffer] concatenated). * * **Resolution:** * Both indexResolution and dataResolution are specified in picoseconds, indicating @@ -151,7 +161,7 @@ typedef struct FluxEntry uint64_t indexResolution; ///< Resolution in picoseconds at which the index stream was sampled. uint64_t dataResolution; ///< Resolution in picoseconds at which the data stream was sampled. uint64_t indexOffset; ///< Byte offset within the payload where the index buffer starts (equals data_length). - uint64_t payloadOffset; ///< File offset where the DataStreamPayloadBlock containing this capture's data is stored. + uint64_t payloadOffset; ///< Block-aligned file offset where the DataStreamPayloadBlock containing this capture's data is stored, divided by (1 << blockAlignmentShift). To get the absolute offset, multiply by (1 << blockAlignmentShift) from FluxHeader. } FluxEntry; /** diff --git a/src/blocks/flux.c b/src/blocks/flux.c index 23470db..c808efc 100644 --- a/src/blocks/flux.c +++ b/src/blocks/flux.c @@ -1073,9 +1073,10 @@ static int32_t extract_flux_data_buffers(const FluxEntry *flux_entry, const uint * This function retrieves the actual flux data and index buffers for a specific * flux capture identified by its head, track, subtrack, and capture_index. The * function locates the corresponding FluxEntry in the flux_entries array (using - * the lookup map for efficiency), seeks to the DataStreamPayloadBlock at the specified - * payloadOffset, reads and decompresses the payload, validates CRC64 checksums, - * and extracts the data and index buffers. + * the lookup map for efficiency), converts the payloadOffset (stored divided by block alignment) + * to an absolute file offset using blockAlignmentShift from FluxHeader, seeks to the + * DataStreamPayloadBlock at the specified offset, reads and decompresses the payload, + * validates CRC64 checksums, and extracts the data and index buffers. * * The function supports both uncompressed and LZMA-compressed payload blocks. * CRC64 validation is performed on both the compressed and uncompressed data. @@ -1188,8 +1189,15 @@ AARU_EXPORT int32_t AARU_CALL aaruf_read_flux_capture(void *context, uint32_t he flux_entry->head, flux_entry->track, flux_entry->subtrack, flux_entry->captureIndex, flux_entry->payloadOffset); + // Get block alignment shift from FluxHeader + uint8_t block_alignment_shift = ctx->flux_data_header.blockAlignmentShift; + + // Convert payloadOffset from block-aligned units to absolute file offset + // payloadOffset is stored divided by (1 << blockAlignmentShift), consistent with DDT + uint64_t absolute_payload_offset = flux_entry->payloadOffset << block_alignment_shift; + DataStreamPayloadHeader payload_header; - int32_t res = read_flux_payload_header(ctx, flux_entry->payloadOffset, &payload_header); + int32_t res = read_flux_payload_header(ctx, absolute_payload_offset, &payload_header); if(res != AARUF_STATUS_OK) { TRACE("Exiting aaruf_read_flux_capture() = %d\n", res); diff --git a/src/close.c b/src/close.c index 5d15f30..9b6165c 100644 --- a/src/close.c +++ b/src/close.c @@ -4268,7 +4268,8 @@ static void write_aaru_json_block(aaruformat_context *ctx) * - head, track, subtrack, captureIndex: Identifiers from the record * - dataResolution, indexResolution: Timing resolution metadata * - indexOffset: Offset within payload where index buffer starts (equals data_length) - * - payloadOffset: File offset where this payload block was written + * - payloadOffset: Block-aligned file offset divided by (1 << blockAlignmentShift), + * consistent with DDT offset storage. Multiply by (1 << blockAlignmentShift) to get absolute offset. * * This metadata is later written to the FluxDataBlock to enable efficient lookup * of flux captures by their identifiers. @@ -4338,9 +4339,11 @@ static void write_aaru_json_block(aaruformat_context *ctx) * If compression doesn't reduce size, the raw data is written instead. This * prevents wasting space on incompressible flux data. * - * @note The payloadOffset stored in the FluxEntry enables direct seeking to the payload - * during reads without requiring a full index scan. This is critical for efficient - * random access to flux captures. + * @note The payloadOffset stored in the FluxEntry is divided by block alignment + * (blockAlignmentShift), consistent with DDT table offset storage. It enables direct + * seeking to the payload during reads without requiring a full index scan. This is + * critical for efficient random access to flux captures. The blockAlignmentShift + * value is stored in the FluxHeader to allow correct decoding. * * @note LZMA properties are written immediately after the header when compression is * enabled. The properties are included in cmpLength but not in the separate @@ -4505,7 +4508,7 @@ static int32_t write_flux_capture_payload(aaruformat_context *ctx, FluxCaptureRe entry->dataResolution = record->entry.dataResolution; entry->indexResolution = record->entry.indexResolution; entry->indexOffset = record->data_length; - entry->payloadOffset = payload_position; + entry->payloadOffset = payload_position >> ctx->user_data_ddt_header.blockAlignmentShift; record->entry = *entry; @@ -4668,7 +4671,7 @@ static int32_t write_flux_capture_payload(aaruformat_context *ctx, FluxCaptureRe * **Format Considerations:** * - The FluxDataBlock must be written after all DataStreamPayloadBlock entries * - The entry count in FluxHeader must match the number of payload blocks written - * - Each FluxEntry's payloadOffset must point to a valid DataStreamPayloadBlock + * - Each FluxEntry's payloadOffset must point to a valid DataStreamPayloadBlock (stored divided by block alignment) * - The CRC64 in FluxHeader enables verification of entry array integrity * - Multiple captures per track are supported via captureIndex differentiation * @@ -4796,8 +4799,9 @@ static int32_t write_flux_blocks(aaruformat_context *ctx) } FluxHeader header = {0}; - header.identifier = FluxDataBlock; - header.entries = (uint16_t)capture_count; + header.identifier = FluxDataBlock; + header.entries = (uint16_t)capture_count; + header.blockAlignmentShift = ctx->user_data_ddt_header.blockAlignmentShift; header.crc64 = capture_count == 0 ? 0 : aaruf_crc64_data((const uint8_t *)entries, capture_count * sizeof(FluxEntry)); diff --git a/templates/aaruformat.hexpat b/templates/aaruformat.hexpat index adffe1d..2e9a73d 100644 --- a/templates/aaruformat.hexpat +++ b/templates/aaruformat.hexpat @@ -1152,6 +1152,7 @@ struct FluxHeader { BlockType identifier; u16 entries; + u8 blockAlignmentShift; u64 crc64; };