Loading...
Searching...
No Matches
optical.c File Reference
`#include <inttypes.h>`
`#include <stdint.h>`
`#include <stdio.h>`
`#include <stdlib.h>`
`#include <string.h>`
`#include "aaruformat.h"`
`#include "log.h"`

Go to the source code of this file.

## Functions

void | process_tracks_block (aaruformat_context *ctx, const IndexEntry *entry)
| Parse and integrate a Tracks block from the image stream into the context.
int32_t | aaruf_get_tracks (const void *context, uint8_t *buffer, size_t *length)
| Retrieve the array of track descriptors contained in an opened AaruFormat image.
int32_t | aaruf_set_tracks (void *context, TrackEntry *tracks, const int count)
| Replace (or clear) the in-memory track table for an AaruFormat image context.

## Function Documentation

## aaruf_get_tracks()

int32_t aaruf_get_tracks | ( | const void * | context,
|  | uint8_t * | buffer,
|  | size_t * | length )

Retrieve the array of track descriptors contained in an opened AaruFormat image.

Provides the caller with a contiguous array of all track entries found in the image. The function follows a two-step usage pattern allowing callers to query the required buffer size before performing the actual copy.

Usage pattern:

- First call with buffer == NULL (or *length smaller than required). The function sets *length to the required size and returns AARUF_ERROR_BUFFER_TOO_SMALL.
- Allocate a buffer of at least *length bytes and call again. On success, the function copies all TrackEntry structures and returns AARUF_STATUS_OK with *length set to the bytes copied.

The returned data is a raw copy of internal TrackEntry structures (host endianness). The caller does not assume ownership of internal memory; only the caller-provided buffer should be freed by the caller.

Preconditions (

Precondition
  ):
  context is a valid pointer to an aaruformatContext previously returned by an open function.
  context->magic == AARU_MAGIC.
  process_tracks_block() has run (implicitly done during image open) populating trackEntries.

Thread safety:

- Read-only access; safe for concurrent calls on different contexts.
- Concurrent calls on the same context are safe only if no other thread is modifying/destroying it.

Buffer sizing logic:

- required_length = ctx->tracksHeader.entries * sizeof(TrackEntry)
- If buffer == NULL OR *length < required_length => *length updated, return AARUF_ERROR_BUFFER_TOO_SMALL.
- On success *length == required_length.

Error strategy:

- Validation failures: return specific error codes and log through FATAL()/TRACE().
- No partial copies are performed.

Parameters

  context | Opaque pointer that MUST point to a valid aaruformatContext.
  buffer | Destination buffer for a copy of all TrackEntry structures, or NULL to query size.
  length | In/Out: On entry capacity of buffer (ignored if buffer == NULL). On return required or copied size in bytes. Must not be NULL.

Returns
  int32_t API status code.

Return values

  AARUF_STATUS_OK | Success; buffer filled.
  AARUF_ERROR_NOT_AARUFORMAT | context is NULL or not a valid libaaruformat context.
  AARUF_ERROR_TRACK_NOT_FOUND | No tracks present (entries == 0 or internal array NULL).
  AARUF_ERROR_BUFFER_TOO_SMALL | Sizing query / provided buffer insufficient; *length updated.

Warning
  Passing an invalid context yields an error; no data is written to buffer.
  The function never performs partial copies.

Note
  Order of TrackEntry elements matches on-disk order.
  Caller may further filter (e.g., data vs audio) after retrieval.

Since
  1.0

Usage example (conceptual):

1. Open an image obtaining a valid aaruformatContext pointer.
2. Invoke aaruf_get_tracks(ctx, NULL, &size) to query required buffer size (expect AARUF_ERROR_BUFFER_TOO_SMALL).
3. Allocate a buffer of "size" bytes.
4. Invoke aaruf_get_tracks(ctx, buffer, &size) again; on AARUF_STATUS_OK iterate over (size / sizeof(TrackEntry)) entries.
5. Free the buffer and close the image when done.

Definition at line 281 of file optical.c.

References AARU_CALL, AARU_EXPORT, AARU_MAGIC, AARUF_ERROR_BUFFER_TOO_SMALL, AARUF_ERROR_NOT_AARUFORMAT, AARUF_ERROR_TRACK_NOT_FOUND, AARUF_STATUS_OK, TracksHeader::entries, FATAL, aaruformat_context::magic, TRACE, aaruformat_context::track_entries, and aaruformat_context::tracks_header.

## aaruf_set_tracks()

int32_t aaruf_set_tracks | ( | void * | context,
|  | TrackEntry * | tracks,
|  | const int | count )

