Loading...
Searching...
No Matches
data.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 <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "aaruformat.h"
#include "log.h"
#include "uthash.h"
int32_t process_data_block(aaruformat_context *ctx, IndexEntry *entry)
{
TRACE("Entering process_data_block(%p, %p)", ctx, entry);
BlockHeader block_header;
int pos = 0;
size_t read_bytes = 0;
size_t lzma_size = 0;
uint8_t *cmp_data = NULL;
uint8_t *cst_data = NULL;
mediaTagEntry *old_media_tag = NULL;
mediaTagEntry *media_tag = NULL;
uint8_t *data = NULL;
uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH];
// Check if the context, index entry, and image stream are valid
if(ctx == NULL || entry == NULL || ctx->imageStream == NULL)
{
FATAL("Invalid context or image stream.");
return AARUF_ERROR_NOT_AARUFORMAT;
}
// Seek to block
pos = fseek(ctx->imageStream, entry->offset, SEEK_SET);
if(pos < 0 || ftell(ctx->imageStream) != entry->offset)
{
FATAL("Could not seek to %" PRIu64 " as indicated by index entry...", entry->offset);
return AARUF_ERROR_CANNOT_READ_BLOCK;
}
// Even if those two checks shall have been done before
// NOP block, skip
if(entry->dataType == NoData || (entry->dataType == UserData && ctx->header.biggestSectorSize > 0))
{
TRACE("NoData block found, skipping");
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
TRACE("Reading block header at position %" PRIu64, entry->offset);
read_bytes = fread(&block_header, 1, sizeof(BlockHeader), ctx->imageStream);
if(read_bytes != sizeof(BlockHeader))
{
FATAL("Could not read block header at %" PRIu64, entry->offset);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
ctx->image_info.ImageSize += block_header.cmpLength;
// Unused, skip
if(entry->dataType == UserData)
{
if(block_header.sectorSize > ctx->image_info.SectorSize)
{
TRACE("Setting sector size to %" PRIu64 " bytes", block_header.sectorSize);
ctx->image_info.SectorSize = block_header.sectorSize;
}
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
if(block_header.identifier != entry->blockType)
{
TRACE("Incorrect identifier for data block at position %" PRIu64, entry->offset);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
if(block_header.type != entry->dataType)
{
TRACE("Expected block with data type %4.4s at position %" PRIu64 " but found data type %4.4s",
(char *)&entry->blockType, entry->offset, (char *)&block_header.type);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
TRACE("Found data block with type %4.4s at position %" PRIu64, (char *)&entry->blockType, entry->offset);
if(block_header.compression == Lzma || block_header.compression == LzmaClauniaSubchannelTransform)
{
int error_no = 0;
if(block_header.compression == LzmaClauniaSubchannelTransform && block_header.type != CdSectorSubchannel)
{
TRACE("Invalid compression type %u for block with data type %u, continuing...", block_header.compression,
block_header.type);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
if(block_header.cmpLength < LZMA_PROPERTIES_LENGTH)
{
TRACE("Compressed block length %" PRIu32 " too small for LZMA properties, continuing...",
block_header.cmpLength);
TRACE("Exiting process_data_block() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
lzma_size = block_header.cmpLength - LZMA_PROPERTIES_LENGTH;
cmp_data = (lzma_size == 0) ? NULL : (uint8_t *)malloc(lzma_size);
if(lzma_size != 0 && cmp_data == NULL)
{
TRACE("Cannot allocate memory for block, continuing...");
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
if(block_header.length != 0)
{
data = (uint8_t *)malloc(block_header.length);
if(data == NULL)
{
TRACE("Cannot allocate memory for block, continuing...");
free(cmp_data);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
}
else
data = NULL;
read_bytes = fread(lzma_properties, 1, LZMA_PROPERTIES_LENGTH, ctx->imageStream);
if(read_bytes != LZMA_PROPERTIES_LENGTH)
{
TRACE("Could not read LZMA properties, continuing...");
free(cmp_data);
free(data);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
if(lzma_size != 0)
{
read_bytes = fread(cmp_data, 1, lzma_size, ctx->imageStream);
if(read_bytes != lzma_size)
{
TRACE("Could not read compressed block, continuing...");
free(cmp_data);
free(data);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
}
if(block_header.length != 0)
{
read_bytes = block_header.length;
error_no = aaruf_lzma_decode_buffer(data, &read_bytes, cmp_data, &lzma_size, lzma_properties,
LZMA_PROPERTIES_LENGTH);
if(error_no != 0)
{
TRACE("Got error %d from LZMA, continuing...", error_no);
free(cmp_data);
free(data);
TRACE("Exiting process_data_block() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
if(read_bytes != block_header.length)
{
TRACE("Error decompressing block, expected %" PRIu32 " bytes but got %zu bytes, continuing...",
block_header.length, read_bytes);
free(cmp_data);
free(data);
TRACE("Exiting process_data_block() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
return AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK;
}
}
else if(lzma_size != 0)
{
TRACE("Compressed payload present for zero-length block, continuing...");
free(cmp_data);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
if(block_header.compression == LzmaClauniaSubchannelTransform && block_header.length != 0)
{
cst_data = (uint8_t *)malloc(block_header.length);
if(cst_data == NULL)
{
TRACE("Cannot allocate memory for block, continuing...");
free(cmp_data);
free(data);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
aaruf_cst_untransform(data, cst_data, block_header.length);
free(data);
data = cst_data;
cst_data = NULL;
}
free(cmp_data);
}
else if(block_header.compression == None)
{
if(block_header.length != 0)
{
data = (uint8_t *)malloc(block_header.length);
if(data == NULL)
{
TRACE("Cannot allocate memory for block, continuing...");
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
}
else
data = NULL;
read_bytes = (block_header.length == 0) ? 0 : fread(data, 1, block_header.length, ctx->imageStream);
if(block_header.length != 0 && read_bytes != block_header.length)
{
free(data);
TRACE("Could not read block, continuing...");
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
}
else
{
TRACE("Found unknown compression type %d, continuing...", block_header.compression);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
if(block_header.length > 0)
{
uint64_t crc64 = aaruf_crc64_data(data, block_header.length);
// Due to how C# wrote it, it is effectively reversed
if(ctx->header.imageMajorVersion <= AARUF_VERSION_V1) crc64 = bswap_64(crc64);
if(crc64 != block_header.crc64)
{
TRACE("Incorrect CRC found: 0x%" PRIx64 " found, expected 0x%" PRIx64 ", continuing...", crc64,
block_header.crc64);
free(data);
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
}
// Check if it's not a media tag, but a sector tag, and fill the appropriate table then
switch(entry->dataType)
{
case CdSectorPrefix:
case CdSectorPrefixCorrected:
if(entry->dataType == CdSectorPrefixCorrected) { ctx->sector_prefix_corrected = data; }
else
ctx->sector_prefix = data;
ctx->readableSectorTags[CdSectorSync] = true;
ctx->readableSectorTags[CdSectorHeader] = true;
break;
case CdSectorSuffix:
case CdSectorSuffixCorrected:
if(entry->dataType == CdSectorSuffixCorrected)
ctx->sector_suffix_corrected = data;
else
ctx->sector_suffix = data;
ctx->readableSectorTags[CdSectorSubHeader] = true;
ctx->readableSectorTags[CdSectorEcc] = true;
ctx->readableSectorTags[CdSectorEccP] = true;
ctx->readableSectorTags[CdSectorEccQ] = true;
ctx->readableSectorTags[CdSectorEdc] = true;
break;
case CdSectorSubchannel:
ctx->sector_subchannel = data;
ctx->readableSectorTags[CdSectorSubchannelAaru] = true;
break;
case AppleProfileTag:
ctx->sector_subchannel = data;
ctx->readableSectorTags[AppleProfileTagAaru] = true;
break;
case AppleSonyTag:
ctx->sector_subchannel = data;
ctx->readableSectorTags[PriamDataTowerTagAaru] = true;
break;
case PriamDataTowerTag:
ctx->sector_subchannel = data;
ctx->readableSectorTags[AppleSonyTagAaru] = true;
break;
case CompactDiscMode2Subheader:
ctx->mode2_subheaders = data;
break;
case DvdSectorId:
ctx->sector_id = data;
ctx->readableSectorTags[DvdSectorNumber] = true;
ctx->readableSectorTags[DvdSectorInformation] = true;
break;
case DvdSectorIed:
ctx->sector_ied = data;
ctx->readableSectorTags[DvdSectorIedAaru] = true;
break;
case DvdSectorCprMai:
ctx->sector_cpr_mai = data;
ctx->readableSectorTags[DvdCmi] = true;
break;
case DvdSectorEdc:
ctx->sector_edc = data;
ctx->readableSectorTags[DvdSectorEdcAaru] = true;
break;
case DvdTitleKeyDecrypted:
ctx->sector_decrypted_title_key = data;
ctx->readableSectorTags[DvdSectorTitleKeyDecrypted] = true;
break;
default:
media_tag = (mediaTagEntry *)malloc(sizeof(mediaTagEntry));
if(media_tag == NULL)
{
TRACE("Cannot allocate memory for media tag entry.");
free(data);
data = NULL;
break;
}
memset(media_tag, 0, sizeof(mediaTagEntry));
media_tag->type = aaruf_get_media_tag_type_for_datatype(block_header.type);
media_tag->data = data;
media_tag->length = block_header.length;
HASH_REPLACE_INT(ctx->mediaTags, type, media_tag, old_media_tag);
if(old_media_tag != NULL)
{
TRACE("Replaced media tag with type %d", old_media_tag->type);
free(old_media_tag->data);
free(old_media_tag);
old_media_tag = NULL;
}
break;
}
TRACE("Exiting process_data_block() = AARUF_STATUS_OK");
return AARUF_STATUS_OK;
}
aaruformat.h
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
AARUF_VERSION_V1
#define AARUF_VERSION_V1
First on‑disk version (C# implementation).
Definition consts.h:71
process_data_block
int32_t process_data_block(aaruformat_context *ctx, IndexEntry *entry)
Processes a data block from the image stream.
Definition data.c:71
aaruf_crc64_data
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
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_get_media_tag_type_for_datatype
int32_t aaruf_get_media_tag_type_for_datatype(int32_t type)
Converts an image data type to an Aaru media tag type.
Definition helpers.c:39
aaruf_cst_untransform
int32_t aaruf_cst_untransform(const uint8_t *sequential, uint8_t *interleaved, size_t length)
Reverses the CST (Claunia's Subchannel Transform) transformation from sequential to interleaved data.
Definition cst.c:193
bswap_64
#define bswap_64(x)
Definition endian.h:81
CdSectorSubchannel
@ CdSectorSubchannel
Compact Disc subchannel data.
Definition enums.h:116
AppleProfileTag
@ AppleProfileTag
Apple Profile (20‑byte) tag.
Definition enums.h:117
DvdSectorIed
@ DvdSectorIed
DVD ID Error Detection Code (IED).
Definition enums.h:129
CdSectorPrefixCorrected
@ CdSectorPrefixCorrected
Compact Disc sector prefix (sync, header) corrected-only stored.
Definition enums.h:121
DvdSectorCprMai
@ DvdSectorCprMai
DVD Copyright Management Information (CPR_MAI).
Definition enums.h:126
AppleSonyTag
@ AppleSonyTag
Apple Sony (12‑byte) tag.
Definition enums.h:118
CdSectorPrefix
@ CdSectorPrefix
Compact Disc sector prefix (sync, header).
Definition enums.h:114
CdSectorSuffixCorrected
@ CdSectorSuffixCorrected
Compact Disc sector suffix (EDC, ECC P, ECC Q) corrected-only stored.
Definition enums.h:122
PriamDataTowerTag
@ PriamDataTowerTag
Priam Data Tower (24‑byte) tag.
Definition enums.h:119
UserData
@ UserData
User (main) data.
Definition enums.h:46
NoData
@ NoData
No data.
Definition enums.h:45
DvdSectorEdc
@ DvdSectorEdc
DVD Error Detection Code (EDC).
Definition enums.h:130
DvdSectorTitleKeyDecrypted
@ DvdSectorTitleKeyDecrypted
Decrypted DVD Title Key.
Definition enums.h:127
DvdSectorId
@ DvdSectorId
DVD Identification Data (ID).
Definition enums.h:128
CdSectorSuffix
@ CdSectorSuffix
Compact Disc sector suffix (EDC, ECC P, ECC Q).
Definition enums.h:115
CompactDiscMode2Subheader
@ CompactDiscMode2Subheader
Compact Disc MODE 2 subheader.
Definition enums.h:123
Lzma
@ Lzma
LZMA compression.
Definition enums.h:34
LzmaClauniaSubchannelTransform
@ LzmaClauniaSubchannelTransform
LZMA applied to Claunia Subchannel Transform processed data.
Definition enums.h:36
None
@ None
Not compressed.
Definition enums.h:33
AARUF_STATUS_OK
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:77
AARUF_ERROR_CANNOT_READ_BLOCK
#define AARUF_ERROR_CANNOT_READ_BLOCK
Generic block read failure (seek/read error).
Definition errors.h:46
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
DvdSectorIedAaru
@ DvdSectorIedAaru
DVD sector ID error detection, 2 bytes.
Definition aaru.h:976
CdSectorHeader
@ CdSectorHeader
4-byte CD header (minute, second, frame, mode)
Definition aaru.h:960
CdSectorEdc
@ CdSectorEdc
32-bit CRC (EDC)
Definition aaru.h:962
CdSectorEccP
@ CdSectorEccP
172 bytes Reed-Solomon ECC (P)
Definition aaru.h:963
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
CdSectorSubHeader
@ CdSectorSubHeader
Mode 2 Form subheader (8 bytes: copy, submode, channel).
Definition aaru.h:961
DvdSectorNumber
@ DvdSectorNumber
DVD sector number, 3 bytes.
Definition aaru.h:975
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
CdSectorEcc
@ CdSectorEcc
Combined P+Q ECC (276 bytes).
Definition aaru.h:965
DvdTitleKeyDecrypted
@ DvdTitleKeyDecrypted
Decrypted DVD sector title key, 5 bytes.
Definition aaru.h:973
CdSectorSync
@ CdSectorSync
12-byte CD sync pattern (00 FF*10 00)
Definition aaru.h:959
CdSectorEccQ
@ CdSectorEccQ
104 bytes Reed-Solomon ECC (Q)
Definition aaru.h:964
AppleSonyTagAaru
@ AppleSonyTagAaru
Apple's Sony sector tags, 12 bytes (address prolog + checksum).
Definition aaru.h:958
log.h
FATAL
#define FATAL(fmt,...)
Definition log.h:40
TRACE
#define TRACE(fmt,...)
Definition log.h:25
AaruHeaderV2::biggestSectorSize
uint16_t biggestSectorSize
size of biggest sector in the image (in bytes).
Definition header.h:120
AaruHeaderV2::imageMajorVersion
uint8_t imageMajorVersion
Container format major version.
Definition header.h:110
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::identifier
uint32_t identifier
Block identifier, must be BlockType::DataBlock.
Definition data.h:72
BlockHeader::sectorSize
uint32_t sectorSize
Size in bytes of each logical sector represented in this block.
Definition data.h:75
BlockHeader::crc64
uint64_t crc64
CRC64-ECMA of the uncompressed payload (length bytes).
Definition data.h:79
BlockHeader::type
uint16_t type
Logical data classification (value from DataType).
Definition data.h:73
BlockHeader::compression
uint16_t compression
Compression algorithm used (value from CompressionType).
Definition data.h:74
ImageInfo::SectorSize
uint32_t SectorSize
Size of each logical sector in bytes (512, 2048, 2352, 4096, etc.).
Definition aaru.h:937
ImageInfo::ImageSize
uint64_t ImageSize
Size of the image payload in bytes (excludes headers/metadata).
Definition aaru.h:935
IndexEntry
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
IndexEntry::blockType
uint32_t blockType
Block identifier of the referenced block (value from BlockType).
Definition index.h:110
IndexEntry::offset
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
IndexEntry::dataType
uint16_t dataType
Data classification (value from DataType) or unused for untyped blocks.
Definition index.h:111
aaruformat_context
Master context representing an open or in‑creation Aaru image.
Definition context.h:175
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::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_edc
uint8_t * sector_edc
DVD sector EDC (4 bytes) if present.
Definition context.h:211
aaruformat_context::sector_suffix
uint8_t * sector_suffix
Raw per-sector suffix (EDC/ECC) uncorrected.
Definition context.h:204
aaruformat_context::header
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:178
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::readableSectorTags
bool * readableSectorTags
Per-sector boolean array (optical tags read successfully?).
Definition context.h:266
aaruformat_context::sector_suffix_corrected
uint8_t * sector_suffix_corrected
Corrected suffix if stored separately.
Definition context.h:205
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::type
int32_t type
Numeric type identifier.
Definition context.h:124
mediaTagEntry::length
uint32_t length
Length in bytes of data.
Definition context.h:125