Loading...
Searching...
No Matches
read.c
Go to the documentation of this file.
/*
* This file is part of the Aaru Data Preservation Suite.
* Copyright (c) 2019-2026 Natalia Portillo.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <aaruformat.h>
#include "internal.h"
#include "log.h"
AARU_EXPORT int32_t AARU_CALL aaruf_read_media_tag(void *context, uint8_t *data, const int32_t tag, uint32_t *length)
{
const uint32_t initial_length = length == NULL ? 0U : *length;
TRACE("Entering aaruf_read_media_tag(%p, %p, %d, %u)", context, data, tag, initial_length);
mediaTagEntry *item;
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(length == NULL)
{
FATAL("Invalid length pointer");
TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
const aaruformat_context *ctx = context;
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
TRACE("Finding media tag %d", tag);
HASH_FIND_INT(ctx->mediaTags, &tag, item);
if(item == NULL)
{
TRACE("Media tag not found");
*length = 0;
TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_MEDIA_TAG_NOT_PRESENT");
return AARUF_ERROR_MEDIA_TAG_NOT_PRESENT;
}
if(data == NULL || *length < item->length)
{
TRACE("Buffer too small for media tag %d, required %u bytes", tag, item->length);
*length = item->length;
TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
*length = item->length;
memcpy(data, item->data, item->length);
TRACE("Media tag %d read successfully, length %u", tag, *length);
TRACE("Exiting aaruf_read_media_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, const uint64_t sector_address, bool negative,
uint8_t *data, uint32_t *length, uint8_t *sector_status)
{
const uint32_t initial_length = length == NULL ? 0U : *length;
TRACE("Entering aaruf_read_sector(%p, %" PRIu64 ", %d, %p, %u)", context, sector_address, negative, data,
initial_length);
aaruformat_context *ctx = NULL;
uint64_t offset = 0;
uint64_t block_offset = 0;
BlockHeader *block_header = NULL;
uint8_t *block = NULL;
size_t read_bytes = 0;
uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH];
size_t lzma_size = 0;
uint8_t *cmp_data = NULL;
int error_no = 0;
*sector_status = SectorStatusNotDumped;
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
ctx = context;
if(length == NULL)
{
FATAL("Invalid length pointer");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(negative && sector_address > ctx->user_data_ddt_header.negative)
{
FATAL("Sector address out of bounds");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
return AARUF_ERROR_SECTOR_OUT_OF_BOUNDS;
}
if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
{
FATAL("Sector address out of bounds");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
return AARUF_ERROR_SECTOR_OUT_OF_BOUNDS;
}
if(ctx->ddt_version == 1)
{
if(negative)
{
FATAL("Negative sector addresses not supported in this image");
return AARUF_ERROR_SECTOR_OUT_OF_BOUNDS;
}
error_no = decode_ddt_entry_v1(ctx, sector_address, &offset, &block_offset, sector_status);
}
else if(ctx->ddt_version == 2)
error_no = decode_ddt_entry_v2(ctx, sector_address, negative, &offset, &block_offset, sector_status);
if(error_no != AARUF_STATUS_OK)
{
FATAL("Error %d decoding DDT entry", error_no);
TRACE("Exiting aaruf_read_sector() = %d", error_no);
return error_no;
}
// Partially written image... as we can't know the real sector size just assume it's common :/
if(*sector_status == SectorStatusNotDumped)
{
*length = ctx->image_info.SectorSize;
TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_SECTOR_NOT_DUMPED");
return AARUF_STATUS_SECTOR_NOT_DUMPED;
}
// Check if block header is cached
TRACE("Checking if block header is cached");
block_header = find_in_cache_uint64(&ctx->block_header_cache, block_offset);
// Read block header
if(block_header == NULL)
{
TRACE("Allocating memory for block header");
block_header = malloc(sizeof(BlockHeader));
if(block_header == NULL)
{
FATAL("Not enough memory for block header");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
TRACE("Reading block header");
if(fseek(ctx->imageStream, block_offset, SEEK_SET) != 0)
{
FATAL("Could not seek to block header");
free(block_header);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
return AARUF_ERROR_CANNOT_READ_HEADER;
}
read_bytes = fread(block_header, 1, sizeof(BlockHeader), ctx->imageStream);
if(read_bytes != sizeof(BlockHeader))
{
FATAL("Error reading block header");
free(block_header);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
return AARUF_ERROR_CANNOT_READ_HEADER;
}
TRACE("Adding block header to cache");
add_to_cache_uint64(&ctx->block_header_cache, block_offset, block_header);
}
else if(fseek(ctx->imageStream, block_offset + sizeof(BlockHeader), SEEK_SET) != 0)
{
FATAL("Could not seek past cached block header");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
return AARUF_ERROR_CANNOT_READ_HEADER;
}
if(data == NULL || *length < block_header->sectorSize)
{
TRACE("Buffer too small for sector, required %u bytes", block_header->sectorSize);
*length = block_header->sectorSize;
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
// Check if block is cached
TRACE("Checking if block is cached");
block = find_in_cache_uint64(&ctx->block_cache, block_offset);
if(block != NULL)
{
TRACE("Getting data from cache");
memcpy(data, block + offset * block_header->sectorSize, block_header->sectorSize);
*length = block_header->sectorSize;
TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
// Decompress block
switch(block_header->compression)
{
case None:
TRACE("Allocating memory for block");
block = (uint8_t *)malloc(block_header->length);
if(block == NULL)
{
FATAL("Not enough memory for block");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
TRACE("Reading block into memory");
read_bytes = fread(block, 1, block_header->length, ctx->imageStream);
if(read_bytes != block_header->length)
{
FATAL("Could not read block");
free(block);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_BLOCK");
return AARUF_ERROR_CANNOT_READ_BLOCK;
}
break;
case Lzma:
if(block_header->cmpLength <= LZMA_PROPERTIES_LENGTH || block_header->length == 0)
{
FATAL("Invalid LZMA block lengths (cmpLength=%u, length=%u)", block_header->cmpLength,
block_header->length);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
lzma_size = block_header->cmpLength - LZMA_PROPERTIES_LENGTH;
TRACE("Allocating memory for compressed data of size %zu bytes", lzma_size);
cmp_data = malloc(lzma_size);
if(cmp_data == NULL)
{
FATAL("Cannot allocate memory for block...");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
TRACE("Allocating memory for block of size %zu bytes", block_header->length);
block = malloc(block_header->length);
if(block == NULL)
{
FATAL("Cannot allocate memory for block...");
free(cmp_data);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
read_bytes = fread(lzma_properties, 1, LZMA_PROPERTIES_LENGTH, ctx->imageStream);
if(read_bytes != LZMA_PROPERTIES_LENGTH)
{
FATAL("Could not read LZMA properties...");
free(block);
free(cmp_data);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
read_bytes = fread(cmp_data, 1, lzma_size, ctx->imageStream);
if(read_bytes != lzma_size)
{
FATAL("Could not read compressed block...");
free(cmp_data);
free(block);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
TRACE("Decompressing block of size %zu bytes", block_header->length);
read_bytes = block_header->length;
error_no = aaruf_lzma_decode_buffer(block, &read_bytes, cmp_data, &lzma_size, lzma_properties,
LZMA_PROPERTIES_LENGTH);
if(error_no != 0)
{
FATAL("Got error %d from LZMA...", error_no);
free(cmp_data);
free(block);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
if(read_bytes != block_header->length)
{
FATAL("Error decompressing block, should be {0} bytes but got {1} bytes...");
free(cmp_data);
free(block);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
free(cmp_data);
break;
case Flac:
TRACE("Allocating memory for compressed data of size %zu bytes", block_header->cmpLength);
cmp_data = malloc(block_header->cmpLength);
if(cmp_data == NULL)
{
FATAL("Cannot allocate memory for block...");
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
TRACE("Allocating memory for block of size %zu bytes", block_header->length);
block = malloc(block_header->length);
if(block == NULL)
{
FATAL("Cannot allocate memory for block...");
free(cmp_data);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
TRACE("Reading compressed data into memory");
read_bytes = fread(cmp_data, 1, block_header->cmpLength, ctx->imageStream);
if(read_bytes != block_header->cmpLength)
{
FATAL("Could not read compressed block...");
free(cmp_data);
free(block);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
TRACE("Decompressing block of size %zu bytes", block_header->length);
read_bytes =
aaruf_flac_decode_redbook_buffer(block, block_header->length, cmp_data, block_header->cmpLength);
if(read_bytes != block_header->length)
{
FATAL("Error decompressing block, should be {0} bytes but got {1} bytes...");
free(cmp_data);
free(block);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
free(cmp_data);
break;
default:
FATAL("Unsupported compression %d", block_header->compression);
TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_UNSUPPORTED_COMPRESSION");
return AARUF_ERROR_UNSUPPORTED_COMPRESSION;
}
// Add block to cache
TRACE("Adding block to cache");
add_to_cache_uint64(&ctx->block_cache, block_offset, block);
memcpy(data, block + offset * block_header->sectorSize, block_header->sectorSize);
*length = block_header->sectorSize;
TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
AARU_EXPORT int32_t AARU_CALL aaruf_read_track_sector(void *context, uint8_t *data, const uint64_t sector_address,
uint32_t *length, const uint8_t track, uint8_t *sector_status)
{
const uint32_t initial_length = length == NULL ? 0U : *length;
TRACE("Entering aaruf_read_track_sector(%p, %p, %" PRIu64 ", %u, %d)", context, data, sector_address,
initial_length, track);
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
aaruformat_context *ctx = context;
if(length == NULL)
{
FATAL("Invalid length pointer");
TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Incorrect media type %d, expected OpticalDisc", ctx->image_info.MetadataMediaType);
TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
for(int i = 0; i < ctx->number_of_data_tracks; i++)
if(ctx->data_tracks[i].sequence == track)
return aaruf_read_sector(context, ctx->data_tracks[i].start + sector_address, false, data, length,
sector_status);
TRACE("Track %d not found", track);
TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_TRACK_NOT_FOUND");
return AARUF_ERROR_TRACK_NOT_FOUND;
}
AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_long(void *context, const uint64_t sector_address, bool negative,
uint8_t *data, uint32_t *length, uint8_t *sector_status)
{
const uint32_t initial_length = length == NULL ? 0U : *length;
TRACE("Entering aaruf_read_sector_long(%p, %" PRIu64 ", %d, %p, %u)", context, sector_address, data,
initial_length);
const aaruformat_context *ctx = NULL;
uint32_t bare_length = 0;
uint32_t tag_length = 0;
uint8_t *bare_data = NULL;
int32_t res = 0;
int32_t query_status;
TrackEntry trk;
int i = 0;
bool trk_found = false;
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
ctx = context;
if(length == NULL)
{
FATAL("Invalid length pointer");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(negative && sector_address > ctx->user_data_ddt_header.negative)
{
FATAL("Sector address out of bounds");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
return AARUF_ERROR_SECTOR_OUT_OF_BOUNDS;
}
if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
{
FATAL("Sector address out of bounds");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
return AARUF_ERROR_SECTOR_OUT_OF_BOUNDS;
}
uint64_t corrected_sector_address = sector_address;
// Calculate positive or negative sector
if(negative)
corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
else
corrected_sector_address += ctx->user_data_ddt_header.negative;
switch(ctx->image_info.MetadataMediaType)
{
case OpticalDisc:
if(ctx->image_info.MediaType == DVDROM || ctx->image_info.MediaType == PS2DVD ||
ctx->image_info.MediaType == SACD || ctx->image_info.MediaType == PS3DVD ||
ctx->image_info.MediaType == DVDR || ctx->image_info.MediaType == DVDRW ||
ctx->image_info.MediaType == DVDPR || ctx->image_info.MediaType == DVDPRW ||
ctx->image_info.MediaType == DVDPRWDL || ctx->image_info.MediaType == DVDRDL ||
ctx->image_info.MediaType == DVDPRDL || ctx->image_info.MediaType == DVDRAM ||
ctx->image_info.MediaType == DVDRWDL || ctx->image_info.MediaType == DVDDownload ||
ctx->image_info.MediaType == Nuon)
{
if(ctx->sector_id == NULL || ctx->sector_ied == NULL || ctx->sector_cpr_mai == NULL ||
ctx->sector_edc == NULL)
return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
if(*length < 2064 || data == NULL)
{
*length = 2064;
FATAL("Buffer too small for sector, required %u bytes", *length);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
bare_length = 0;
query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
{
TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
return query_status;
}
if(bare_length == 0)
{
FATAL("Invalid bare sector length (0)");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
TRACE("Allocating memory for bare data");
bare_data = (uint8_t *)malloc(bare_length);
if(bare_data == NULL)
{
FATAL("Could not allocate memory for bare data");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
if(res != AARUF_STATUS_OK)
{
*length = 2064;
free(bare_data);
TRACE("Exiting aaruf_read_sector_long() = %d", res);
return res;
}
memcpy(data, ctx->sector_id + corrected_sector_address * 4, 4);
memcpy(data + 4, ctx->sector_ied + corrected_sector_address * 2, 2);
memcpy(data + 6, ctx->sector_cpr_mai + corrected_sector_address * 6, 6);
memcpy(data + 12, bare_data, 2048);
memcpy(data + 2060, ctx->sector_edc + corrected_sector_address * 4, 4);
*length = 2064;
free(bare_data);
return AARUF_STATUS_OK;
}
if(*length < 2352 || data == NULL)
{
*length = 2352;
FATAL("Buffer too small for sector, required %u bytes", *length);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
if((ctx->sector_suffix == NULL || ctx->sector_prefix == NULL) &&
(ctx->sector_suffix_ddt == NULL || ctx->sector_prefix_ddt == NULL) &&
(ctx->sector_suffix_ddt2 == NULL || ctx->sector_prefix_ddt2 == NULL))
return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
bare_length = 0;
query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
{
TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
return query_status;
}
if(bare_length == 0)
{
FATAL("Invalid bare sector length (0)");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
TRACE("Allocating memory for bare data");
bare_data = (uint8_t *)malloc(bare_length);
if(bare_data == NULL)
{
FATAL("Could not allocate memory for bare data");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
if(res != AARUF_STATUS_OK)
{
free(bare_data);
TRACE("Exiting aaruf_read_sector_long() = %d", res);
return res;
}
trk_found = false;
for(i = 0; i < ctx->number_of_data_tracks; i++)
if(sector_address >= ctx->data_tracks[i].start && sector_address <= ctx->data_tracks[i].end)
{
trk_found = true;
trk = ctx->data_tracks[i];
break;
}
if(!trk_found)
{
FATAL("Track not found");
free(bare_data);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_TRACK_NOT_FOUND");
return AARUF_ERROR_TRACK_NOT_FOUND;
}
switch(trk.type)
{
case Audio:
case Data:
memcpy(data, bare_data, bare_length);
*length = bare_length;
free(bare_data);
return res;
case CdMode1:
memcpy(data + 16, bare_data, 2048);
if(ctx->sector_prefix_ddt2 != NULL)
{
const uint64_t prefix_ddt_entry = ctx->sector_prefix_ddt2[corrected_sector_address];
const uint32_t prefix_status = prefix_ddt_entry >> 60;
const uint64_t prefix_index = prefix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
if(prefix_status == SectorStatusMode1Correct)
{
aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
res = AARUF_STATUS_OK;
}
else if(prefix_status == SectorStatusNotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
memcpy(data, ctx->sector_prefix + prefix_index * 16, 16);
}
else if(ctx->sector_prefix != NULL)
memcpy(data, ctx->sector_prefix + corrected_sector_address * 16, 16);
else if(ctx->sector_prefix_ddt != NULL)
{
if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
{
aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
res = AARUF_STATUS_OK;
}
else if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
memcpy(data,
ctx->sector_prefix_corrected +
((ctx->sector_prefix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 16,
16);
}
else
{
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
free(bare_data);
return AARUF_ERROR_REACHED_UNREACHABLE_CODE;
}
if(res != AARUF_STATUS_OK)
{
*length = 2352;
free(bare_data);
return res;
}
if(ctx->sector_suffix_ddt2 != NULL)
{
const uint64_t suffix_ddt_entry = ctx->sector_suffix_ddt2[corrected_sector_address];
const uint64_t suffix_status = suffix_ddt_entry >> 60;
const uint64_t suffix_index = suffix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
if(suffix_status == SectorStatusMode1Correct)
{
aaruf_ecc_cd_reconstruct(ctx->ecc_cd_context, data, trk.type);
res = AARUF_STATUS_OK;
}
else if(suffix_status == SectorStatusNotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
memcpy(data + 2064, ctx->sector_suffix + suffix_index * 288, 288);
}
else if(ctx->sector_suffix != NULL)
memcpy(data + 2064, ctx->sector_suffix + corrected_sector_address * 288, 288);
else if(ctx->sector_suffix_ddt != NULL)
{
if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
{
aaruf_ecc_cd_reconstruct(ctx->ecc_cd_context, data, trk.type);
res = AARUF_STATUS_OK;
}
else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
memcpy(data + 2064,
ctx->sector_suffix_corrected +
((ctx->sector_suffix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 288,
288);
}
else
{
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
free(bare_data);
return AARUF_ERROR_REACHED_UNREACHABLE_CODE;
}
*length = 2352;
free(bare_data);
return res;
case CdMode2Formless:
case CdMode2Form1:
case CdMode2Form2:
if(ctx->sector_prefix_ddt2 != NULL)
{
const uint64_t prefix_ddt_entry = ctx->sector_prefix_ddt2[corrected_sector_address];
const uint64_t prefix_status = prefix_ddt_entry >> 60;
const uint64_t prefix_index = prefix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
if(prefix_status == SectorStatusMode2Form1Ok || prefix_status == SectorStatusMode2Form2Ok)
{
aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
res = AARUF_STATUS_OK;
}
else if(prefix_status == SectorStatusNotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
memcpy(data, ctx->sector_prefix + prefix_index * 16, 16);
}
else if(ctx->sector_prefix != NULL)
memcpy(data, ctx->sector_prefix + corrected_sector_address * 16, 16);
else if(ctx->sector_prefix_ddt != NULL)
{
if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
{
aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
res = AARUF_STATUS_OK;
}
else if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
memcpy(data,
ctx->sector_prefix_corrected +
((ctx->sector_prefix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 16,
16);
}
else
{
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
free(bare_data);
return AARUF_ERROR_REACHED_UNREACHABLE_CODE;
}
if(res != AARUF_STATUS_OK)
{
*length = 2352;
free(bare_data);
return res;
}
if(ctx->mode2_subheaders != NULL && ctx->sector_suffix_ddt2 != NULL)
{
memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
const uint64_t suffix_ddt_entry = ctx->sector_suffix_ddt2[corrected_sector_address];
const uint64_t suffix_status = suffix_ddt_entry >> 60;
const uint64_t suffix_index = suffix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
if(suffix_status == SectorStatusMode2Form1Ok)
{
memcpy(data + 24, bare_data, 2048);
aaruf_ecc_cd_reconstruct(ctx->ecc_cd_context, data, CdMode2Form1);
}
else if(suffix_status == SectorStatusMode2Form2Ok ||
suffix_status == SectorStatusMode2Form2NoCrc)
{
memcpy(data + 24, bare_data, 2324);
if(suffix_status == SectorStatusMode2Form2Ok)
aaruf_ecc_cd_reconstruct(ctx->ecc_cd_context, data, CdMode2Form2);
}
else if(suffix_status == SectorStatusNotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
// Mode 2 where ECC failed
memcpy(data + 24, bare_data, 2328);
}
else if(ctx->mode2_subheaders != NULL && ctx->sector_suffix_ddt != NULL)
{
memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form1Ok)
{
memcpy(data + 24, bare_data, 2048);
aaruf_ecc_cd_reconstruct(ctx->ecc_cd_context, data, CdMode2Form1);
}
else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2Ok ||
(ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2NoCrc)
{
memcpy(data + 24, bare_data, 2324);
if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2Ok)
aaruf_ecc_cd_reconstruct(ctx->ecc_cd_context, data, CdMode2Form2);
}
else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
res = AARUF_STATUS_SECTOR_NOT_DUMPED;
else
// Mode 2 where ECC failed
memcpy(data + 24, bare_data, 2328);
}
else if(ctx->mode2_subheaders != NULL)
{
memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
memcpy(data + 24, bare_data, 2328);
}
else
memcpy(data + 16, bare_data, 2336);
*length = 2352;
free(bare_data);
return res;
default:
FATAL("Invalid track type %d", trk.type);
free(bare_data);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INVALID_TRACK_FORMAT");
return AARUF_ERROR_INVALID_TRACK_FORMAT;
}
case BlockMedia:
switch(ctx->image_info.MediaType)
{
case AppleFileWare:
case AppleProfile:
case AppleSonySS:
case AppleSonyDS:
case AppleWidget:
case PriamDataTower:
if(ctx->sector_subchannel == NULL)
return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
switch(ctx->image_info.MediaType)
{
case AppleFileWare:
case AppleProfile:
case AppleWidget:
tag_length = 20;
break;
case AppleSonySS:
case AppleSonyDS:
tag_length = 12;
break;
case PriamDataTower:
tag_length = 24;
break;
default:
FATAL("Unsupported media type %d", ctx->image_info.MediaType);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
bare_length = 512;
if(*length < tag_length + bare_length || data == NULL)
{
*length = tag_length + bare_length;
FATAL("Buffer too small for sector, required %u bytes", *length);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
return AARUF_ERROR_BUFFER_TOO_SMALL;
}
TRACE("Allocating memory for bare data of size %u bytes", bare_length);
bare_data = malloc(bare_length);
if(bare_data == NULL)
{
FATAL("Could not allocate memory for bare data");
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
return AARUF_ERROR_NOT_ENOUGH_MEMORY;
}
res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
if(res != AARUF_STATUS_OK)
{
free(bare_data);
TRACE("Exiting aaruf_read_sector_long() = %d", res);
return res;
}
if(bare_length != 512)
{
FATAL("Bare data length is %u, expected 512", bare_length);
free(bare_data);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
memcpy(data + bare_length, ctx->sector_subchannel + corrected_sector_address * tag_length,
tag_length);
memcpy(data, bare_data, bare_length);
*length = tag_length + bare_length;
free(bare_data);
TRACE("Exiting aaruf_read_sector_long() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
default:
FATAL("Incorrect media type %d for long sector reading", ctx->image_info.MediaType);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
default:
FATAL("Incorrect media type %d for long sector reading", ctx->image_info.MediaType);
TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
}
AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_tag(const void *context, const uint64_t sector_address,
const bool negative, uint8_t *buffer, uint32_t *length,
const int32_t tag)
{
const uint32_t initial_length = length == NULL ? 0U : *length;
TRACE("Entering aaruf_read_sector_tag(%p, %" PRIu64 ", %d, %p, %u, %d)", context, sector_address, negative, buffer,
initial_length, tag);
const aaruformat_context *ctx = NULL;
if(context == NULL)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
ctx = context;
if(length == NULL)
{
FATAL("Invalid length pointer");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
// Not a libaaruformat context
if(ctx->magic != AARU_MAGIC)
{
FATAL("Invalid context");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
return AARUF_ERROR_NOT_AARUFORMAT;
}
if(negative && sector_address > ctx->user_data_ddt_header.negative)
{
FATAL("Sector address out of bounds");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
return AARUF_ERROR_SECTOR_OUT_OF_BOUNDS;
}
if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
{
FATAL("Sector address out of bounds");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
return AARUF_ERROR_SECTOR_OUT_OF_BOUNDS;
}
uint64_t corrected_sector_address = sector_address;
// Calculate positive or negative sector
if(negative)
corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
else
corrected_sector_address += ctx->user_data_ddt_header.negative;
switch(tag)
{
case CdTrackFlags:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 1 || buffer == NULL)
{
*length = 1;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
for(int i = 0; i < ctx->tracks_header.entries; i++)
if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
{
buffer[0] = ctx->track_entries[i].flags;
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
FATAL("Track not found");
return AARUF_ERROR_TRACK_NOT_FOUND;
case CdTrackIsrc:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 12 || buffer == NULL)
{
*length = 12;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
for(int i = 0; i < ctx->tracks_header.entries; i++)
if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
{
memcpy(buffer, ctx->track_entries[i].isrc, 12);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
FATAL("Track not found");
return AARUF_ERROR_TRACK_NOT_FOUND;
case CdSectorSubchannelAaru:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 96 || buffer == NULL)
{
*length = 96;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_subchannel == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 96, 96);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case DvdCmi:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 1 || buffer == NULL)
{
*length = 1;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_cpr_mai == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_cpr_mai + corrected_sector_address * 6, 1);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case DvdSectorInformation:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 1 || buffer == NULL)
{
*length = 1;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_id == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_id + corrected_sector_address * 4, 1);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case DvdSectorNumber:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 3 || buffer == NULL)
{
*length = 3;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_id == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_id + corrected_sector_address * 4 + 1, 3);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case DvdSectorIedAaru:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 2 || buffer == NULL)
{
*length = 2;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_ied == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_ied + corrected_sector_address * 2, 2);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case DvdSectorEdcAaru:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 4 || buffer == NULL)
{
*length = 4;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_edc == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_edc + corrected_sector_address * 4, 4);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case DvdTitleKeyDecrypted:
if(ctx->image_info.MetadataMediaType != OpticalDisc)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 5 || buffer == NULL)
{
*length = 5;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_decrypted_title_key == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_decrypted_title_key + corrected_sector_address * 5, 5);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case AppleSonyTagAaru:
if(ctx->image_info.MetadataMediaType != BlockMedia)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 12 || buffer == NULL)
{
*length = 12;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_subchannel == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 12, 12);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case AppleProfileTagAaru:
if(ctx->image_info.MetadataMediaType != BlockMedia)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 20 || buffer == NULL)
{
*length = 20;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_subchannel == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 20, 20);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
case PriamDataTowerTagAaru:
if(ctx->image_info.MetadataMediaType != BlockMedia)
{
FATAL("Invalid media type for tag");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
return AARUF_ERROR_INCORRECT_MEDIA_TYPE;
}
if(*length != 24 || buffer == NULL)
{
*length = 24;
FATAL("Incorrect tag size");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
return AARUF_ERROR_INCORRECT_DATA_SIZE;
}
if(ctx->sector_subchannel == NULL)
{
FATAL("Sector tag not found");
TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
return AARUF_ERROR_SECTOR_TAG_NOT_PRESENT;
}
memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 24, 24);
TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
default:
TRACE("Do not know how to read sector tag %d", tag);
return AARUF_ERROR_INVALID_TAG;
}
}
aaruformat.h
CD_DFIX_MASK
#define CD_DFIX_MASK
Mask for extracting positional index (lower 24 bits) in Compact Disc suffix/prefix deduplicated block...
Definition consts.h:102
LZMA_PROPERTIES_LENGTH
#define LZMA_PROPERTIES_LENGTH
Size in bytes of the fixed LZMA properties header (lc/lp/pb + dictionary size).
Definition consts.h:82
AARU_MAGIC
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
CD_XFIX_MASK
#define CD_XFIX_MASK
Mask for extracting correction / fix flags in Compact Disc suffix/prefix DDT entries.
Definition consts.h:100
AARU_CALL
#define AARU_CALL
Definition decls.h:46
aaruf_lzma_decode_buffer
int32_t aaruf_lzma_decode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t *src_size, const uint8_t *props, size_t props_size)
Decodes an LZMA-compressed buffer.
Definition lzma.c:39
aaruf_ecc_cd_reconstruct_prefix
void aaruf_ecc_cd_reconstruct_prefix(uint8_t *sector, uint8_t type, int64_t lba)
Reconstructs the prefix (sync, address, mode) of a CD sector.
Definition ecc_cd.c:409
AARU_EXPORT
#define AARU_EXPORT
Definition decls.h:55
aaruf_ecc_cd_reconstruct
void aaruf_ecc_cd_reconstruct(void *context, uint8_t *sector, uint8_t type)
Reconstructs the EDC and ECC fields of a CD sector.
Definition ecc_cd.c:476
aaruf_flac_decode_redbook_buffer
size_t aaruf_flac_decode_redbook_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size)
Decodes a FLAC-compressed Red Book audio buffer.
Definition flac.c:48
SectorStatusNotDumped
@ SectorStatusNotDumped
Sector(s) not yet acquired during image dumping.
Definition enums.h:236
SectorStatusMode2Form2NoCrc
@ SectorStatusMode2Form2NoCrc
Suffix matches MODE 2 Form 2 but CRC empty/missing.
Definition enums.h:242
SectorStatusMode1Correct
@ SectorStatusMode1Correct
Valid MODE 1 data with regenerable suffix/prefix.
Definition enums.h:239
SectorStatusMode2Form2Ok
@ SectorStatusMode2Form2Ok
Suffix matches MODE 2 Form 2 with valid CRC.
Definition enums.h:241
SectorStatusMode2Form1Ok
@ SectorStatusMode2Form1Ok
Suffix verified/regenerable for MODE 2 Form 1.
Definition enums.h:240
Correct
@ Correct
Sector(s) contain valid MODE 1 data with regenerable suffix/prefix.
Definition enums.h:189
Mode2Form2Ok
@ Mode2Form2Ok
Sector suffix valid for MODE 2 Form 2 with correct CRC.
Definition enums.h:191
Mode2Form1Ok
@ Mode2Form1Ok
Sector suffix valid for MODE 2 Form 1; regenerable.
Definition enums.h:190
NotDumped
@ NotDumped
Sector(s) have not yet been dumped.
Definition enums.h:188
Mode2Form2NoCrc
@ Mode2Form2NoCrc
Sector suffix valid for MODE 2 Form 2 but CRC absent/empty.
Definition enums.h:192
OpticalDisc
@ OpticalDisc
Purely optical discs.
Definition enums.h:224
BlockMedia
@ BlockMedia
Media that is physically block-based or abstracted like that.
Definition enums.h:225
CdMode1
@ CdMode1
Compact Disc Mode 1 data track.
Definition enums.h:203
Data
@ Data
Generic data track (not further specified).
Definition enums.h:202
CdMode2Form2
@ CdMode2Form2
Compact Disc Mode 2 Form 2 data track.
Definition enums.h:206
Audio
@ Audio
Audio track.
Definition enums.h:201
CdMode2Form1
@ CdMode2Form1
Compact Disc Mode 2 Form 1 data track.
Definition enums.h:205
CdMode2Formless
@ CdMode2Formless
Compact Disc Mode 2 (formless) data track.
Definition enums.h:204
Lzma
@ Lzma
LZMA compression.
Definition enums.h:34
None
@ None
Not compressed.
Definition enums.h:33
Flac
@ Flac
FLAC compression.
Definition enums.h:35
AARUF_STATUS_OK
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:77
AARUF_ERROR_INCORRECT_MEDIA_TYPE
#define AARUF_ERROR_INCORRECT_MEDIA_TYPE
Operation incompatible with image media type.
Definition errors.h:51
AARUF_ERROR_TRACK_NOT_FOUND
#define AARUF_ERROR_TRACK_NOT_FOUND
Referenced track number not present.
Definition errors.h:52
AARUF_ERROR_CANNOT_READ_HEADER
#define AARUF_ERROR_CANNOT_READ_HEADER
Failed to read container header.
Definition errors.h:45
AARUF_ERROR_NOT_ENOUGH_MEMORY
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
Definition errors.h:48
AARUF_ERROR_SECTOR_OUT_OF_BOUNDS
#define AARUF_ERROR_SECTOR_OUT_OF_BOUNDS
Requested logical sector outside media bounds.
Definition errors.h:44
AARUF_ERROR_INVALID_TRACK_FORMAT
#define AARUF_ERROR_INVALID_TRACK_FORMAT
Track metadata internally inconsistent or malformed.
Definition errors.h:54
AARUF_ERROR_CANNOT_READ_BLOCK
#define AARUF_ERROR_CANNOT_READ_BLOCK
Generic block read failure (seek/read error).
Definition errors.h:46
AARUF_ERROR_INCORRECT_DATA_SIZE
#define AARUF_ERROR_INCORRECT_DATA_SIZE
Data size does not match expected size.
Definition errors.h:65
AARUF_ERROR_SECTOR_TAG_NOT_PRESENT
#define AARUF_ERROR_SECTOR_TAG_NOT_PRESENT
Requested sector tag (e.g. subchannel/prefix) not stored.
Definition errors.h:55
AARUF_STATUS_SECTOR_NOT_DUMPED
#define AARUF_STATUS_SECTOR_NOT_DUMPED
Sector not captured (gap / missing / intentionally skipped).
Definition errors.h:78
AARUF_ERROR_NOT_AARUFORMAT
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK
#define AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK
Decompression routine failed or size mismatch.
Definition errors.h:56
AARUF_ERROR_INVALID_TAG
#define AARUF_ERROR_INVALID_TAG
Invalid or unsupported media or sector tag format.
Definition errors.h:66
AARUF_ERROR_MEDIA_TAG_NOT_PRESENT
#define AARUF_ERROR_MEDIA_TAG_NOT_PRESENT
Requested media tag absent.
Definition errors.h:50
AARUF_ERROR_BUFFER_TOO_SMALL
#define AARUF_ERROR_BUFFER_TOO_SMALL
Caller-supplied buffer insufficient for data.
Definition errors.h:49
AARUF_ERROR_UNSUPPORTED_COMPRESSION
#define AARUF_ERROR_UNSUPPORTED_COMPRESSION
Block marked with unsupported compression algorithm.
Definition errors.h:47
AARUF_ERROR_REACHED_UNREACHABLE_CODE
#define AARUF_ERROR_REACHED_UNREACHABLE_CODE
Internal logic assertion hit unexpected path.
Definition errors.h:53
AppleProfile
@ AppleProfile
Definition aaru.h:708
AppleSonySS
@ AppleSonySS
3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR
Definition aaru.h:250
DVDPRWDL
@ DVDPRWDL
DVD+RW DL.
Definition aaru.h:141
DVDRW
@ DVDRW
DVD-RW.
Definition aaru.h:138
DVDRWDL
@ DVDRWDL
DVD-RW DL.
Definition aaru.h:145
SACD
@ SACD
Super Audio CD (Scarlet Book).
Definition aaru.h:121
DVDPRDL
@ DVDPRDL
DVD+R DL.
Definition aaru.h:143
DVDR
@ DVDR
DVD-R.
Definition aaru.h:137
PS3DVD
@ PS3DVD
Sony PlayStation 3 game DVD.
Definition aaru.h:209
PS2DVD
@ PS2DVD
Sony PlayStation 2 game DVD.
Definition aaru.h:208
PriamDataTower
@ PriamDataTower
Definition aaru.h:711
AppleFileWare
@ AppleFileWare
5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy
Definition aaru.h:252
DVDPR
@ DVDPR
DVD+R.
Definition aaru.h:139
AppleWidget
@ AppleWidget
Definition aaru.h:709
DVDPRW
@ DVDPRW
DVD+RW.
Definition aaru.h:140
Nuon
@ Nuon
Nuon (DVD based videogame console).
Definition aaru.h:241
DVDDownload
@ DVDDownload
DVD-Download.
Definition aaru.h:146
DVDRDL
@ DVDRDL
DVD-R DL.
Definition aaru.h:142
AppleSonyDS
@ AppleSonyDS
3.5", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR
Definition aaru.h:251
DVDROM
@ DVDROM
DVD-ROM (applies to DVD Video and DVD Audio).
Definition aaru.h:136
DVDRAM
@ DVDRAM
DVD-RAM.
Definition aaru.h:144
DvdSectorIedAaru
@ DvdSectorIedAaru
DVD sector ID error detection, 2 bytes.
Definition aaru.h:976
CdTrackFlags
@ CdTrackFlags
Track flags (audio/data, copy permitted, pre-emphasis).
Definition aaru.h:969
DvdSectorEdcAaru
@ DvdSectorEdcAaru
DVD sector EDC, 4 bytes.
Definition aaru.h:977
DvdCmi
@ DvdCmi
DVD Copyright Management Information (CSS).
Definition aaru.h:970
CdSectorSubchannelAaru
@ CdSectorSubchannelAaru
96 raw subchannel bytes (P-W)
Definition aaru.h:966
DvdSectorNumber
@ DvdSectorNumber
DVD sector number, 3 bytes.
Definition aaru.h:975
CdTrackIsrc
@ CdTrackIsrc
Track ISRC (12 ASCII chars, no terminator).
Definition aaru.h:967
PriamDataTowerTagAaru
@ PriamDataTowerTagAaru
Priam DataTower sector tags, 24 bytes.
Definition aaru.h:979
AppleProfileTagAaru
@ AppleProfileTagAaru
Apple's Profile sector tags, 20 bytes.
Definition aaru.h:978
DvdSectorInformation
@ DvdSectorInformation
DVD sector information, 1 bytes.
Definition aaru.h:974
DvdTitleKeyDecrypted
@ DvdTitleKeyDecrypted
Decrypted DVD sector title key, 5 bytes.
Definition aaru.h:973
AppleSonyTagAaru
@ AppleSonyTagAaru
Apple's Sony sector tags, 12 bytes (address prolog + checksum).
Definition aaru.h:958
internal.h
decode_ddt_entry_v1
int32_t decode_ddt_entry_v1(aaruformat_context *ctx, uint64_t sector_address, uint64_t *offset, uint64_t *block_offset, uint8_t *sector_status)
Decodes a DDT v1 entry for a given sector address.
Definition ddt_v1.c:405
decode_ddt_entry_v2
int32_t decode_ddt_entry_v2(aaruformat_context *ctx, uint64_t sector_address, bool negative, uint64_t *offset, uint64_t *block_offset, uint8_t *sector_status)
Decodes a DDT v2 entry for a given sector address.
Definition ddt_v2.c:511
log.h
FATAL
#define FATAL(fmt,...)
Definition log.h:40
TRACE
#define TRACE(fmt,...)
Definition log.h:25
add_to_cache_uint64
void add_to_cache_uint64(struct CacheHeader *cache, uint64_t key, void *value)
Adds a value to the cache with a uint64_t key, using string conversion.
Definition lru.c:113
find_in_cache_uint64
void * find_in_cache_uint64(struct CacheHeader *cache, uint64_t key)
Finds a value in the cache by uint64_t key, using string conversion.
Definition lru.c:93
aaruf_read_sector
int32_t aaruf_read_sector(void *context, const uint64_t sector_address, bool negative, uint8_t *data, uint32_t *length, uint8_t *sector_status)
Reads a sector from the AaruFormat image.
Definition read.c:253
aaruf_read_sector_long
int32_t aaruf_read_sector_long(void *context, const uint64_t sector_address, bool negative, uint8_t *data, uint32_t *length, uint8_t *sector_status)
Reads a complete sector with all metadata from the AaruFormat image.
Definition read.c:826
aaruf_read_track_sector
int32_t aaruf_read_track_sector(void *context, uint8_t *data, const uint64_t sector_address, uint32_t *length, const uint8_t track, uint8_t *sector_status)
Reads a sector from a specific track in the AaruFormat image.
Definition read.c:670
aaruf_read_media_tag
int32_t aaruf_read_media_tag(void *context, uint8_t *data, const int32_t tag, uint32_t *length)
Reads a media tag from the AaruFormat image.
Definition read.c:85
aaruf_read_sector_tag
int32_t aaruf_read_sector_tag(const void *context, const uint64_t sector_address, const bool negative, uint8_t *buffer, uint32_t *length, const int32_t tag)
Reads a specific sector tag from the AaruFormat image.
Definition read.c:1474
BlockHeader
Header preceding the compressed data payload of a data block (BlockType::DataBlock).
Definition data.h:71
BlockHeader::cmpLength
uint32_t cmpLength
Size in bytes of the compressed payload immediately following this header.
Definition data.h:76
BlockHeader::length
uint32_t length
Size in bytes of the uncompressed payload resulting after decompression.
Definition data.h:77
BlockHeader::sectorSize
uint32_t sectorSize
Size in bytes of each logical sector represented in this block.
Definition data.h:75
BlockHeader::compression
uint16_t compression
Compression algorithm used (value from CompressionType).
Definition data.h:74
DdtHeader2::overflow
uint32_t overflow
Trailing dumped sectors beyond user area (overflow range), still mapped with entries.
Definition ddt.h:151
DdtHeader2::negative
uint32_t negative
Leading negative LBA count; added to external L to build internal index.
Definition ddt.h:149
ImageInfo::MediaType
uint32_t MediaType
Media type identifier (see MediaType enum; 0=Unknown).
Definition aaru.h:943
ImageInfo::MetadataMediaType
uint8_t MetadataMediaType
Media type for sidecar generation (internal archival use).
Definition aaru.h:944
ImageInfo::SectorSize
uint32_t SectorSize
Size of each logical sector in bytes (512, 2048, 2352, 4096, etc.).
Definition aaru.h:937
ImageInfo::Sectors
uint64_t Sectors
Total count of addressable logical sectors/blocks.
Definition aaru.h:936
TrackEntry
Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags).
Definition optical.h:72
TrackEntry::flags
uint8_t flags
Control / attribute bitfield (see file documentation for suggested bit mapping).
Definition optical.h:80
TrackEntry::sequence
uint8_t sequence
Track number (1..99 typical for CD audio/data). 0 may indicate placeholder/non-standard.
Definition optical.h:73
TrackEntry::start
int64_t start
Inclusive starting LBA of the track.
Definition optical.h:75
TrackEntry::type
uint8_t type
Track type (value from TrackType).
Definition optical.h:74
TrackEntry::isrc
uint8_t isrc[13]
ISRC raw 13-byte code (no null terminator). All zeros if not present.
Definition optical.h:79
TracksHeader::entries
uint16_t entries
Number of TrackEntry records following this header.
Definition optical.h:64
aaruformat_context
Master context representing an open or in‑creation Aaru image.
Definition context.h:175
aaruformat_context::user_data_ddt_header
DdtHeader2 user_data_ddt_header
Active user data DDT v2 header (primary table meta).
Definition context.h:192
aaruformat_context::sector_cpr_mai
uint8_t * sector_cpr_mai
DVD sector CPR_MAI (6 bytes) if present.
Definition context.h:210
aaruformat_context::sector_prefix_corrected
uint8_t * sector_prefix_corrected
Corrected variant (post error correction) if stored.
Definition context.h:203
aaruformat_context::data_tracks
TrackEntry * data_tracks
Filtered list of data tracks (subset of trackEntries).
Definition context.h:246
aaruformat_context::block_header_cache
struct CacheHeader block_header_cache
LRU/Cache header for block headers.
Definition context.h:259
aaruformat_context::sector_ied
uint8_t * sector_ied
DVD sector IED (2 bytes) if present.
Definition context.h:209
aaruformat_context::sector_prefix
uint8_t * sector_prefix
Raw per-sector prefix (e.g., sync+header) uncorrected.
Definition context.h:202
aaruformat_context::sector_suffix_ddt2
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
Definition context.h:189
aaruformat_context::sector_edc
uint8_t * sector_edc
DVD sector EDC (4 bytes) if present.
Definition context.h:211
aaruformat_context::ecc_cd_context
CdEccContext * ecc_cd_context
CD ECC/EDC helper tables (allocated on demand).
Definition context.h:251
aaruformat_context::block_cache
struct CacheHeader block_cache
LRU/Cache header for block payloads.
Definition context.h:260
aaruformat_context::sector_suffix_ddt
uint32_t * sector_suffix_ddt
Legacy CD sector suffix DDT.
Definition context.h:187
aaruformat_context::sector_suffix
uint8_t * sector_suffix
Raw per-sector suffix (EDC/ECC) uncorrected.
Definition context.h:204
aaruformat_context::ddt_version
int ddt_version
DDT version in use (1=legacy, 2=v2 hierarchical).
Definition context.h:197
aaruformat_context::magic
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:177
aaruformat_context::sector_prefix_ddt2
uint64_t * sector_prefix_ddt2
CD sector prefix DDT V2.
Definition context.h:188
aaruformat_context::mediaTags
mediaTagEntry * mediaTags
Hash table of extra media tags (uthash root).
Definition context.h:267
aaruformat_context::sector_decrypted_title_key
uint8_t * sector_decrypted_title_key
DVD decrypted title key (5 bytes) if present.
Definition context.h:212
aaruformat_context::sector_subchannel
uint8_t * sector_subchannel
Raw 96-byte subchannel (if captured).
Definition context.h:206
aaruformat_context::imageStream
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:179
aaruformat_context::mode2_subheaders
uint8_t * mode2_subheaders
MODE2 Form1/Form2 8-byte subheaders (concatenated).
Definition context.h:207
aaruformat_context::image_info
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:263
aaruformat_context::sector_id
uint8_t * sector_id
DVD sector ID (4 bytes) if present.
Definition context.h:208
aaruformat_context::sector_prefix_ddt
uint32_t * sector_prefix_ddt
Legacy CD sector prefix DDT (deprecated by *2).
Definition context.h:186
aaruformat_context::track_entries
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
Definition context.h:245
aaruformat_context::number_of_data_tracks
uint8_t number_of_data_tracks
Count of tracks considered "data" (sequence 1..99 heuristics).
Definition context.h:248
aaruformat_context::sector_suffix_corrected
uint8_t * sector_suffix_corrected
Corrected suffix if stored separately.
Definition context.h:205
aaruformat_context::tracks_header
TracksHeader tracks_header
Tracks header (optical) if present.
Definition context.h:247
mediaTagEntry
Hash table entry for an arbitrary media tag (e.g., proprietary drive/medium descriptor).
Definition context.h:122
mediaTagEntry::data
uint8_t * data
Tag data blob (opaque to library core); length bytes long.
Definition context.h:123
mediaTagEntry::length
uint32_t length
Length in bytes of data.
Definition context.h:125