Replace (or clear) the in-memory track table for an AaruFormat image context.

Copies an array of caller-provided TrackEntry structures into the internal context, replacing any previously stored track metadata. A CRC64 is recomputed over the new table and stored in the associated TracksHeader. Passing a count of 0 clears existing track information.

Typical usage:

- Prepare an array of TrackEntry structures describing each track (filled by the caller).
- Call aaruf_set_tracks() with the array and the track count to load them into the context.
- Subsequently the table can be retrieved with aaruf_get_tracks().

Memory ownership:

- The function allocates (or frees when clearing) internal storage sized to (count * sizeof(TrackEntry)).
- The caller retains ownership of the input array (if any) and may free or reuse it after the call.

Validation performed:

- `context` must be non-NULL and reference aaruformatContext with magic == AARU_MAGIC.
- `tracks` must be non-NULL when `count` > 0.
- `count` must be >= 0. (Negative values produce AARUF_ERROR_INVALID_TRACK_FORMAT.)
- (Implementation detail) count is truncated to uint16_t for header storage; values > UINT16_MAX will silently wrap. Callers should ensure count <= 65535. This behavior may change in a future version.

Concurrency & thread-safety:

- Not thread-safe. Mutates shared context state. External synchronization is required if multiple threads access the same context.

Side effects:

- Frees any existing internal track table before allocating the new one.
- Updates ctx->tracksHeader.identifier, entries, crc64.
- When clearing (count == 0) sets header to zero and frees internal table.

Error handling & atomicity:

- On allocation failure the previous track table is already freed (non-atomic replace) and the header is zeroed (no partial new state left). Caller must repopulate.
- No partial copies: either all tracks are stored or none.

Parameters

  context | Opaque pointer that MUST point to a valid aaruformatContext returned by an open/create call.
  tracks | Pointer to an array of TrackEntry structures to copy. Must not be NULL if count > 0. Ignored (may be NULL) when count == 0.
  count | Number of TrackEntry elements in `tracks`. If 0, existing tracks are cleared. Must be >= 0 and (recommended) <= UINT16_MAX.

Returns
  int32_t API status code indicating success or the nature of the failure.

Return values

  AARUF_STATUS_OK | Success (tracks replaced or cleared).
  AARUF_ERROR_NOT_AARUFORMAT | `context` is NULL or not a recognized libaaruformat context.
  AARUF_ERROR_INVALID_TRACK_FORMAT | Invalid input (tracks NULL with count > 0, or count < 0).
  AARUF_ERROR_NOT_ENOUGH_MEMORY | Memory allocation failed while copying tracks.

Warning
  Not thread-safe. Do not invoke concurrently with readers/writers of the same context.

Note
  After success, aaruf_get_tracks() can be used to read back the stored table.

See also
  aaruf_get_tracks()

Since
  1.0

Usage example (conceptual):

1. Prepare an array of TrackEntry structures (N elements) and fill the fields.
2. Call aaruf_set_tracks(ctx, array, N) to store them; check for AARUF_STATUS_OK.
3. To clear all tracks later call aaruf_set_tracks(ctx, NULL, 0).
4. Use aaruf_get_tracks() afterwards to retrieve them if needed.

Definition at line 392 of file optical.c.

References AARU_CALL, AARU_EXPORT, AARU_MAGIC, aaruf_crc64_data(), AARUF_ERROR_INVALID_TRACK_FORMAT, AARUF_ERROR_NOT_AARUFORMAT, AARUF_ERROR_NOT_ENOUGH_MEMORY, AARUF_STATUS_OK, TracksHeader::crc64, aaruformat_context::data_tracks, aaruformat_context::dirty_tracks_block, TracksHeader::entries, FATAL, ImageInfo::HasPartitions, ImageInfo::HasSessions, TracksHeader::identifier, aaruformat_context::image_info, aaruformat_context::magic, aaruformat_context::number_of_data_tracks, TrackEntry::sequence, TRACE, aaruformat_context::track_entries, aaruformat_context::tracks_header, and TracksBlock.

## process_tracks_block()

void process_tracks_block | ( | aaruformat_context * | ctx,
|  | const IndexEntry * | entry )

Parse and integrate a Tracks block from the image stream into the context.

This function seeks to the byte offset specified by the supplied `entry`, reads a TracksHeader followed by the declared number of TrackEntry records, validates the block through its CRC64, and populates multiple fields in the provided `ctx:`

- ctx->tracksHeader (identifier, entries, crc64)
- ctx->trackEntries (raw array with ALL tracks in on-disk order)
- ctx->dataTracks (array filtered to data track sequences in [1..99])
- ctx->numberOfDataTracks
- ctx->imageInfo.ImageSize (incremented by sizeof(TrackEntry) * entries)
- ctx->imageInfo.HasPartitions / HasSessions (both set true unconditionally on success path before filtering)

