libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
optical.c
Go to the documentation of this file.
1/*
2 * This file is part of the Aaru Data Preservation Suite.
3 * Copyright (c) 2019-2026 Natalia Portillo.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <inttypes.h>
20#include <stdint.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "aaruformat.h"
26#include "internal.h"
27#include "log.h"
28
113{
114 int pos = 0;
115 size_t read_bytes = 0;
116 uint64_t crc64 = 0;
117 int j = 0, k = 0;
118
119 // Check if the context and image stream are valid
120 if(ctx == NULL || ctx->imageStream == NULL)
121 {
122 FATAL("Invalid context or image stream.");
123 return;
124 }
125
126 // Seek to block
127 pos = aaruf_fseek(ctx->imageStream, (aaru_off_t)entry->offset, SEEK_SET);
128 if(pos < 0 || aaruf_ftell(ctx->imageStream) != (aaru_off_t)entry->offset)
129 {
130 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...\n", entry->offset);
131
132 return;
133 }
134
135 // Even if those two checks shall have been done before
136 read_bytes = fread(&ctx->tracks_header, 1, sizeof(TracksHeader), ctx->imageStream);
137
138 if(read_bytes != sizeof(TracksHeader))
139 {
140 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
141 TRACE("Could not read tracks header, continuing...\n");
142 return;
143 }
144
146 {
147 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
148 TRACE("Incorrect identifier for data block at position %" PRIu64 "\n", entry->offset);
149 }
150
151 ctx->image_info.ImageSize += sizeof(TrackEntry) * ctx->tracks_header.entries;
152
153 ctx->track_entries = (TrackEntry *)malloc(sizeof(TrackEntry) * ctx->tracks_header.entries);
154
155 if(ctx->track_entries == NULL)
156 {
157 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
158 FATAL("Could not allocate memory for metadata block, continuing...\n");
159 return;
160 }
161
162 read_bytes = fread(ctx->track_entries, sizeof(TrackEntry), ctx->tracks_header.entries, ctx->imageStream);
163
164 if(read_bytes != ctx->tracks_header.entries)
165 {
166 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
167 free(ctx->track_entries);
168 ctx->track_entries = NULL;
169 FATAL("Could not read metadata block, continuing...\n");
170
171 return;
172 }
173
174 crc64 = aaruf_crc64_data((const uint8_t *)ctx->track_entries, ctx->tracks_header.entries * sizeof(TrackEntry));
175
176 // Due to how C# wrote it, it is effectively reversed
177 if(ctx->header.imageMajorVersion <= AARUF_VERSION_V1) crc64 = bswap_64(crc64);
178
179 if(crc64 != ctx->tracks_header.crc64)
180 {
181 TRACE("Incorrect CRC found: 0x%" PRIx64 " found, expected 0x%" PRIx64 ", continuing...\n", crc64,
182 ctx->tracks_header.crc64);
183 return;
184 }
185
186 TRACE("Found %d tracks at position %" PRIu64 ".\n", ctx->tracks_header.entries, entry->offset);
187
188 ctx->image_info.HasPartitions = true;
189 ctx->image_info.HasSessions = true;
190
191 ctx->number_of_data_tracks = 0;
192
193 for(j = 0; j < ctx->tracks_header.entries; j++)
194 {
195 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99) ctx->number_of_data_tracks++;
196 }
197
198 if(ctx->number_of_data_tracks > 0)
199 {
200 ctx->data_tracks = malloc(sizeof(TrackEntry) * ctx->number_of_data_tracks);
201 if(ctx->data_tracks == NULL)
202 {
203 FATAL("Could not allocate memory for data tracks, continuing without filtered list.\n");
204 ctx->number_of_data_tracks = 0;
205 }
206 }
207 else
208 ctx->data_tracks = NULL;
209
210 if(ctx->data_tracks != NULL)
211 {
212 k = 0;
213 for(j = 0; j < ctx->tracks_header.entries; j++)
214 {
215 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99)
216 memcpy(&ctx->data_tracks[k++], &ctx->track_entries[j], sizeof(TrackEntry));
217 }
218 }
219}
220
282AARU_EXPORT int32_t AARU_CALL aaruf_get_tracks(const void *context, uint8_t *buffer, size_t *length)
283{
284 TRACE("Entering aaruf_get_tracks(%p, %p, %zu)", context, buffer, (length ? *length : 0));
285
286 // Check context is correct AaruFormat context
287 if(context == NULL)
288 {
289 FATAL("Invalid context");
290
291 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
293 }
294
295 const aaruformat_context *ctx = context;
296
297 // Not a libaaruformat context
298 if(ctx->magic != AARU_MAGIC)
299 {
300 FATAL("Invalid context");
301
302 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
304 }
305
306 if(ctx->tracks_header.entries == 0 || ctx->track_entries == NULL)
307 {
308 FATAL("Image contains no tracks");
309
310 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_TRACK_NOT_FOUND");
312 }
313
314 size_t required_length = ctx->tracks_header.entries * sizeof(TrackEntry);
315
316 if(buffer == NULL || length == NULL || *length < required_length)
317 {
318 if(length) *length = required_length;
319 TRACE("Buffer too small for tracks, required %zu bytes", required_length);
320
321 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_BUFFER_TOO_SMALL");
323 }
324
325 memcpy(buffer, ctx->track_entries, required_length);
326 *length = required_length;
327
328 TRACE("Exiting aaruf_get_tracks(%p, %p, %zu) = AARUF_STATUS_OK", context, buffer, *length);
329 return AARUF_STATUS_OK;
330}
331
393AARU_EXPORT int32_t AARU_CALL aaruf_set_tracks(void *context, TrackEntry *tracks, const int count)
394{
395 TRACE("Entering aaruf_set_tracks(%p, %p, %d)", context, tracks, count);
396
397 // Check context is correct AaruFormat context
398 if(context == NULL)
399 {
400 FATAL("Invalid context");
401
402 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
404 }
405
406 aaruformat_context *ctx = context;
407
408 // Not a libaaruformat context
409 if(ctx->magic != AARU_MAGIC)
410 {
411 FATAL("Invalid context");
412
413 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
415 }
416
417 // Clearing existing tracks
418 if(count == 0)
419 {
420 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
421 free(ctx->track_entries);
422 ctx->track_entries = NULL;
423 free(ctx->data_tracks);
424 ctx->data_tracks = NULL;
425 ctx->number_of_data_tracks = 0;
426
427 TRACE("Exiting aaruf_set_tracks() = AARUF_STATUS_OK");
428 return AARUF_STATUS_OK;
429 }
430
431 if(tracks == NULL || count < 0)
432 {
433 FATAL("Invalid tracks data");
434
435 TRACE("Exiting aaruf_set_tracks() = AARUF_ERROR_INVALID_TRACK_FORMAT");
437 }
438
440 ctx->tracks_header.entries = (uint16_t)count;
441 free(ctx->track_entries);
442 ctx->track_entries = malloc(sizeof(TrackEntry) * count);
443 if(ctx->track_entries == NULL)
444 {
445 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
446 FATAL("Could not allocate memory for tracks");
447
448 TRACE("Exiting aaruf_set_tracks() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
450 }
451 memcpy(ctx->track_entries, tracks, sizeof(TrackEntry) * count);
452 ctx->tracks_header.crc64 = aaruf_crc64_data((const uint8_t *)ctx->track_entries, sizeof(TrackEntry) * count);
453
454 ctx->image_info.HasPartitions = true;
455 ctx->image_info.HasSessions = true;
456 ctx->dirty_tracks_block = true; // Mark tracks block as dirty
457
458 free(ctx->data_tracks);
459 ctx->data_tracks = NULL;
460
461 ctx->number_of_data_tracks = 0;
462
463 for(int j = 0; j < ctx->tracks_header.entries; j++)
464 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99) ctx->number_of_data_tracks++;
465
466 if(ctx->number_of_data_tracks > 0)
467 {
468 ctx->data_tracks = malloc(sizeof(TrackEntry) * ctx->number_of_data_tracks);
469 if(ctx->data_tracks == NULL)
470 {
471 free(ctx->track_entries);
472 ctx->track_entries = NULL;
473 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
474 ctx->number_of_data_tracks = 0;
475 FATAL("Could not allocate memory for data tracks");
476
477 TRACE("Exiting aaruf_set_tracks() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
479 }
480 }
481
482 if(ctx->data_tracks != NULL)
483 {
484 int k = 0;
485 for(int j = 0; j < ctx->tracks_header.entries; j++)
486 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99)
487 memcpy(&ctx->data_tracks[k++], &ctx->track_entries[j], sizeof(TrackEntry));
488 }
489
490 TRACE("Exiting aaruf_set_tracks() = AARUF_STATUS_OK");
491 return AARUF_STATUS_OK;
492}
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
#define AARUF_VERSION_V1
First on‑disk version (C# implementation).
Definition consts.h:71
#define AARU_CALL
Definition decls.h:46
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
#define AARU_EXPORT
Definition decls.h:55
#define bswap_64(x)
Definition endian.h:81
@ TracksBlock
Block containing optical disc tracks.
Definition enums.h:174
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:81
#define AARUF_ERROR_TRACK_NOT_FOUND
Referenced track number not present.
Definition errors.h:52
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
Definition errors.h:48
#define AARUF_ERROR_INVALID_TRACK_FORMAT
Track metadata internally inconsistent or malformed.
Definition errors.h:54
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
#define AARUF_ERROR_BUFFER_TOO_SMALL
Caller-supplied buffer insufficient for data.
Definition errors.h:49
static int aaruf_fseek(FILE *stream, aaru_off_t offset, int origin)
Definition internal.h:46
static aaru_off_t aaruf_ftell(FILE *stream)
Definition internal.h:52
int64_t aaru_off_t
Definition internal.h:42
#define FATAL(fmt,...)
Definition log.h:40
#define TRACE(fmt,...)
Definition log.h:25
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.
Definition optical.c:282
void process_tracks_block(aaruformat_context *ctx, const IndexEntry *entry)
Parse and integrate a Tracks block from the image stream into the context.
Definition optical.c:112
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.
Definition optical.c:393
uint8_t imageMajorVersion
Container format major version.
Definition header.h:110
uint8_t HasPartitions
Image contains partitions (or tracks for optical media); 0=no, non-zero=yes.
Definition aaru.h:935
uint8_t HasSessions
Image contains multiple sessions (optical media); 0=single/none, non-zero=multi.
Definition aaru.h:936
uint64_t ImageSize
Size of the image payload in bytes (excludes headers/metadata).
Definition aaru.h:937
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags).
Definition optical.h:72
uint8_t sequence
Track number (1..99 typical for CD audio/data). 0 may indicate placeholder/non-standard.
Definition optical.h:73
Header for an optical tracks block listing track entries.
Definition optical.h:62
uint32_t identifier
Block identifier (must be BlockType::TracksBlock).
Definition optical.h:63
uint16_t entries
Number of TrackEntry records following this header.
Definition optical.h:64
uint64_t crc64
CRC64-ECMA of the TrackEntry array (header excluded, legacy byte-swap for early versions).
Definition optical.h:65
Master context representing an open or in‑creation Aaru image.
Definition context.h:175
TrackEntry * data_tracks
Filtered list of data tracks (subset of trackEntries).
Definition context.h:246
bool dirty_tracks_block
True if tracks block should be written during close.
Definition context.h:326
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:178
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:177
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:179
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:263
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
Definition context.h:245
uint8_t number_of_data_tracks
Count of tracks considered "data" (sequence 1..99 heuristics).
Definition context.h:248
TracksHeader tracks_header
Tracks header (optical) if present.
Definition context.h:247