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-2025 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 "log.h"
27
111 void process_tracks_block(aaruformat_context *ctx, const IndexEntry *entry)
112{
113 int pos = 0;
114 size_t read_bytes = 0;
115 uint64_t crc64 = 0;
116 int j = 0, k = 0;
117
118 // Check if the context and image stream are valid
119 if(ctx == NULL || ctx->imageStream == NULL)
120 {
121 FATAL("Invalid context or image stream.");
122 return;
123 }
124
125 // Seek to block
126 pos = fseek(ctx->imageStream, entry->offset, SEEK_SET);
127 if(pos < 0 || ftell(ctx->imageStream) != entry->offset)
128 {
129 FATAL("Could not seek to %" PRIu64 " as indicated by index entry...\n", entry->offset);
130
131 return;
132 }
133
134 // Even if those two checks shall have been done before
135 read_bytes = fread(&ctx->tracks_header, 1, sizeof(TracksHeader), ctx->imageStream);
136
137 if(read_bytes != sizeof(TracksHeader))
138 {
139 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
140 TRACE("Could not read tracks header, continuing...\n");
141 return;
142 }
143
144 if(ctx->tracks_header.identifier != TracksBlock)
145 {
146 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
147 TRACE("Incorrect identifier for data block at position %" PRIu64 "\n", entry->offset);
148 }
149
150 ctx->image_info.ImageSize += sizeof(TrackEntry) * ctx->tracks_header.entries;
151
152 ctx->track_entries = (TrackEntry *)malloc(sizeof(TrackEntry) * ctx->tracks_header.entries);
153
154 if(ctx->track_entries == NULL)
155 {
156 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
157 FATAL("Could not allocate memory for metadata block, continuing...\n");
158 return;
159 }
160
161 read_bytes = fread(ctx->track_entries, sizeof(TrackEntry), ctx->tracks_header.entries, ctx->imageStream);
162
163 if(read_bytes != ctx->tracks_header.entries)
164 {
165 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
166 free(ctx->track_entries);
167 ctx->track_entries = NULL;
168 FATAL("Could not read metadata block, continuing...\n");
169
170 return;
171 }
172
173 crc64 = aaruf_crc64_data((const uint8_t *)ctx->track_entries, ctx->tracks_header.entries * sizeof(TrackEntry));
174
175 // Due to how C# wrote it, it is effectively reversed
176 if(ctx->header.imageMajorVersion <= AARUF_VERSION_V1) crc64 = bswap_64(crc64);
177
178 if(crc64 != ctx->tracks_header.crc64)
179 {
180 TRACE("Incorrect CRC found: 0x%" PRIx64 " found, expected 0x%" PRIx64 ", continuing...\n", crc64,
181 ctx->tracks_header.crc64);
182 return;
183 }
184
185 TRACE("Found %d tracks at position %" PRIu64 ".\n", ctx->tracks_header.entries, entry->offset);
186
187 ctx->image_info.HasPartitions = true;
188 ctx->image_info.HasSessions = true;
189
190 ctx->number_of_data_tracks = 0;
191
192 for(j = 0; j < ctx->tracks_header.entries; j++)
193 {
194 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99) ctx->number_of_data_tracks++;
195 }
196
197 if(ctx->number_of_data_tracks > 0)
198 {
199 ctx->data_tracks = malloc(sizeof(TrackEntry) * ctx->number_of_data_tracks);
200 if(ctx->data_tracks == NULL)
201 {
202 FATAL("Could not allocate memory for data tracks, continuing without filtered list.\n");
203 ctx->number_of_data_tracks = 0;
204 }
205 }
206 else
207 ctx->data_tracks = NULL;
208
209 if(ctx->data_tracks != NULL)
210 {
211 k = 0;
212 for(j = 0; j < ctx->tracks_header.entries; j++)
213 {
214 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99)
215 memcpy(&ctx->data_tracks[k++], &ctx->track_entries[j], sizeof(TrackEntry));
216 }
217 }
218}
219
281 AARU_EXPORT int32_t AARU_CALL aaruf_get_tracks(const void *context, uint8_t *buffer, size_t *length)
282{
283 TRACE("Entering aaruf_get_tracks(%p, %p, %zu)", context, buffer, (length ? *length : 0));
284
285 // Check context is correct AaruFormat context
286 if(context == NULL)
287 {
288 FATAL("Invalid context");
289
290 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
291 return AARUF_ERROR_NOT_AARUFORMAT;
292 }
293
294 const aaruformat_context *ctx = context;
295
296 // Not a libaaruformat context
297 if(ctx->magic != AARU_MAGIC)
298 {
299 FATAL("Invalid context");
300
301 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
302 return AARUF_ERROR_NOT_AARUFORMAT;
303 }
304
305 if(ctx->tracks_header.entries == 0 || ctx->track_entries == NULL)
306 {
307 FATAL("Image contains no tracks");
308
309 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_TRACK_NOT_FOUND");
310 return AARUF_ERROR_TRACK_NOT_FOUND;
311 }
312
313 size_t required_length = ctx->tracks_header.entries * sizeof(TrackEntry);
314
315 if(buffer == NULL || length == NULL || *length < required_length)
316 {
317 if(length) *length = required_length;
318 TRACE("Buffer too small for tracks, required %zu bytes", required_length);
319
320 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_BUFFER_TOO_SMALL");
321 return AARUF_ERROR_BUFFER_TOO_SMALL;
322 }
323
324 memcpy(buffer, ctx->track_entries, required_length);
325 *length = required_length;
326
327 TRACE("Exiting aaruf_get_tracks(%p, %p, %zu) = AARUF_STATUS_OK", context, buffer, *length);
328 return AARUF_STATUS_OK;
329}
330
392 AARU_EXPORT int32_t AARU_CALL aaruf_set_tracks(void *context, TrackEntry *tracks, const int count)
393{
394 TRACE("Entering aaruf_set_tracks(%p, %p, %d)", context, tracks, count);
395
396 // Check context is correct AaruFormat context
397 if(context == NULL)
398 {
399 FATAL("Invalid context");
400
401 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
402 return AARUF_ERROR_NOT_AARUFORMAT;
403 }
404
405 aaruformat_context *ctx = context;
406
407 // Not a libaaruformat context
408 if(ctx->magic != AARU_MAGIC)
409 {
410 FATAL("Invalid context");
411
412 TRACE("Exiting aaruf_get_tracks() = AARUF_ERROR_NOT_AARUFORMAT");
413 return AARUF_ERROR_NOT_AARUFORMAT;
414 }
415
416 // Clearing existing tracks
417 if(count == 0)
418 {
419 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
420 free(ctx->track_entries);
421 ctx->track_entries = NULL;
422 free(ctx->data_tracks);
423 ctx->data_tracks = NULL;
424 ctx->number_of_data_tracks = 0;
425
426 TRACE("Exiting aaruf_set_tracks() = AARUF_STATUS_OK");
427 return AARUF_STATUS_OK;
428 }
429
430 if(tracks == NULL || count < 0)
431 {
432 FATAL("Invalid tracks data");
433
434 TRACE("Exiting aaruf_set_tracks() = AARUF_ERROR_INVALID_TRACK_FORMAT");
435 return AARUF_ERROR_INVALID_TRACK_FORMAT;
436 }
437
438 ctx->tracks_header.identifier = TracksBlock;
439 ctx->tracks_header.entries = (uint16_t)count;
440 free(ctx->track_entries);
441 ctx->track_entries = malloc(sizeof(TrackEntry) * count);
442 if(ctx->track_entries == NULL)
443 {
444 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
445 FATAL("Could not allocate memory for tracks");
446
447 TRACE("Exiting aaruf_set_tracks() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
448 return AARUF_ERROR_NOT_ENOUGH_MEMORY;
449 }
450 memcpy(ctx->track_entries, tracks, sizeof(TrackEntry) * count);
451 ctx->tracks_header.crc64 = aaruf_crc64_data((const uint8_t *)ctx->track_entries, sizeof(TrackEntry) * count);
452
453 ctx->image_info.HasPartitions = true;
454 ctx->image_info.HasSessions = true;
455
456 free(ctx->data_tracks);
457 ctx->data_tracks = NULL;
458
459 ctx->number_of_data_tracks = 0;
460
461 for(int j = 0; j < ctx->tracks_header.entries; j++)
462 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99) ctx->number_of_data_tracks++;
463
464 if(ctx->number_of_data_tracks > 0)
465 {
466 ctx->data_tracks = malloc(sizeof(TrackEntry) * ctx->number_of_data_tracks);
467 if(ctx->data_tracks == NULL)
468 {
469 free(ctx->track_entries);
470 ctx->track_entries = NULL;
471 memset(&ctx->tracks_header, 0, sizeof(TracksHeader));
472 ctx->number_of_data_tracks = 0;
473 FATAL("Could not allocate memory for data tracks");
474
475 TRACE("Exiting aaruf_set_tracks() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
476 return AARUF_ERROR_NOT_ENOUGH_MEMORY;
477 }
478 }
479
480 if(ctx->data_tracks != NULL)
481 {
482 int k = 0;
483 for(int j = 0; j < ctx->tracks_header.entries; j++)
484 if(ctx->track_entries[j].sequence > 0 && ctx->track_entries[j].sequence <= 99)
485 memcpy(&ctx->data_tracks[k++], &ctx->track_entries[j], sizeof(TrackEntry));
486 }
487
488 TRACE("Exiting aaruf_set_tracks() = AARUF_STATUS_OK");
489 return AARUF_STATUS_OK;
490}
aaruformat.h
AARU_MAGIC
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
AARUF_VERSION_V1
#define AARUF_VERSION_V1
First on‑disk version (C# implementation).
Definition consts.h:71
AARU_CALL
#define AARU_CALL
Definition decls.h:45
aaruf_crc64_data
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
AARU_EXPORT
#define AARU_EXPORT
Definition decls.h:54
bswap_64
#define bswap_64(x)
Definition endian.h:81
TracksBlock
@ TracksBlock
Block containing optical disc tracks.
Definition enums.h:150
AARUF_STATUS_OK
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:75
AARUF_ERROR_TRACK_NOT_FOUND
#define AARUF_ERROR_TRACK_NOT_FOUND
Referenced track number not present.
Definition errors.h:52
AARUF_ERROR_NOT_ENOUGH_MEMORY
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
Definition errors.h:48
AARUF_ERROR_INVALID_TRACK_FORMAT
#define AARUF_ERROR_INVALID_TRACK_FORMAT
Track metadata internally inconsistent or malformed.
Definition errors.h:54
AARUF_ERROR_NOT_AARUFORMAT
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
AARUF_ERROR_BUFFER_TOO_SMALL
#define AARUF_ERROR_BUFFER_TOO_SMALL
Caller-supplied buffer insufficient for data.
Definition errors.h:49
log.h
FATAL
#define FATAL(fmt,...)
Definition log.h:40
TRACE
#define TRACE(fmt,...)
Definition log.h:25
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.
Definition optical.c:281
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.
Definition optical.c:111
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.
Definition optical.c:392
AaruHeaderV2::imageMajorVersion
uint8_t imageMajorVersion
Container format major version.
Definition header.h:110
ImageInfo::HasPartitions
uint8_t HasPartitions
Image contains partitions (or tracks for optical media); 0=no, non-zero=yes.
Definition aaru.h:871
ImageInfo::HasSessions
uint8_t HasSessions
Image contains multiple sessions (optical media); 0=single/none, non-zero=multi.
Definition aaru.h:872
ImageInfo::ImageSize
uint64_t ImageSize
Size of the image payload in bytes (excludes headers/metadata)
Definition aaru.h:873
IndexEntry
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
IndexEntry::offset
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
TrackEntry
Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags).
Definition optical.h:72
TrackEntry::sequence
uint8_t sequence
Track number (1..99 typical for CD audio/data). 0 may indicate placeholder/non-standard.
Definition optical.h:73
TracksHeader
Header for an optical tracks block listing track entries.
Definition optical.h:62
TracksHeader::identifier
uint32_t identifier
Block identifier (must be BlockType::TracksBlock).
Definition optical.h:63
TracksHeader::entries
uint16_t entries
Number of TrackEntry records following this header.
Definition optical.h:64
TracksHeader::crc64
uint64_t crc64
CRC64-ECMA of the TrackEntry array (header excluded, legacy byte-swap for early versions).
Definition optical.h:65
aaruformat_context
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
aaruformat_context::data_tracks
TrackEntry * data_tracks
Filtered list of data tracks (subset of trackEntries).
Definition context.h:243
aaruformat_context::header
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:175
aaruformat_context::magic
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:174
aaruformat_context::imageStream
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:176
aaruformat_context::image_info
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:260
aaruformat_context::track_entries
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
Definition context.h:242
aaruformat_context::number_of_data_tracks
uint8_t number_of_data_tracks
Count of tracks considered "data" (sequence 1..99 heuristics).
Definition context.h:245
aaruformat_context::tracks_header
TracksHeader tracks_header
Tracks header (optical) if present.
Definition context.h:244