It also performs a legacy endian correction of the computed CRC for images whose major version is <= AARUF_VERSION_V1 (historical writer quirk).

The function is intended for internal library use during image opening / indexing and is NOT part of the stable public API (no versioning guarantees). Callers outside the library should use the higher-level image open helpers that trigger this parsing implicitly.

Error & early-return behavior (no exception mechanism, all via logging + early return):

- NULL `ctx` or NULL ctx->imageStream: Logs FATAL and returns immediately; context left untouched.
- Seek failure: FATAL + return; context left untouched.
- TracksHeader read short: tracksHeader zeroed, TRACE logged, return.
- Identifier mismatch: tracksHeader zeroed, TRACE logged, return.
- Allocation failure for trackEntries: tracksHeader zeroed, FATAL logged, return.
- Short read of TrackEntry array: tracksHeader zeroed, allocated trackEntries freed, FATAL logged, return.
- CRC mismatch: TRACE logged and return; (NOTE: at this point trackEntries remain allocated and tracksHeader retains the just-read values, but caller receives no explicit status.)

Memory management:

- Allocates ctx->trackEntries with malloc() sized to entries * sizeof(TrackEntry).
- Allocates ctx->dataTracks only if at least one filtered data track is found; otherwise sets it to NULL.
- On certain failure paths (short reads) allocated memory is freed; on CRC mismatch memory is kept.
- Pre-existing ctx->trackEntries or ctx->dataTracks are NOT freed before overwriting pointers, so repeated calls without prior cleanup will leak memory. The function is therefore expected to be called exactly once per context lifetime. This constraint should be observed by library code.

Filtering rule for ctx->dataTracks:

- Any TrackEntry with sequence in inclusive range [1, 99] is considered a data track (historical convention in format) and copied into ctx->dataTracks preserving original order.

Thread safety:

- Not thread-safe: mutates shared state in `ctx` without synchronization.
- Must not be called concurrently with readers/writers referencing the same context.

Preconditions (

Precondition
  ):
  - `ctx` != NULL
  - `ctx->imageStream` is a valid FILE* opened for reading at least up to the block region.
  - `entry` != NULL and entry->offset points to the start of a well-formed Tracks block.

Postconditions (

Postcondition
  ) on success (CRC valid):
  - ctx->tracksHeader.identifier == TracksBlock
  - ctx->tracksHeader.entries > 0 implies ctx->trackEntries != NULL
  - ctx->dataTracks != NULL iff numberOfDataTracks > 0
  - numberOfDataTracks <= tracksHeader.entries
  - imageInfo flags (HasPartitions, HasSessions) set true

Limitations / Caveats:

- No explicit status code: callers infer success by inspecting ctx->tracksHeader.entries and presence of ctx->trackEntries after invocation.
- In case of CRC mismatch trackEntries are retained though not guaranteed trustworthy; caller may wish to discard them or trigger re-read.
- Potential memory leak if invoked multiple times without freeing previous arrays.

Logging strategy:

- FATAL used for unrecoverable structural or resource errors.
- TRACE used for informational / soft failures (e.g., CRC mismatch, identifier mismatch, short read).

Parameters

  ctx | Mutable pointer to an aaruformatContext receiving parsed track metadata.
  entry | Pointer to the index entry describing this Tracks block (offset required; size not strictly used beyond informational logging and sequential reading).

Returns
  void This function does not return a status code; errors are reported via logging side effects.

Warning
  Not idempotent and not leak-safe if called more than once for a context.
  Absence of a returned status requires defensive post-call validation by the caller.
  CRC mismatch leaves possibly invalid data in ctx->trackEntries.

See also
  aaruf_get_tracks()
  aaruf_set_tracks()

Definition at line 111 of file optical.c.

References aaruf_crc64_data(), AARUF_VERSION_V1, bswap_64, TracksHeader::crc64, aaruformat_context::data_tracks, TracksHeader::entries, FATAL, ImageInfo::HasPartitions, ImageInfo::HasSessions, aaruformat_context::header, TracksHeader::identifier, aaruformat_context::image_info, AaruHeaderV2::imageMajorVersion, ImageInfo::ImageSize, aaruformat_context::imageStream, aaruformat_context::number_of_data_tracks, IndexEntry::offset, TrackEntry::sequence, TRACE, aaruformat_context::track_entries, aaruformat_context::tracks_header, and TracksBlock.

Referenced by aaruf_open().