libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
read.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 <stdlib.h>
20#include <string.h>
21
22#include <aaruformat.h>
23
24#include "erasure_internal.h"
25#include "internal.h"
26#include "log.h"
27#include "ngcw/lfg.h"
28#include "ngcw/ngcw_junk.h"
29#include "ngcw/wii_crypto.h"
30#include "ps3/ps3_crypto.h"
32#include "wiiu/wiiu_crypto.h"
33
44static void wii_reconstruct_group_junk(aaruformat_context *ctx, uint64_t phys_group, uint8_t *group_cache)
45{
46 if(ctx->ngcw_junk_entries == NULL || ctx->ngcw_junk_entry_count == 0) return;
47
48 if(ctx->wii_partition_regions == NULL) return;
49
50 /* Find which partition this group belongs to */
51 const WiiPartitionRegion *regions = (const WiiPartitionRegion *)ctx->wii_partition_regions;
52 int in_part = -1;
53
54 for(uint32_t p = 0; p < ctx->wii_partition_region_count; p++)
55 {
56 if(phys_group >= regions[p].start_sector && phys_group < regions[p].end_sector)
57 {
58 in_part = (int)p;
59 break;
60 }
61 }
62
63 if(in_part < 0) return; /* Outside partition — no Wii junk reconstruction needed */
64
65 uint64_t group_idx = phys_group - regions[in_part].start_sector;
66 uint64_t group_disc_off = phys_group * WII_GROUP_SIZE;
67
68 for(uint64_t off = 0; off < WII_GROUP_DATA_SIZE; off += WII_SECTOR_SIZE)
69 {
70 uint64_t disc_off = group_disc_off + WII_GROUP_HASH_SIZE + off;
71
72 /* Look up this user data sector in the junk map */
73 const NgcwJunkEntry *entries = (const NgcwJunkEntry *)ctx->ngcw_junk_entries;
74 int lo = 0;
75 int hi = (int)ctx->ngcw_junk_entry_count - 1;
76 int found = -1;
77
78 while(lo <= hi)
79 {
80 int mid = lo + (hi - lo) / 2;
81 uint64_t entry_end = entries[mid].offset + entries[mid].length;
82
83 if(disc_off >= entry_end)
84 lo = mid + 1;
85 else if(disc_off < entries[mid].offset)
86 hi = mid - 1;
87 else
88 {
89 found = mid;
90 break;
91 }
92 }
93
94 if(found < 0) continue; /* Not junk — leave stored data */
95
96 /* Junk found — regenerate using OBMAFS stream formula */
97 struct ngc_lfg_ctx lfg;
98 uint32_t seed_copy[NGC_LFG_SEED_SIZE];
99 memcpy(seed_copy, entries[found].seed, sizeof(seed_copy));
100 ngc_lfg_set_seed(&lfg, seed_copy);
101
102 uint64_t stream_pos = group_idx * WII_GROUP_DATA_SIZE + off;
103 size_t advance = (size_t)(stream_pos % WII_GROUP_SIZE);
104
105 if(advance > 0)
106 {
107 uint8_t discard[4096];
108 size_t adv = advance;
109
110 while(adv > 0)
111 {
112 size_t step = adv > sizeof(discard) ? sizeof(discard) : adv;
113 ngc_lfg_get_bytes(&lfg, discard, step);
114 adv -= step;
115 }
116 }
117
118 size_t chunk = WII_GROUP_DATA_SIZE - (size_t)off;
119
120 if(chunk > WII_SECTOR_SIZE) chunk = WII_SECTOR_SIZE;
121
122 ngc_lfg_get_bytes(&lfg, group_cache + WII_GROUP_HASH_SIZE + off, chunk);
123 }
124}
125
184AARU_EXPORT int32_t AARU_CALL aaruf_read_media_tag(void *context, uint8_t *data, const int32_t tag, uint32_t *length)
185{
186 const uint32_t initial_length = length == NULL ? 0U : *length;
187
188 TRACE("Entering aaruf_read_media_tag(%p, %p, %d, %u)", context, data, tag, initial_length);
189
190 mediaTagEntry *item;
191
192 if(context == NULL)
193 {
194 FATAL("Invalid context");
195 TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
197 }
198
199 if(length == NULL)
200 {
201 FATAL("Invalid length pointer");
202 TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
204 }
205
206 const aaruformat_context *ctx = context;
207
208 // Not a libaaruformat context
209 if(ctx->magic != AARU_MAGIC)
210 {
211 FATAL("Invalid context");
212 TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
214 }
215
216 TRACE("Finding media tag %d", tag);
217 HASH_FIND_INT(ctx->mediaTags, &tag, item);
218
219 if(item == NULL)
220 {
221 TRACE("Media tag not found");
222 *length = 0;
223
224 TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_MEDIA_TAG_NOT_PRESENT");
226 }
227
228 if(data == NULL || *length < item->length)
229 {
230 TRACE("Buffer too small for media tag %d, required %u bytes", tag, item->length);
231 *length = item->length;
232
233 TRACE("Exiting aaruf_read_media_tag() = AARUF_ERROR_BUFFER_TOO_SMALL");
235 }
236
237 *length = item->length;
238 memcpy(data, item->data, item->length);
239
240 TRACE("Media tag %d read successfully, length %u", tag, *length);
241 TRACE("Exiting aaruf_read_media_tag() = AARUF_STATUS_OK");
242 return AARUF_STATUS_OK;
243}
244
352AARU_EXPORT int32_t AARU_CALL aaruf_read_sector(void *context, const uint64_t sector_address, bool negative,
353 uint8_t *data, uint32_t *length, uint8_t *sector_status)
354{
355 const uint32_t initial_length = length == NULL ? 0U : *length;
356
357 TRACE("Entering aaruf_read_sector(%p, %" PRIu64 ", %d, %p, %u)", context, sector_address, negative, data,
358 initial_length);
359
360 aaruformat_context *ctx = NULL;
361 uint64_t offset = 0;
362 uint64_t block_offset = 0;
363 BlockHeader *block_header = NULL;
364 uint8_t *block = NULL;
365 size_t read_bytes = 0;
366 uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH];
367 size_t lzma_size = 0;
368 uint8_t *cmp_data = NULL;
369 int error_no = 0;
370 *sector_status = SectorStatusNotDumped;
371
372 if(context == NULL)
373 {
374 FATAL("Invalid context");
375
376 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_AARUFORMAT");
378 }
379
380 ctx = context;
381
382 if(length == NULL)
383 {
384 FATAL("Invalid length pointer");
385
386 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
388 }
389
390 // Not a libaaruformat context
391 if(ctx->magic != AARU_MAGIC)
392 {
393 FATAL("Invalid context");
394
395 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_AARUFORMAT");
397 }
398
399 // Flux-only images carry no DDT; sector reads cannot be served.
400 if(ctx->no_user_data_ddt)
401 {
402 *sector_status = SectorStatusNotDumped;
403 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_USER_DATA_NOT_PRESENT (flux-only image)");
405 }
406
407 if(negative && sector_address > ctx->user_data_ddt_header.negative)
408 {
409 FATAL("Sector address out of bounds");
410
411 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
413 }
414
415 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
416 {
417 FATAL("Sector address out of bounds");
418
419 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
421 }
422
423 if(ctx->ddt_version == 1)
424 {
425 if(negative)
426 {
427 FATAL("Negative sector addresses not supported in this image");
429 }
430
431 error_no = decode_ddt_entry_v1(ctx, sector_address, &offset, &block_offset, sector_status);
432 }
433 else if(ctx->ddt_version == 2)
434 error_no = decode_ddt_entry_v2(ctx, sector_address, negative, &offset, &block_offset, sector_status);
435
436 if(error_no != AARUF_STATUS_OK)
437 {
438 FATAL("Error %d decoding DDT entry", error_no);
439
440 TRACE("Exiting aaruf_read_sector() = %d", error_no);
441 return error_no;
442 }
443
444 // Partially written image... as we can't know the real sector size just assume it's common :/
445 if(*sector_status == SectorStatusNotDumped)
446 {
447 *length = ctx->image_info.SectorSize;
448
449 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_SECTOR_NOT_DUMPED");
451 }
452
453 // NGCW: SectorStatusGenerable — regenerate junk from seed, no block data exists
454 if(*sector_status == SectorStatusGenerable && (ctx->header.mediaType == GOD || ctx->header.mediaType == WOD))
455 {
456 if(!ctx->ngcw_junk_initialized)
457 {
459 ctx->ngcw_junk_initialized = true;
460 }
461
462 *length = ctx->image_info.SectorSize;
463
464 if(data == NULL)
465 {
466 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_BUFFER_TOO_SMALL (generable, NULL data)");
468 }
469
470 if(ctx->ngcw_junk_entries != NULL)
471 {
472 uint64_t disc_offset = sector_address * (uint64_t)ctx->image_info.SectorSize;
473
475 disc_offset, data, *length) == 0)
476 {
477 if(ctx->header.mediaType == GOD)
478 {
479 *sector_status = SectorStatusDumped;
480 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (GOD generable)");
481 return AARUF_STATUS_OK;
482 }
483
484 // WOD: regenerated junk needs Wii re-encryption.
485 // We have the plaintext in the data buffer — do re-encryption now and return.
487 {
488 wii_lazy_init(ctx);
489 ctx->wii_encryption_initialized = true;
490 }
491
492 if(ctx->wii_partition_regions != NULL && ctx->wii_encrypted_group_cache != NULL &&
494 {
495 const uint8_t *part_key = wii_get_sector_key((const WiiPartitionRegion *)ctx->wii_partition_regions,
496 ctx->wii_partition_region_count, sector_address);
497
498 if(part_key != NULL)
499 {
500 uint64_t phys_group = sector_address / WII_LOGICAL_PER_GROUP;
501 uint32_t slice_index = (uint32_t)(sector_address % WII_LOGICAL_PER_GROUP);
502
503 if(!ctx->wii_cache_valid || ctx->wii_cached_physical_group != phys_group)
504 {
505 uint64_t first_logical = phys_group * WII_LOGICAL_PER_GROUP;
506
507 ctx->wii_building_crypto_block = true;
508
509 for(uint32_t s = 0; s < WII_LOGICAL_PER_GROUP; s++)
510 {
511 uint64_t logical = first_logical + s;
512
513 if(logical == sector_address)
514 {
515 memcpy(ctx->wii_encrypted_group_cache + s * (*length), data, *length);
516 }
517 else
518 {
519 uint32_t s_len = *length;
520 uint8_t s_status = 0;
521 int32_t s_ret = aaruf_read_sector(context, logical, false,
522 ctx->wii_encrypted_group_cache + s * s_len,
523 &s_len, &s_status);
524
525 if(s_ret != AARUF_STATUS_OK)
526 memset(ctx->wii_encrypted_group_cache + s * (*length), 0, *length);
527 }
528 }
529
530 ctx->wii_building_crypto_block = false;
531
532 // Reconstruct junk in user data area
534
538 ctx->wii_cached_physical_group = phys_group;
539 ctx->wii_cache_valid = true;
540 }
541
542 memcpy(data, ctx->wii_encrypted_group_cache + slice_index * (*length), *length);
543 }
544 }
545
546 *sector_status = SectorStatusDumped;
547 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (WOD generable re-encrypted)");
548 return AARUF_STATUS_OK;
549 }
550 else
551 {
552 // Not found in junk map — zero-fill
553 memset(data, 0, *length);
554 *sector_status = SectorStatusDumped;
555 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (generable not in map)");
556 return AARUF_STATUS_OK;
557 }
558 }
559 else
560 {
561 // No junk map loaded — zero-fill
562 memset(data, 0, *length);
563 *sector_status = SectorStatusDumped;
564 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (no junk map)");
565 return AARUF_STATUS_OK;
566 }
567 }
568
569 // Check if block header is cached
570 TRACE("Checking if block header is cached");
571 block_header = find_in_cache_uint64(&ctx->block_header_cache, block_offset);
572
573 // Read block header
574 if(block_header == NULL)
575 {
576 TRACE("Allocating memory for block header");
577 block_header = malloc(sizeof(BlockHeader));
578 if(block_header == NULL)
579 {
580 FATAL("Not enough memory for block header");
581
582 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
584 }
585
586 TRACE("Reading block header");
587 if(aaruf_fseek(ctx->imageStream, (aaru_off_t)block_offset, SEEK_SET) != 0)
588 {
589 FATAL("Could not seek to block header");
590 free(block_header);
591
592 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
594 }
595
596 read_bytes = fread(block_header, 1, sizeof(BlockHeader), ctx->imageStream);
597
598 if(read_bytes != sizeof(BlockHeader))
599 {
600 FATAL("Error reading block header");
601 free(block_header);
602
603 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
605 }
606
607 TRACE("Adding block header to cache");
608 add_to_cache_uint64(&ctx->block_header_cache, block_offset, block_header, sizeof(BlockHeader));
609 }
610 else if(aaruf_fseek(ctx->imageStream, (aaru_off_t)(block_offset + sizeof(BlockHeader)), SEEK_SET) != 0)
611 {
612 FATAL("Could not seek past cached block header");
613
614 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
616 }
617
618 /* Sanity check: if the cached/read block header looks corrupt, skip directly to EC recovery.
619 * A corrupt header will have garbage sectorSize, compression, or identifier fields. */
620 if(block_header->identifier != DataBlock ||
621 block_header->sectorSize == 0 || block_header->sectorSize > 65536)
622 {
623 TRACE("Block header at offset %" PRIu64 " appears corrupt (id=0x%08X sectorSize=%u)",
624 block_offset, block_header->identifier, block_header->sectorSize);
625 goto ec_try_recovery;
626 }
627
628 if(data == NULL || *length < block_header->sectorSize)
629 {
630 TRACE("Buffer too small for sector, required %u bytes", block_header->sectorSize);
631 *length = block_header->sectorSize;
632
633 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_BUFFER_TOO_SMALL");
635 }
636
637 // Check if block is cached
638 TRACE("Checking if block is cached");
639 block = find_in_cache_uint64(&ctx->block_cache, block_offset);
640
641 if(block != NULL)
642 {
643 TRACE("Getting data from cache");
644 memcpy(data, block + offset * block_header->sectorSize, block_header->sectorSize);
645 *length = block_header->sectorSize;
646
647 // PS3 re-encryption: if stored decrypted, re-encrypt for caller
648 if(*sector_status == SectorStatusUnencrypted &&
649 (ctx->header.mediaType == PS3DVD || ctx->header.mediaType == PS3BD))
650 {
652 {
653 ps3_lazy_init(ctx);
654 ctx->ps3_encryption_initialized = true;
655 }
656
657 if(ctx->ps3_disc_key != NULL && ctx->ps3_plaintext_regions != NULL &&
659 ctx->ps3_plaintext_region_count, sector_address))
660 {
661 ps3_encrypt_sector(ctx->ps3_disc_key, sector_address, data, *length);
662 }
663
664 *sector_status = SectorStatusDumped;
665 }
666
667 // Wii U re-encryption: if stored decrypted, re-encrypt for caller
668 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD &&
670 {
672 {
673 wiiu_lazy_init(ctx);
674 ctx->wiiu_encryption_initialized = true;
675 }
676
677 if(ctx->wiiu_partition_regions != NULL && ctx->wiiu_encrypted_block_cache != NULL)
678 {
679 const uint8_t *part_key = wiiu_get_sector_key((const WiiuPartitionRegion *)ctx->wiiu_partition_regions,
680 ctx->wiiu_partition_region_count, sector_address);
681
682 if(part_key != NULL)
683 {
684 uint64_t phys_sector = sector_address / WIIU_LOGICAL_PER_PHYSICAL;
685 uint32_t slice_index = (uint32_t)(sector_address % WIIU_LOGICAL_PER_PHYSICAL);
686
687 if(!ctx->wiiu_cache_valid || ctx->wiiu_cached_physical_sector != phys_sector)
688 {
689 uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
690
691 // Read all 16 logical sectors via aaruf_read_sector with recursion guard
692 ctx->wiiu_building_crypto_block = true;
693
694 for(uint32_t s = 0; s < WIIU_LOGICAL_PER_PHYSICAL; s++)
695 {
696 uint64_t logical = first_logical + s;
697
698 if(logical == sector_address)
699 {
700 // Current sector is already in data buffer
701 memcpy(ctx->wiiu_encrypted_block_cache + s * (*length), data, *length);
702 }
703 else
704 {
705 uint32_t s_len = *length;
706 uint8_t s_status = 0;
707 int32_t s_ret =
708 aaruf_read_sector(context, logical, false,
709 ctx->wiiu_encrypted_block_cache + s * s_len, &s_len, &s_status);
710
711 if(s_ret != AARUF_STATUS_OK)
712 memset(ctx->wiiu_encrypted_block_cache + s * (*length), 0, *length);
713 }
714 }
715
716 ctx->wiiu_building_crypto_block = false;
717
720 ctx->wiiu_cached_physical_sector = phys_sector;
721 ctx->wiiu_cache_valid = true;
722 }
723
724 memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * (*length), *length);
725 }
726 }
727
728 *sector_status = SectorStatusDumped;
729 }
730
731 // Wii re-encryption: if stored decrypted, re-encrypt for caller
732 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WOD && !ctx->wii_building_crypto_block)
733 {
735 {
736 wii_lazy_init(ctx);
737 ctx->wii_encryption_initialized = true;
738 }
739
740 if(!ctx->ngcw_junk_initialized)
741 {
743 ctx->ngcw_junk_initialized = true;
744 }
745
746 if(ctx->wii_partition_regions != NULL && ctx->wii_encrypted_group_cache != NULL)
747 {
748 const uint8_t *part_key = wii_get_sector_key((const WiiPartitionRegion *)ctx->wii_partition_regions,
749 ctx->wii_partition_region_count, sector_address);
750
751 if(part_key != NULL)
752 {
753 uint64_t phys_group = sector_address / WII_LOGICAL_PER_GROUP;
754 uint32_t slice_index = (uint32_t)(sector_address % WII_LOGICAL_PER_GROUP);
755
756 if(!ctx->wii_cache_valid || ctx->wii_cached_physical_group != phys_group)
757 {
758 uint64_t first_logical = phys_group * WII_LOGICAL_PER_GROUP;
759
760 ctx->wii_building_crypto_block = true;
761
762 for(uint32_t s = 0; s < WII_LOGICAL_PER_GROUP; s++)
763 {
764 uint64_t logical = first_logical + s;
765
766 if(logical == sector_address)
767 {
768 memcpy(ctx->wii_encrypted_group_cache + s * (*length), data, *length);
769 }
770 else
771 {
772 uint32_t s_len = *length;
773 uint8_t s_status = 0;
774 int32_t s_ret =
775 aaruf_read_sector(context, logical, false,
776 ctx->wii_encrypted_group_cache + s * s_len, &s_len, &s_status);
777
778 if(s_ret != AARUF_STATUS_OK)
779 memset(ctx->wii_encrypted_group_cache + s * (*length), 0, *length);
780 }
781 }
782
783 ctx->wii_building_crypto_block = false;
784
785 // Reconstruct junk in user data area
787
791 ctx->wii_cached_physical_group = phys_group;
792 ctx->wii_cache_valid = true;
793 }
794
795 memcpy(data, ctx->wii_encrypted_group_cache + slice_index * (*length), *length);
796 }
797 }
798
799 *sector_status = SectorStatusDumped;
800 }
801
802 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK");
803 return AARUF_STATUS_OK;
804 }
805
806 // Decompress block
807 switch(block_header->compression)
808 {
809 case kCompressionNone:
810 TRACE("Allocating memory for block");
811 block = (uint8_t *)malloc(block_header->length);
812 if(block == NULL)
813 {
814 FATAL("Not enough memory for block");
815
816 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
818 }
819
820 TRACE("Reading block into memory");
821 read_bytes = fread(block, 1, block_header->length, ctx->imageStream);
822
823 if(read_bytes != block_header->length)
824 {
825 FATAL("Could not read block");
826 free(block);
827
828 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_BLOCK");
830 }
831
832 break;
833 case kCompressionLzma:
834 if(block_header->cmpLength <= LZMA_PROPERTIES_LENGTH || block_header->length == 0)
835 {
836 FATAL("Invalid LZMA block lengths (cmpLength=%u, length=%u)", block_header->cmpLength,
837 block_header->length);
838
839 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
840 goto ec_try_recovery;
841 }
842
843 lzma_size = block_header->cmpLength - LZMA_PROPERTIES_LENGTH;
844 TRACE("Allocating memory for compressed data of size %zu bytes", lzma_size);
845 cmp_data = malloc(lzma_size);
846
847 if(cmp_data == NULL)
848 {
849 FATAL("Cannot allocate memory for block...");
850
851 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
853 }
854
855 TRACE("Allocating memory for block of size %zu bytes", block_header->length);
856 block = malloc(block_header->length);
857 if(block == NULL)
858 {
859 FATAL("Cannot allocate memory for block...");
860 free(cmp_data);
861
862 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
864 }
865
866 read_bytes = fread(lzma_properties, 1, LZMA_PROPERTIES_LENGTH, ctx->imageStream);
867
868 if(read_bytes != LZMA_PROPERTIES_LENGTH)
869 {
870 FATAL("Could not read LZMA properties...");
871 free(block);
872 free(cmp_data);
873
874 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
875 goto ec_try_recovery;
876 }
877
878 read_bytes = fread(cmp_data, 1, lzma_size, ctx->imageStream);
879 if(read_bytes != lzma_size)
880 {
881 FATAL("Could not read compressed block...");
882 free(cmp_data);
883 free(block);
884
885 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
886 goto ec_try_recovery;
887 }
888
889 TRACE("Decompressing block of size %zu bytes", block_header->length);
890 read_bytes = block_header->length;
891 error_no = aaruf_lzma_decode_buffer(block, &read_bytes, cmp_data, &lzma_size, lzma_properties,
893
894 if(error_no != 0)
895 {
896 FATAL("Got error %d from LZMA...", error_no);
897 free(cmp_data);
898 free(block);
899
900 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
901 goto ec_try_recovery;
902 }
903
904 if(read_bytes != block_header->length)
905 {
906 FATAL("Error decompressing block, should be {0} bytes but got {1} bytes...");
907 free(cmp_data);
908 free(block);
909
910 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
911 goto ec_try_recovery;
912 }
913
914 free(cmp_data);
915
916 break;
917 case kCompressionZstd:
918 if(block_header->cmpLength == 0 || block_header->length == 0)
919 {
920 FATAL("Invalid zstd block lengths (cmpLength=%u, length=%u)", block_header->cmpLength,
921 block_header->length);
922 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
923 goto ec_try_recovery;
924 }
925
926 TRACE("Allocating memory for block of size %zu bytes", block_header->length);
927 block = (uint8_t *)malloc(block_header->length);
928 if(block == NULL)
929 {
930 FATAL("Not enough memory for block");
931 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
933 }
934
935 TRACE("Allocating memory for compressed data of size %zu bytes", block_header->cmpLength);
936 cmp_data = malloc(block_header->cmpLength);
937 if(cmp_data == NULL)
938 {
939 FATAL("Not enough memory for compressed data");
940 free(block);
941 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
943 }
944
945 aaruf_fseek(ctx->imageStream, (aaru_off_t)(block_offset + sizeof(BlockHeader)), SEEK_SET);
946
947 read_bytes = fread(cmp_data, 1, block_header->cmpLength, ctx->imageStream);
948 if(read_bytes != block_header->cmpLength)
949 {
950 FATAL("Could not read compressed block");
951 free(cmp_data);
952 free(block);
953 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
954 goto ec_try_recovery;
955 }
956
957 read_bytes = aaruf_zstd_decode_buffer(block, block_header->length, cmp_data, block_header->cmpLength);
958 if(read_bytes != block_header->length)
959 {
960 FATAL("Error decompressing zstd block, expected %u bytes got %zu", block_header->length, read_bytes);
961 free(cmp_data);
962 free(block);
963 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
964 goto ec_try_recovery;
965 }
966
967 free(cmp_data);
968
969 break;
970 case kCompressionFlac:
971 TRACE("Allocating memory for compressed data of size %zu bytes", block_header->cmpLength);
972 cmp_data = malloc(block_header->cmpLength);
973
974 if(cmp_data == NULL)
975 {
976 FATAL("Cannot allocate memory for block...");
977
978 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
980 }
981
982 TRACE("Allocating memory for block of size %zu bytes", block_header->length);
983 block = malloc(block_header->length);
984 if(block == NULL)
985 {
986 FATAL("Cannot allocate memory for block...");
987 free(cmp_data);
988
989 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
991 }
992
993 TRACE("Reading compressed data into memory");
994 read_bytes = fread(cmp_data, 1, block_header->cmpLength, ctx->imageStream);
995 if(read_bytes != block_header->cmpLength)
996 {
997 FATAL("Could not read compressed block...");
998 free(cmp_data);
999 free(block);
1000
1001 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
1002 goto ec_try_recovery;
1003 }
1004
1005 TRACE("Decompressing block of size %zu bytes", block_header->length);
1006 read_bytes =
1007 aaruf_flac_decode_redbook_buffer(block, block_header->length, cmp_data, block_header->cmpLength);
1008
1009 if(read_bytes != block_header->length)
1010 {
1011 FATAL("Error decompressing block, should be {0} bytes but got {1} bytes...");
1012 free(cmp_data);
1013 free(block);
1014
1015 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
1016 goto ec_try_recovery;
1017 }
1018
1019 free(cmp_data);
1020
1021 break;
1022 default:
1023 FATAL("Unsupported compression %d", block_header->compression);
1024 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_UNSUPPORTED_COMPRESSION");
1025 goto ec_try_recovery;
1026 }
1027
1028 // Add block to cache
1029 TRACE("Adding block to cache");
1030 add_to_cache_uint64(&ctx->block_cache, block_offset, block, block_header->length);
1031
1032 memcpy(data, block + offset * block_header->sectorSize, block_header->sectorSize);
1033 *length = block_header->sectorSize;
1034
1035 // PS3 re-encryption: if stored decrypted, re-encrypt for caller
1036 if(*sector_status == SectorStatusUnencrypted && (ctx->header.mediaType == PS3DVD || ctx->header.mediaType == PS3BD))
1037 {
1039 {
1040 ps3_lazy_init(ctx);
1041 ctx->ps3_encryption_initialized = true;
1042 }
1043
1044 if(ctx->ps3_disc_key != NULL && ctx->ps3_plaintext_regions != NULL &&
1046 ctx->ps3_plaintext_region_count, sector_address))
1047 {
1048 ps3_encrypt_sector(ctx->ps3_disc_key, sector_address, data, *length);
1049 }
1050
1051 *sector_status = SectorStatusDumped;
1052 }
1053
1054 // Wii U re-encryption: if stored decrypted, re-encrypt for caller
1055 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD && !ctx->wiiu_building_crypto_block)
1056 {
1058 {
1059 wiiu_lazy_init(ctx);
1060 ctx->wiiu_encryption_initialized = true;
1061 }
1062
1063 if(ctx->wiiu_partition_regions != NULL && ctx->wiiu_encrypted_block_cache != NULL)
1064 {
1065 const uint8_t *part_key = wiiu_get_sector_key((const WiiuPartitionRegion *)ctx->wiiu_partition_regions,
1066 ctx->wiiu_partition_region_count, sector_address);
1067
1068 if(part_key != NULL)
1069 {
1070 uint64_t phys_sector = sector_address / WIIU_LOGICAL_PER_PHYSICAL;
1071 uint32_t slice_index = (uint32_t)(sector_address % WIIU_LOGICAL_PER_PHYSICAL);
1072
1073 if(!ctx->wiiu_cache_valid || ctx->wiiu_cached_physical_sector != phys_sector)
1074 {
1075 uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
1076
1077 // Read all 16 logical sectors via aaruf_read_sector with recursion guard
1078 ctx->wiiu_building_crypto_block = true;
1079
1080 for(uint32_t s = 0; s < WIIU_LOGICAL_PER_PHYSICAL; s++)
1081 {
1082 uint64_t logical = first_logical + s;
1083
1084 if(logical == sector_address)
1085 {
1086 // Current sector is already in data buffer
1087 memcpy(ctx->wiiu_encrypted_block_cache + s * (*length), data, *length);
1088 }
1089 else
1090 {
1091 uint32_t s_len = *length;
1092 uint8_t s_status = 0;
1093 int32_t s_ret =
1094 aaruf_read_sector(context, logical, false, ctx->wiiu_encrypted_block_cache + s * s_len,
1095 &s_len, &s_status);
1096
1097 if(s_ret != AARUF_STATUS_OK)
1098 memset(ctx->wiiu_encrypted_block_cache + s * (*length), 0, *length);
1099 }
1100 }
1101
1102 ctx->wiiu_building_crypto_block = false;
1103
1105 ctx->wiiu_cached_physical_sector = phys_sector;
1106 ctx->wiiu_cache_valid = true;
1107 }
1108
1109 memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * (*length), *length);
1110 }
1111 }
1112
1113 *sector_status = SectorStatusDumped;
1114 }
1115
1116 // Wii re-encryption: if stored decrypted, re-encrypt for caller
1117 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WOD && !ctx->wii_building_crypto_block)
1118 {
1120 {
1121 wii_lazy_init(ctx);
1122 ctx->wii_encryption_initialized = true;
1123 }
1124
1125 if(!ctx->ngcw_junk_initialized)
1126 {
1128 ctx->ngcw_junk_initialized = true;
1129 }
1130
1131 if(ctx->wii_partition_regions != NULL && ctx->wii_encrypted_group_cache != NULL)
1132 {
1133 const uint8_t *part_key = wii_get_sector_key((const WiiPartitionRegion *)ctx->wii_partition_regions,
1134 ctx->wii_partition_region_count, sector_address);
1135
1136 if(part_key != NULL)
1137 {
1138 uint64_t phys_group = sector_address / WII_LOGICAL_PER_GROUP;
1139 uint32_t slice_index = (uint32_t)(sector_address % WII_LOGICAL_PER_GROUP);
1140
1141 if(!ctx->wii_cache_valid || ctx->wii_cached_physical_group != phys_group)
1142 {
1143 uint64_t first_logical = phys_group * WII_LOGICAL_PER_GROUP;
1144
1145 ctx->wii_building_crypto_block = true;
1146
1147 for(uint32_t s = 0; s < WII_LOGICAL_PER_GROUP; s++)
1148 {
1149 uint64_t logical = first_logical + s;
1150
1151 if(logical == sector_address)
1152 {
1153 memcpy(ctx->wii_encrypted_group_cache + s * (*length), data, *length);
1154 }
1155 else
1156 {
1157 uint32_t s_len = *length;
1158 uint8_t s_status = 0;
1159 int32_t s_ret = aaruf_read_sector(
1160 context, logical, false, ctx->wii_encrypted_group_cache + s * s_len, &s_len, &s_status);
1161
1162 if(s_ret != AARUF_STATUS_OK)
1163 memset(ctx->wii_encrypted_group_cache + s * (*length), 0, *length);
1164 }
1165 }
1166
1167 ctx->wii_building_crypto_block = false;
1168
1169 // Reconstruct junk in user data area
1171
1175 ctx->wii_cached_physical_group = phys_group;
1176 ctx->wii_cache_valid = true;
1177 }
1178
1179 memcpy(data, ctx->wii_encrypted_group_cache + slice_index * (*length), *length);
1180 }
1181 }
1182
1183 *sector_status = SectorStatusDumped;
1184 }
1185
1186 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK");
1187 return AARUF_STATUS_OK;
1188
1189 /* Erasure coding recovery: attempt to reconstruct a block that failed
1190 * decompression due to on-disk corruption. ec_recover_data_block()
1191 * reads the stripe, RS-decodes the erased shard, decompresses it,
1192 * and extracts the requested sector. */
1193ec_try_recovery:
1195 {
1196 TRACE("Attempting erasure coding recovery for block at offset %" PRIu64, block_offset);
1197 int32_t rc = ec_recover_data_block(ctx, block_offset, offset, data, length, *sector_status);
1198 if(rc == AARUF_STATUS_OK)
1199 {
1200 TRACE("Erasure coding recovery succeeded");
1201 return AARUF_STATUS_OK;
1202 }
1203 TRACE("Erasure coding recovery failed: %d", rc);
1204 }
1205
1206 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
1208}
1209
1282AARU_EXPORT int32_t AARU_CALL aaruf_read_track_sector(void *context, uint8_t *data, const uint64_t sector_address,
1283 uint32_t *length, const uint8_t track, uint8_t *sector_status)
1284{
1285 const uint32_t initial_length = length == NULL ? 0U : *length;
1286
1287 TRACE("Entering aaruf_read_track_sector(%p, %p, %" PRIu64 ", %u, %d)", context, data, sector_address,
1288 initial_length, track);
1289
1290 if(context == NULL)
1291 {
1292 FATAL("Invalid context");
1293
1294 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_NOT_AARUFORMAT");
1296 }
1297
1298 aaruformat_context *ctx = context;
1299
1300 if(length == NULL)
1301 {
1302 FATAL("Invalid length pointer");
1303
1304 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1306 }
1307
1308 // Not a libaaruformat context
1309 if(ctx->magic != AARU_MAGIC)
1310 {
1311 FATAL("Invalid context");
1312
1313 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_NOT_AARUFORMAT");
1315 }
1316
1318 {
1319 FATAL("Incorrect media type %d, expected OpticalDisc", ctx->image_info.MetadataMediaType);
1320
1321 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
1323 }
1324
1325 for(int i = 0; i < ctx->number_of_data_tracks; i++)
1326 if(ctx->data_tracks[i].sequence == track)
1327 return aaruf_read_sector(context, ctx->data_tracks[i].start + sector_address, false, data, length,
1328 sector_status);
1329
1330 TRACE("Track %d not found", track);
1331 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_TRACK_NOT_FOUND");
1333}
1334
1438AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_long(void *context, const uint64_t sector_address, bool negative,
1439 uint8_t *data, uint32_t *length, uint8_t *sector_status)
1440{
1441 const uint32_t initial_length = length == NULL ? 0U : *length;
1442
1443 TRACE("Entering aaruf_read_sector_long(%p, %" PRIu64 ", %d, %p, %u)", context, sector_address, data,
1444 initial_length);
1445
1446 const aaruformat_context *ctx = NULL;
1447 uint32_t bare_length = 0;
1448 uint32_t tag_length = 0;
1449 uint8_t *bare_data = NULL;
1450 int32_t res = 0;
1451 int32_t query_status;
1452 TrackEntry trk;
1453 int i = 0;
1454 bool trk_found = false;
1455
1456 if(context == NULL)
1457 {
1458 FATAL("Invalid context");
1459
1460 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_AARUFORMAT");
1462 }
1463
1464 ctx = context;
1465
1466 if(length == NULL)
1467 {
1468 FATAL("Invalid length pointer");
1469
1470 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1472 }
1473
1474 // Not a libaaruformat context
1475 if(ctx->magic != AARU_MAGIC)
1476 {
1477 FATAL("Invalid context");
1478
1479 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_AARUFORMAT");
1481 }
1482
1483 // Flux-only images carry no DDT; sector reads cannot be served.
1484 if(ctx->no_user_data_ddt)
1485 {
1486 if(sector_status != NULL) *sector_status = SectorStatusNotDumped;
1487 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_USER_DATA_NOT_PRESENT (flux-only image)");
1489 }
1490
1491 if(negative && sector_address > ctx->user_data_ddt_header.negative)
1492 {
1493 FATAL("Sector address out of bounds");
1494
1495 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
1497 }
1498
1499 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
1500 {
1501 FATAL("Sector address out of bounds");
1502
1503 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
1505 }
1506
1507 uint64_t corrected_sector_address = sector_address;
1508
1509 // Calculate positive or negative sector
1510 if(negative)
1511 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
1512 else
1513 corrected_sector_address += ctx->user_data_ddt_header.negative;
1514
1515 // LBA as encoded in a CD sector header (lead-in sectors are negative)
1516 const int64_t signed_lba = negative ? -(int64_t)sector_address : (int64_t)sector_address;
1517
1518 switch(ctx->image_info.MetadataMediaType)
1519 {
1520 case OpticalDisc:
1521 if(ctx->image_info.MediaType == DVDROM || ctx->image_info.MediaType == PS2DVD ||
1522 ctx->image_info.MediaType == SACD || ctx->image_info.MediaType == PS3DVD ||
1523 ctx->image_info.MediaType == DVDR || ctx->image_info.MediaType == DVDRW ||
1524 ctx->image_info.MediaType == DVDPR || ctx->image_info.MediaType == DVDPRW ||
1528 ctx->image_info.MediaType == Nuon)
1529 {
1530 if(ctx->sector_id == NULL || ctx->sector_ied == NULL || ctx->sector_cpr_mai == NULL ||
1531 ctx->sector_edc == NULL)
1532 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1533
1534 if(*length < 2064 || data == NULL)
1535 {
1536 *length = 2064;
1537 FATAL("Buffer too small for sector, required %u bytes", *length);
1538
1539 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1541 }
1542
1543 bare_length = 0;
1544 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1545
1546 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1547 {
1548 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1549 return query_status;
1550 }
1551
1552 if(bare_length == 0)
1553 {
1554 FATAL("Invalid bare sector length (0)");
1555
1556 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1558 }
1559
1560 TRACE("Allocating memory for bare data");
1561 bare_data = (uint8_t *)malloc(bare_length);
1562
1563 if(bare_data == NULL)
1564 {
1565 FATAL("Could not allocate memory for bare data");
1566
1567 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1569 }
1570
1571 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1572
1573 if(res != AARUF_STATUS_OK)
1574 {
1575 *length = 2064;
1576 free(bare_data);
1577
1578 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1579 return res;
1580 }
1581
1582 memcpy(data, ctx->sector_id + corrected_sector_address * 4, 4);
1583 memcpy(data + 4, ctx->sector_ied + corrected_sector_address * 2, 2);
1584 memcpy(data + 6, ctx->sector_cpr_mai + corrected_sector_address * 6, 6);
1585 memcpy(data + 12, bare_data, 2048);
1586 memcpy(data + 2060, ctx->sector_edc + corrected_sector_address * 4, 4);
1587
1588 *length = 2064;
1589
1590 free(bare_data);
1591 return AARUF_STATUS_OK;
1592 }
1593
1594 if(ctx->image_info.MediaType == GOD || ctx->image_info.MediaType == WOD)
1595 {
1596 if(ctx->sector_id == NULL || ctx->sector_ied == NULL || ctx->sector_cpr_mai == NULL ||
1597 ctx->sector_edc == NULL)
1598 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1599
1600 if(*length < 2064 || data == NULL)
1601 {
1602 *length = 2064;
1603 FATAL("Buffer too small for sector, required %u bytes", *length);
1604
1605 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1607 }
1608
1609 bare_length = 0;
1610 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1611
1612 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1613 {
1614 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1615 return query_status;
1616 }
1617
1618 if(bare_length == 0)
1619 {
1620 FATAL("Invalid bare sector length (0)");
1621
1622 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1624 }
1625
1626 TRACE("Allocating memory for bare data");
1627 bare_data = (uint8_t *)malloc(bare_length);
1628
1629 if(bare_data == NULL)
1630 {
1631 FATAL("Could not allocate memory for bare data");
1632
1633 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1635 }
1636
1637 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1638
1639 if(res != AARUF_STATUS_OK)
1640 {
1641 *length = 2064;
1642 free(bare_data);
1643
1644 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1645 return res;
1646 }
1647
1648 memcpy(data, ctx->sector_id + corrected_sector_address * 4, 4);
1649 memcpy(data + 4, ctx->sector_ied + corrected_sector_address * 2, 2);
1650 memcpy(data + 6, bare_data, 2048);
1651 memcpy(data + 2054, ctx->sector_cpr_mai + corrected_sector_address * 6, 6);
1652 memcpy(data + 2060, ctx->sector_edc + corrected_sector_address * 4, 4);
1653
1654 *length = 2064;
1655
1656 free(bare_data);
1657 return AARUF_STATUS_OK;
1658 }
1659
1660 if(ctx->image_info.MediaType == BDROM || ctx->image_info.MediaType == BDR ||
1661 ctx->image_info.MediaType == BDRE || ctx->image_info.MediaType == BDRXL ||
1662 ctx->image_info.MediaType == BDREXL || ctx->image_info.MediaType == UHDBD ||
1663 ctx->image_info.MediaType == XGD4 || ctx->image_info.MediaType == PS3BD ||
1665 {
1666 if(ctx->sector_edc == NULL) return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1667
1668 if(*length < 2052 || data == NULL)
1669 {
1670 *length = 2052;
1671 FATAL("Buffer too small for sector, required %u bytes", *length);
1672
1673 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1675 }
1676
1677 bare_length = 0;
1678 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1679
1680 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1681 {
1682 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1683 return query_status;
1684 }
1685
1686 if(bare_length == 0)
1687 {
1688 FATAL("Invalid bare sector length (0)");
1689
1690 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1692 }
1693
1694 TRACE("Allocating memory for bare data");
1695 bare_data = (uint8_t *)malloc(bare_length);
1696
1697 if(bare_data == NULL)
1698 {
1699 FATAL("Could not allocate memory for bare data");
1700
1701 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1703 }
1704
1705 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1706
1707 if(res != AARUF_STATUS_OK)
1708 {
1709 free(bare_data);
1710
1711 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1712 return res;
1713 }
1714
1715 memcpy(data, bare_data, 2048);
1716 memcpy(data + 2048, ctx->sector_edc + corrected_sector_address * 4, 4);
1717
1718 *length = 2052;
1719
1720 free(bare_data);
1721 return AARUF_STATUS_OK;
1722 }
1723
1724 if(*length < 2352 || data == NULL)
1725 {
1726 *length = 2352;
1727 FATAL("Buffer too small for sector, required %u bytes", *length);
1728
1729 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1731 }
1732
1733 if((ctx->sector_suffix == NULL || ctx->sector_prefix == NULL) &&
1734 (ctx->sector_suffix_ddt == NULL || ctx->sector_prefix_ddt == NULL) &&
1735 (ctx->sector_suffix_ddt2 == NULL || ctx->sector_prefix_ddt2 == NULL))
1736 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1737
1738 bare_length = 0;
1739 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1740
1741 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1742 {
1743 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1744 return query_status;
1745 }
1746
1747 if(bare_length == 0)
1748 {
1749 FATAL("Invalid bare sector length (0)");
1750
1751 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1753 }
1754
1755 TRACE("Allocating memory for bare data");
1756 bare_data = (uint8_t *)malloc(bare_length);
1757
1758 if(bare_data == NULL)
1759 {
1760 FATAL("Could not allocate memory for bare data");
1761
1762 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1764 }
1765
1766 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1767
1768 if(res != AARUF_STATUS_OK)
1769 {
1770 free(bare_data);
1771
1772 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1773 return res;
1774 }
1775
1776 trk_found = false;
1777
1778 for(i = 0; i < ctx->number_of_data_tracks; i++)
1779 if(sector_address >= ctx->data_tracks[i].start && sector_address <= ctx->data_tracks[i].end)
1780 {
1781 trk_found = true;
1782 trk = ctx->data_tracks[i];
1783 break;
1784 }
1785
1786 if(!trk_found)
1787 {
1788 FATAL("Track not found");
1789 free(bare_data);
1790
1791 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_TRACK_NOT_FOUND");
1793 }
1794
1795 switch(trk.type)
1796 {
1797 case kTrackTypeAudio:
1798 case kTrackTypeData:
1799 memcpy(data, bare_data, bare_length);
1800 *length = bare_length;
1801 free(bare_data);
1802 return res;
1803 case kTrackTypeCdMode1:
1804 memcpy(data + 16, bare_data, 2048);
1805
1806 if(ctx->sector_prefix_ddt2 != NULL)
1807 {
1808 const uint64_t prefix_ddt_entry = ctx->sector_prefix_ddt2[corrected_sector_address];
1809 const uint32_t prefix_status = prefix_ddt_entry >> 60;
1810 const uint64_t prefix_index = prefix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1811
1812 if(prefix_status == SectorStatusMode1Correct)
1813 {
1814 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, signed_lba);
1815 res = AARUF_STATUS_OK;
1816 }
1817 else if(prefix_status == SectorStatusNotDumped)
1819 else if(ctx->sector_prefix == NULL || (prefix_index + 1) * 16 > ctx->sector_prefix_length)
1820 {
1821 FATAL("Sector prefix index %" PRIu64 " outside stored prefix block", prefix_index);
1822 free(bare_data);
1823 *sector_status = SectorStatusErrored;
1824
1825 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_CANNOT_READ_BLOCK");
1827 }
1828 else
1829 memcpy(data, ctx->sector_prefix + prefix_index * 16, 16);
1830 }
1831 else if(ctx->sector_prefix != NULL)
1832 memcpy(data, ctx->sector_prefix + corrected_sector_address * 16, 16);
1833 else if(ctx->sector_prefix_ddt != NULL)
1834 {
1835 if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
1836 {
1837 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
1838 res = AARUF_STATUS_OK;
1839 }
1840 else if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
1842 else
1843 memcpy(data,
1845 ((ctx->sector_prefix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 16,
1846 16);
1847 }
1848 else
1849 {
1850 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
1851 free(bare_data);
1853 }
1854
1855 if(res != AARUF_STATUS_OK)
1856 {
1857 *length = 2352;
1858 free(bare_data);
1859 return res;
1860 }
1861
1862 if(ctx->sector_suffix_ddt2 != NULL)
1863 {
1864 const uint64_t suffix_ddt_entry = ctx->sector_suffix_ddt2[corrected_sector_address];
1865 const uint64_t suffix_status = suffix_ddt_entry >> 60;
1866 const uint64_t suffix_index = suffix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1867
1868 if(suffix_status == SectorStatusMode1Correct)
1869 {
1871 res = AARUF_STATUS_OK;
1872 }
1873 else if(suffix_status == SectorStatusNotDumped)
1875 else if(ctx->sector_suffix == NULL || (suffix_index + 1) * 288 > ctx->sector_suffix_length)
1876 {
1877 FATAL("Sector suffix index %" PRIu64 " outside stored suffix block", suffix_index);
1878 free(bare_data);
1879 *sector_status = SectorStatusErrored;
1880
1881 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_CANNOT_READ_BLOCK");
1883 }
1884 else
1885 memcpy(data + 2064, ctx->sector_suffix + suffix_index * 288, 288);
1886 }
1887 else if(ctx->sector_suffix != NULL)
1888 memcpy(data + 2064, ctx->sector_suffix + corrected_sector_address * 288, 288);
1889 else if(ctx->sector_suffix_ddt != NULL)
1890 {
1891 if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
1892 {
1894 res = AARUF_STATUS_OK;
1895 }
1896 else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
1898 else
1899 memcpy(data + 2064,
1901 ((ctx->sector_suffix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 288,
1902 288);
1903 }
1904 else
1905 {
1906 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
1907 free(bare_data);
1909 }
1910
1911 *length = 2352;
1912 free(bare_data);
1913 return res;
1917 if(ctx->sector_prefix_ddt2 != NULL)
1918 {
1919 const uint64_t prefix_ddt_entry = ctx->sector_prefix_ddt2[corrected_sector_address];
1920 const uint64_t prefix_status = prefix_ddt_entry >> 60;
1921 const uint64_t prefix_index = prefix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1922
1923 if(prefix_status == SectorStatusMode2Form1Ok || prefix_status == SectorStatusMode2Form2Ok)
1924 {
1925 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, signed_lba);
1926 res = AARUF_STATUS_OK;
1927 }
1928 else if(prefix_status == SectorStatusNotDumped)
1930 else if(ctx->sector_prefix == NULL || (prefix_index + 1) * 16 > ctx->sector_prefix_length)
1931 {
1932 FATAL("Sector prefix index %" PRIu64 " outside stored prefix block", prefix_index);
1933 free(bare_data);
1934 *sector_status = SectorStatusErrored;
1935
1936 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_CANNOT_READ_BLOCK");
1938 }
1939 else
1940 memcpy(data, ctx->sector_prefix + prefix_index * 16, 16);
1941 }
1942 else if(ctx->sector_prefix != NULL)
1943 memcpy(data, ctx->sector_prefix + corrected_sector_address * 16, 16);
1944 else if(ctx->sector_prefix_ddt != NULL)
1945 {
1946 if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
1947 {
1948 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
1949 res = AARUF_STATUS_OK;
1950 }
1951 else if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
1953 else
1954 memcpy(data,
1956 ((ctx->sector_prefix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 16,
1957 16);
1958 }
1959 else
1960 {
1961 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
1962 free(bare_data);
1964 }
1965
1966 if(res != AARUF_STATUS_OK)
1967 {
1968 *length = 2352;
1969 free(bare_data);
1970 return res;
1971 }
1972
1973 if(ctx->mode2_subheaders != NULL && ctx->sector_suffix_ddt2 != NULL)
1974 {
1975 memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
1976 const uint64_t suffix_ddt_entry = ctx->sector_suffix_ddt2[corrected_sector_address];
1977 const uint64_t suffix_status = suffix_ddt_entry >> 60;
1978 const uint64_t suffix_index = suffix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1979
1980 if(suffix_status == SectorStatusMode2Form1Ok)
1981 {
1982 memcpy(data + 24, bare_data, 2048);
1984 }
1985 else if(suffix_status == SectorStatusMode2Form2Ok ||
1986 suffix_status == SectorStatusMode2Form2NoCrc)
1987 {
1988 memcpy(data + 24, bare_data, 2324);
1989 if(suffix_status == SectorStatusMode2Form2Ok)
1991 else
1992 memset(data + 2348, 0, 4);
1993 }
1994 else if(suffix_status == SectorStatusNotDumped)
1996 else if(ctx->sector_suffix == NULL || (suffix_index + 1) * 288 > ctx->sector_suffix_length)
1997 {
1998 FATAL("Sector suffix index %" PRIu64 " outside stored suffix block", suffix_index);
1999 free(bare_data);
2000 *sector_status = SectorStatusErrored;
2001
2002 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_CANNOT_READ_BLOCK");
2004 }
2005 else
2006 {
2007 // Mode 2 where ECC/EDC failed — restore user data + stored suffix.
2008 // Check both subheader copies to match write path form detection.
2009 if((data[0x12] & 0x20) || (data[0x16] & 0x20))
2010 {
2011 // Form 2: 2324 bytes user data, 4 bytes EDC suffix
2012 memcpy(data + 24, bare_data, 2324);
2013 memcpy(data + 2348, ctx->sector_suffix + suffix_index * 288, 4);
2014 }
2015 else
2016 {
2017 // Form 1: 2048 bytes user data, 280 bytes EDC+ECC suffix
2018 memcpy(data + 24, bare_data, 2048);
2019 memcpy(data + 2072, ctx->sector_suffix + suffix_index * 288, 280);
2020 }
2021 }
2022 }
2023 else if(ctx->mode2_subheaders != NULL && ctx->sector_suffix_ddt != NULL)
2024 {
2025 memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
2026
2027 if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form1Ok)
2028 {
2029 memcpy(data + 24, bare_data, 2048);
2031 }
2032 else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2Ok ||
2033 (ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2NoCrc)
2034 {
2035 memcpy(data + 24, bare_data, 2324);
2036 if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2Ok)
2038 else
2039 memset(data + 2348, 0, 4);
2040 }
2041 else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
2043 else
2044 {
2045 // Mode 2 where ECC/EDC failed — restore user data + stored suffix.
2046 // Check both subheader copies to match write path form detection.
2047 const uint32_t sfx_index =
2048 (ctx->sector_suffix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1;
2049 if((data[0x12] & 0x20) || (data[0x16] & 0x20))
2050 {
2051 memcpy(data + 24, bare_data, 2324);
2052 memcpy(data + 2348, ctx->sector_suffix_corrected + sfx_index * 288, 4);
2053 }
2054 else
2055 {
2056 memcpy(data + 24, bare_data, 2048);
2057 memcpy(data + 2072, ctx->sector_suffix_corrected + sfx_index * 288, 280);
2058 }
2059 }
2060 }
2061 else if(ctx->mode2_subheaders != NULL)
2062 {
2063 memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
2064 memcpy(data + 24, bare_data, bare_length < 2328 ? bare_length : 2328);
2065 }
2066 else
2067 memcpy(data + 16, bare_data, bare_length < 2336 ? bare_length : 2336);
2068
2069 *length = 2352;
2070 free(bare_data);
2071 return res;
2072 default:
2073 FATAL("Invalid track type %d", trk.type);
2074 free(bare_data);
2075
2076 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INVALID_TRACK_FORMAT");
2078 }
2079 case BlockMedia:
2080 switch(ctx->image_info.MediaType)
2081 {
2082 case AppleFileWare:
2083 case AppleProfile:
2084 case AppleSonySS:
2085 case AppleSonyDS:
2086 case AppleWidget:
2087 case PriamDataTower:
2088 if(ctx->sector_subchannel == NULL)
2089 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
2090
2091 switch(ctx->image_info.MediaType)
2092 {
2093 case AppleFileWare:
2094 case AppleProfile:
2095 case AppleWidget:
2096 tag_length = 20;
2097 break;
2098 case AppleSonySS:
2099 case AppleSonyDS:
2100 tag_length = 12;
2101 break;
2102 case PriamDataTower:
2103 tag_length = 24;
2104 break;
2105 default:
2106 FATAL("Unsupported media type %d", ctx->image_info.MediaType);
2107
2108 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2110 }
2111
2112 bare_length = 512;
2113
2114 if(*length < tag_length + bare_length || data == NULL)
2115 {
2116 *length = tag_length + bare_length;
2117 FATAL("Buffer too small for sector, required %u bytes", *length);
2118
2119 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
2121 }
2122
2123 TRACE("Allocating memory for bare data of size %u bytes", bare_length);
2124 bare_data = malloc(bare_length);
2125
2126 if(bare_data == NULL)
2127 {
2128 FATAL("Could not allocate memory for bare data");
2129
2130 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2132 }
2133
2134 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
2135
2136 if(res != AARUF_STATUS_OK)
2137 {
2138 free(bare_data);
2139
2140 TRACE("Exiting aaruf_read_sector_long() = %d", res);
2141 return res;
2142 }
2143
2144 if(bare_length != 512)
2145 {
2146 FATAL("Bare data length is %u, expected 512", bare_length);
2147 free(bare_data);
2148
2149 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2151 }
2152
2153 memcpy(data + bare_length, ctx->sector_subchannel + corrected_sector_address * tag_length,
2154 tag_length);
2155 memcpy(data, bare_data, bare_length);
2156 *length = tag_length + bare_length;
2157
2158 free(bare_data);
2159
2160 TRACE("Exiting aaruf_read_sector_long() = AARUF_STATUS_OK");
2161 return AARUF_STATUS_OK;
2162 default:
2163 FATAL("Incorrect media type %d for long sector reading", ctx->image_info.MediaType);
2164
2165 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2167 }
2168 default:
2169 FATAL("Incorrect media type %d for long sector reading", ctx->image_info.MediaType);
2170
2171 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2173 }
2174}
2175
2295AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_tag(const void *context, const uint64_t sector_address,
2296 const bool negative, uint8_t *buffer, uint32_t *length,
2297 const int32_t tag)
2298{
2299 const uint32_t initial_length = length == NULL ? 0U : *length;
2300
2301 TRACE("Entering aaruf_read_sector_tag(%p, %" PRIu64 ", %d, %p, %u, %d)", context, sector_address, negative, buffer,
2302 initial_length, tag);
2303
2304 const aaruformat_context *ctx = NULL;
2305
2306 if(context == NULL)
2307 {
2308 FATAL("Invalid context");
2309
2310 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2312 }
2313
2314 ctx = context;
2315
2316 if(length == NULL)
2317 {
2318 FATAL("Invalid length pointer");
2319
2320 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2322 }
2323
2324 // Not a libaaruformat context
2325 if(ctx->magic != AARU_MAGIC)
2326 {
2327 FATAL("Invalid context");
2328
2329 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2331 }
2332
2333 // Flux-only images carry no DDT and therefore no per-sector tags.
2334 if(ctx->no_user_data_ddt)
2335 {
2336 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_USER_DATA_NOT_PRESENT (flux-only image)");
2338 }
2339
2340 if(negative && sector_address > ctx->user_data_ddt_header.negative)
2341 {
2342 FATAL("Sector address out of bounds");
2343
2344 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2346 }
2347
2348 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
2349 {
2350 FATAL("Sector address out of bounds");
2351
2352 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2354 }
2355
2356 uint64_t corrected_sector_address = sector_address;
2357
2358 // Calculate positive or negative sector
2359 if(negative)
2360 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
2361 else
2362 corrected_sector_address += ctx->user_data_ddt_header.negative;
2363
2364 switch(tag)
2365 {
2368 {
2369 FATAL("Invalid media type for tag");
2370 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2372 }
2373
2374 if(*length != 1 || buffer == NULL)
2375 {
2376 *length = 1;
2377 FATAL("Incorrect tag size");
2378 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2380 }
2381
2382 for(int i = 0; i < ctx->tracks_header.entries; i++)
2383 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2384 {
2385 buffer[0] = ctx->track_entries[i].flags;
2386 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2387 return AARUF_STATUS_OK;
2388 }
2389
2390 FATAL("Track not found");
2394 {
2395 FATAL("Invalid media type for tag");
2396 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2398 }
2399
2400 if(*length != 12 || buffer == NULL)
2401 {
2402 *length = 12;
2403 FATAL("Incorrect tag size");
2404 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2406 }
2407
2408 for(int i = 0; i < ctx->tracks_header.entries; i++)
2409 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2410 {
2411 memcpy(buffer, ctx->track_entries[i].isrc, 12);
2412 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2413 return AARUF_STATUS_OK;
2414 }
2415
2416 FATAL("Track not found");
2420 {
2421 FATAL("Invalid media type for tag");
2422 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2424 }
2425
2426 if(*length != 96 || buffer == NULL)
2427 {
2428 *length = 96;
2429 FATAL("Incorrect tag size");
2430 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2432 }
2433
2434 if(ctx->sector_subchannel == NULL)
2435 {
2436 FATAL("Sector tag not found");
2437 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2439 }
2440
2441 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 96, 96);
2442 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2443 return AARUF_STATUS_OK;
2444 case kSectorTagDvdCmi:
2446 {
2447 FATAL("Invalid media type for tag");
2448 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2450 }
2451
2452 if(*length != 1 || buffer == NULL)
2453 {
2454 *length = 1;
2455 FATAL("Incorrect tag size");
2456 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2458 }
2459
2460 if(ctx->sector_cpr_mai == NULL)
2461 {
2462 FATAL("Sector tag not found");
2463 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2465 }
2466
2467 memcpy(buffer, ctx->sector_cpr_mai + corrected_sector_address * 6, 1);
2468 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2469 return AARUF_STATUS_OK;
2472 {
2473 FATAL("Invalid media type for tag");
2474 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2476 }
2477
2478 if(*length != 1 || buffer == NULL)
2479 {
2480 *length = 1;
2481 FATAL("Incorrect tag size");
2482 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2484 }
2485
2486 if(ctx->sector_id == NULL)
2487 {
2488 FATAL("Sector tag not found");
2489 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2491 }
2492
2493 memcpy(buffer, ctx->sector_id + corrected_sector_address * 4, 1);
2494 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2495 return AARUF_STATUS_OK;
2498 {
2499 FATAL("Invalid media type for tag");
2500 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2502 }
2503
2504 if(*length != 3 || buffer == NULL)
2505 {
2506 *length = 3;
2507 FATAL("Incorrect tag size");
2508 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2510 }
2511
2512 if(ctx->sector_id == NULL)
2513 {
2514 FATAL("Sector tag not found");
2515 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2517 }
2518
2519 memcpy(buffer, ctx->sector_id + corrected_sector_address * 4 + 1, 3);
2520 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2521 return AARUF_STATUS_OK;
2524 {
2525 FATAL("Invalid media type for tag");
2526 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2528 }
2529
2530 if(*length != 2 || buffer == NULL)
2531 {
2532 *length = 2;
2533 FATAL("Incorrect tag size");
2534 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2536 }
2537
2538 if(ctx->sector_ied == NULL)
2539 {
2540 FATAL("Sector tag not found");
2541 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2543 }
2544
2545 memcpy(buffer, ctx->sector_ied + corrected_sector_address * 2, 2);
2546 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2547 return AARUF_STATUS_OK;
2550 {
2551 FATAL("Invalid media type for tag");
2552 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2554 }
2555
2556 if(*length != 4 || buffer == NULL)
2557 {
2558 *length = 4;
2559 FATAL("Incorrect tag size");
2560 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2562 }
2563
2564 if(ctx->sector_edc == NULL)
2565 {
2566 FATAL("Sector tag not found");
2567 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2569 }
2570
2571 memcpy(buffer, ctx->sector_edc + corrected_sector_address * 4, 4);
2572 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2573 return AARUF_STATUS_OK;
2576 {
2577 FATAL("Invalid media type for tag");
2578 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2580 }
2581
2582 if(*length != 5 || buffer == NULL)
2583 {
2584 *length = 5;
2585 FATAL("Incorrect tag size");
2586 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2588 }
2589
2590 if(ctx->sector_decrypted_title_key == NULL)
2591 {
2592 FATAL("Sector tag not found");
2593 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2595 }
2596
2597 memcpy(buffer, ctx->sector_decrypted_title_key + corrected_sector_address * 5, 5);
2598 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2599 return AARUF_STATUS_OK;
2602 {
2603 FATAL("Invalid media type for tag");
2604 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2606 }
2607
2608 if(*length != 12 || buffer == NULL)
2609 {
2610 *length = 12;
2611 FATAL("Incorrect tag size");
2612 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2614 }
2615
2616 if(ctx->sector_subchannel == NULL)
2617 {
2618 FATAL("Sector tag not found");
2619 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2621 }
2622
2623 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 12, 12);
2624 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2625 return AARUF_STATUS_OK;
2628 {
2629 FATAL("Invalid media type for tag");
2630 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2632 }
2633
2634 if(*length != 20 || buffer == NULL)
2635 {
2636 *length = 20;
2637 FATAL("Incorrect tag size");
2638 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2640 }
2641
2642 if(ctx->sector_subchannel == NULL)
2643 {
2644 FATAL("Sector tag not found");
2645 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2647 }
2648
2649 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 20, 20);
2650 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2651 return AARUF_STATUS_OK;
2654 {
2655 FATAL("Invalid media type for tag");
2656 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2658 }
2659
2660 if(*length != 24 || buffer == NULL)
2661 {
2662 *length = 24;
2663 FATAL("Incorrect tag size");
2664 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2666 }
2667
2668 if(ctx->sector_subchannel == NULL)
2669 {
2670 FATAL("Sector tag not found");
2671 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2673 }
2674
2675 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 24, 24);
2676 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2677 return AARUF_STATUS_OK;
2678 default:
2679 TRACE("Do not know how to read sector tag %d", tag);
2681 }
2682}
#define CD_DFIX_MASK
Mask for extracting positional index (lower 24 bits) in Compact Disc suffix/prefix deduplicated block...
Definition consts.h:116
#define LZMA_PROPERTIES_LENGTH
Size in bytes of the fixed LZMA properties header (lc/lp/pb + dictionary size).
Definition consts.h:86
#define AARU_MAGIC
Magic identifier for AaruFormat container (ASCII "AARUFRMT").
Definition consts.h:64
#define CD_XFIX_MASK
Mask for extracting correction / fix flags in Compact Disc suffix/prefix DDT entries.
Definition consts.h:104
#define AARU_CALL
Definition decls.h:46
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
int32_t aaruf_read_sector(void *context, 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:352
int32_t aaruf_read_media_tag(void *context, uint8_t *data, int32_t tag, uint32_t *length)
Reads a media tag from the AaruFormat image.
Definition read.c:184
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
#define AARU_EXPORT
Definition decls.h:55
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
size_t aaruf_zstd_decode_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size)
Decodes a Zstandard-compressed buffer.
Definition zstd.c:34
int32_t aaruf_read_track_sector(void *context, uint8_t *data, uint64_t sector_address, uint32_t *length, uint8_t track, uint8_t *sector_status)
Reads a sector from a specific track in the AaruFormat image.
Definition read.c:1282
int32_t aaruf_read_sector_tag(const void *context, uint64_t sector_address, bool negative, uint8_t *buffer, uint32_t *length, int32_t tag)
Reads a specific sector tag from the AaruFormat image.
Definition read.c:2295
int32_t aaruf_read_sector_long(void *context, 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:1438
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
@ DataBlock
Block containing data.
Definition enums.h:164
@ SectorStatusDumped
Sector(s) successfully dumped without error.
Definition enums.h:259
@ SectorStatusNotDumped
Sector(s) not yet acquired during image dumping.
Definition enums.h:258
@ SectorStatusGenerable
Content can be generated using a known algorithm.
Definition enums.h:269
@ SectorStatusUnencrypted
Content originally encrypted but stored decrypted in image.
Definition enums.h:268
@ SectorStatusMode2Form2NoCrc
Suffix matches MODE 2 Form 2 but CRC empty/missing.
Definition enums.h:264
@ SectorStatusMode1Correct
Valid MODE 1 data with regenerable suffix/prefix.
Definition enums.h:261
@ SectorStatusMode2Form2Ok
Suffix matches MODE 2 Form 2 with valid CRC.
Definition enums.h:263
@ SectorStatusErrored
Error during dumping; data may be incomplete or corrupt.
Definition enums.h:260
@ SectorStatusMode2Form1Ok
Suffix verified/regenerable for MODE 2 Form 1.
Definition enums.h:262
@ Correct
Sector(s) contain valid MODE 1 data with regenerable suffix/prefix.
Definition enums.h:211
@ Mode2Form2Ok
Sector suffix valid for MODE 2 Form 2 with correct CRC.
Definition enums.h:213
@ Mode2Form1Ok
Sector suffix valid for MODE 2 Form 1; regenerable.
Definition enums.h:212
@ NotDumped
Sector(s) have not yet been dumped.
Definition enums.h:210
@ Mode2Form2NoCrc
Sector suffix valid for MODE 2 Form 2 but CRC absent/empty.
Definition enums.h:214
@ OpticalDisc
Purely optical discs.
Definition enums.h:246
@ BlockMedia
Media that is physically block-based or abstracted like that.
Definition enums.h:247
@ kTrackTypeCdMode2Form2
Compact Disc Mode 2 Form 2 data track.
Definition enums.h:228
@ kTrackTypeData
Generic data track (not further specified).
Definition enums.h:224
@ kTrackTypeCdMode2Form1
Compact Disc Mode 2 Form 1 data track.
Definition enums.h:227
@ kTrackTypeAudio
Audio track.
Definition enums.h:223
@ kTrackTypeCdMode2Formless
Compact Disc Mode 2 (formless) data track.
Definition enums.h:226
@ kTrackTypeCdMode1
Compact Disc Mode 1 data track.
Definition enums.h:225
@ kCompressionLzma
LZMA compression.
Definition enums.h:34
@ kCompressionNone
Not compressed.
Definition enums.h:33
@ kCompressionZstd
Zstandard compression.
Definition enums.h:37
@ kCompressionFlac
FLAC compression.
Definition enums.h:35
int32_t ec_recover_data_block(aaruformat_context *ctx, uint64_t block_offset, uint64_t offset, uint8_t *data, uint32_t *length, uint8_t sector_status)
Attempt to recover a data block that failed decompression or CRC verification.
Definition erasure.c:1303
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:82
#define AARUF_ERROR_INCORRECT_MEDIA_TYPE
Operation incompatible with image media type.
Definition errors.h:51
#define AARUF_ERROR_USER_DATA_NOT_PRESENT
Image has no user-data DDT (e.g. flux-only image); sector data is unavailable.
Definition errors.h:76
#define AARUF_ERROR_TRACK_NOT_FOUND
Referenced track number not present.
Definition errors.h:52
#define AARUF_ERROR_CANNOT_READ_HEADER
Failed to read container header.
Definition errors.h:45
#define AARUF_ERROR_NOT_ENOUGH_MEMORY
Memory allocation failure (critical).
Definition errors.h:48
#define AARUF_ERROR_SECTOR_OUT_OF_BOUNDS
Requested logical sector outside media bounds.
Definition errors.h:44
#define AARUF_ERROR_INVALID_TRACK_FORMAT
Track metadata internally inconsistent or malformed.
Definition errors.h:54
#define AARUF_ERROR_CANNOT_READ_BLOCK
Generic block read failure (seek/read error).
Definition errors.h:46
#define AARUF_ERROR_INCORRECT_DATA_SIZE
Data size does not match expected size.
Definition errors.h:65
#define AARUF_ERROR_SECTOR_TAG_NOT_PRESENT
Requested sector tag (e.g. subchannel/prefix) not stored.
Definition errors.h:55
#define AARUF_STATUS_SECTOR_NOT_DUMPED
Sector not captured (gap / missing / intentionally skipped).
Definition errors.h:83
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
#define AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK
Decompression routine failed or size mismatch.
Definition errors.h:56
#define AARUF_ERROR_INVALID_TAG
Invalid or unsupported media or sector tag format.
Definition errors.h:66
#define AARUF_ERROR_MEDIA_TAG_NOT_PRESENT
Requested media tag absent.
Definition errors.h:50
#define AARUF_ERROR_BUFFER_TOO_SMALL
Caller-supplied buffer insufficient for data.
Definition errors.h:49
#define AARUF_ERROR_REACHED_UNREACHABLE_CODE
Internal logic assertion hit unexpected path.
Definition errors.h:53
@ BDREXL
BD-RE XL.
Definition aaru.h:163
@ AppleProfile
Definition aaru.h:710
@ PS5BD
Sony PlayStation 5 game Blu-ray.
Definition aaru.h:215
@ GOD
Nintendo GameCube Optical Disc.
Definition aaru.h:514
@ AppleSonySS
3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR
Definition aaru.h:252
@ DVDPRWDL
DVD+RW DL.
Definition aaru.h:141
@ BDRXL
BD-R XL.
Definition aaru.h:162
@ DVDRW
DVD-RW.
Definition aaru.h:138
@ DVDRWDL
DVD-RW DL.
Definition aaru.h:145
@ WOD
Nintendo Wii Optical Disc.
Definition aaru.h:524
@ PS3BD
Sony PlayStation 3 game Blu-ray.
Definition aaru.h:211
@ SACD
Super Audio CD (Scarlet Book).
Definition aaru.h:121
@ UHDBD
Ultra HD Blu-ray.
Definition aaru.h:164
@ DVDPRDL
DVD+R DL.
Definition aaru.h:143
@ DVDR
DVD-R.
Definition aaru.h:137
@ PS3DVD
Sony PlayStation 3 game DVD.
Definition aaru.h:210
@ BDROM
BD-ROM (and BD Video).
Definition aaru.h:159
@ PS2DVD
Sony PlayStation 2 game DVD.
Definition aaru.h:209
@ XGD4
Microsoft X-box One Game Disc.
Definition aaru.h:222
@ BDR
BD-R.
Definition aaru.h:160
@ PS4BD
Sony PlayStation 4 game Blu-ray.
Definition aaru.h:212
@ PriamDataTower
Definition aaru.h:713
@ AppleFileWare
5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy
Definition aaru.h:254
@ BDRE
BD-RE.
Definition aaru.h:161
@ DVDPR
DVD+R.
Definition aaru.h:139
@ AppleWidget
Definition aaru.h:711
@ DVDPRW
DVD+RW.
Definition aaru.h:140
@ Nuon
Nuon (DVD based videogame console).
Definition aaru.h:243
@ DVDDownload
DVD-Download.
Definition aaru.h:146
@ DVDRDL
DVD-R DL.
Definition aaru.h:142
@ AppleSonyDS
3.5", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR
Definition aaru.h:253
@ WUOD
Nintendo Wii U Optical Disc.
Definition aaru.h:525
@ DVDROM
DVD-ROM (applies to DVD Video and DVD Audio).
Definition aaru.h:136
@ DVDRAM
DVD-RAM.
Definition aaru.h:144
@ kSectorTagCdTrackFlags
Track flags (audio/data, copy permitted, pre-emphasis).
Definition aaru.h:971
@ kSectorTagDvdCmi
DVD Copyright Management Information (CSS).
Definition aaru.h:972
@ kSectorTagDvdSectorIed
DVD sector ID error detection, 2 bytes.
Definition aaru.h:978
@ kSectorTagCdSubchannel
96 raw subchannel bytes (P-W)
Definition aaru.h:968
@ kSectorTagAppleSony
Apple's Sony sector tags, 12 bytes (address prolog + checksum).
Definition aaru.h:960
@ kSectorTagAppleProfile
Apple's Profile sector tags, 20 bytes.
Definition aaru.h:980
@ kSectorTagCdTrackIsrc
Track ISRC (12 ASCII chars, no terminator).
Definition aaru.h:969
@ kSectorTagDvdSectorInformation
DVD sector information, 1 bytes.
Definition aaru.h:976
@ kSectorTagDvdSectorEdc
DVD sector EDC, 4 bytes.
Definition aaru.h:979
@ kSectorTagDvdSectorNumber
DVD sector number, 3 bytes.
Definition aaru.h:977
@ kSectorTagPriamDataTower
Priam DataTower sector tags, 24 bytes.
Definition aaru.h:981
@ kSectorTagDvdTitleKeyDecrypted
Decrypted DVD sector title key, 5 bytes.
Definition aaru.h:975
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:496
static int aaruf_fseek(FILE *stream, aaru_off_t offset, int origin)
Definition internal.h:46
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:663
int64_t aaru_off_t
Definition internal.h:42
void ngc_lfg_get_bytes(struct ngc_lfg_ctx *ctx, uint8_t *out, size_t count)
Generate count bytes of junk data into out.
Definition lfg.c:82
void ngc_lfg_set_seed(struct ngc_lfg_ctx *ctx, const uint32_t seed[17])
Initialize the LFG from a 17-word big-endian seed.
Definition lfg.c:73
#define NGC_LFG_SEED_SIZE
Number of uint32 words needed to seed the LFG.
Definition lfg.h:36
#define FATAL(fmt,...)
Definition log.h:40
#define TRACE(fmt,...)
Definition log.h:25
void add_to_cache_uint64(struct CacheHeader *cache, uint64_t key, void *value, size_t size)
Adds a value to the cache with a uint64_t key, evicting LRU entries if over budget.
Definition lru.c:68
void * find_in_cache_uint64(struct CacheHeader *cache, uint64_t key)
Finds a value in the cache by uint64_t key.
Definition lru.c:41
void ngcw_junk_lazy_init(aaruformat_context *ctx)
Lazy initialization: load junk map from media tags.
Definition ngcw_junk.c:211
int ngcw_regenerate_junk_sector(const NgcwJunkEntry *entries, uint32_t entry_count, uint64_t disc_offset, uint8_t *output, uint32_t length)
Regenerate a junk sector from the junk map.
Definition ngcw_junk.c:154
void ps3_lazy_init(aaruformat_context *ctx)
Lazy-initialize PS3 encryption state from context media tags.
Definition ps3_crypto.c:70
void ps3_encrypt_sector(const uint8_t disc_key[16], uint64_t sector_num, uint8_t *data, uint32_t length)
Encrypt a sector using PS3 disc encryption (AES-128-CBC).
Definition ps3_crypto.c:56
bool ps3_is_sector_encrypted(const Ps3PlaintextRegion *plaintext_regions, uint32_t region_count, uint64_t sector_address)
Check whether a sector is encrypted (i.e., not in any plaintext region).
static void wii_reconstruct_group_junk(aaruformat_context *ctx, uint64_t phys_group, uint8_t *group_cache)
Reconstruct junk in a Wii group's user data area before re-encryption.
Definition read.c:44
uint32_t mediaType
Media type enumeration (value from MediaType).
Definition header.h:114
Header preceding the compressed data payload of a data block (BlockType::DataBlock).
Definition data.h:71
uint32_t cmpLength
Size in bytes of the compressed payload immediately following this header.
Definition data.h:76
uint32_t length
Size in bytes of the uncompressed payload resulting after decompression.
Definition data.h:77
uint32_t identifier
Block identifier, must be BlockType::DataBlock.
Definition data.h:72
uint32_t sectorSize
Size in bytes of each logical sector represented in this block.
Definition data.h:75
uint16_t compression
Compression algorithm used (value from CompressionType).
Definition data.h:74
uint32_t overflow
Trailing dumped sectors beyond user area (overflow range), still mapped with entries.
Definition ddt.h:151
uint32_t negative
Leading negative LBA count; added to external L to build internal index.
Definition ddt.h:149
uint32_t MediaType
Media type identifier (see MediaType enum; 0=Unknown).
Definition aaru.h:945
uint8_t MetadataMediaType
Media type for sidecar generation (internal archival use).
Definition aaru.h:946
uint32_t SectorSize
Size of each logical sector in bytes (512, 2048, 2352, 4096, etc.).
Definition aaru.h:939
uint64_t Sectors
Total count of addressable logical sectors/blocks.
Definition aaru.h:938
In-memory junk map entry.
Definition ngcw_junk.h:48
uint64_t length
Length of junk region in bytes.
Definition ngcw_junk.h:50
uint64_t offset
Disc byte offset where junk starts.
Definition ngcw_junk.h:49
A plaintext (unencrypted) region on a PS3 disc.
Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags).
Definition optical.h:72
uint8_t flags
Control / attribute bitfield (see file documentation for suggested bit mapping).
Definition optical.h:81
uint8_t sequence
Track number (1..99 typical for CD audio/data).
Definition optical.h:73
int64_t start
Inclusive starting LBA of the track.
Definition optical.h:76
uint8_t type
Track type (value from TrackType).
Definition optical.h:75
uint8_t isrc[13]
ISRC raw 13-byte code (no null terminator). All zeros if not present.
Definition optical.h:80
uint16_t entries
Number of TrackEntry records following this header.
Definition optical.h:64
A Wii partition region entry (in-memory representation).
Definition wii_crypto.h:52
uint32_t start_sector
First physical sector of partition.
Definition wii_crypto.h:53
A Wii U partition region entry (in-memory representation).
Definition wiiu_crypto.h:49
Master context representing an open or in‑creation Aaru image.
Definition context.h:178
uint8_t * ps3_disc_key
Cached disc key (16 bytes), NULL if not loaded.
Definition context.h:357
bool wiiu_building_crypto_block
True while gathering sectors for re-encryption (suppresses recursion).
Definition context.h:370
DdtHeader2 user_data_ddt_header
Active user data DDT v2 header (primary table meta).
Definition context.h:195
void * wiiu_partition_regions
Parsed WiiuPartitionRegion array, NULL if not loaded.
Definition context.h:364
size_t sector_suffix_length
Length of sector_suffix.
Definition context.h:295
uint8_t * sector_cpr_mai
DVD sector CPR_MAI (6 bytes) if present.
Definition context.h:214
uint32_t ps3_plaintext_region_count
Number of plaintext regions.
Definition context.h:359
uint8_t * sector_prefix_corrected
Corrected variant (post error correction) if stored.
Definition context.h:207
uint32_t wiiu_partition_region_count
Number of partition regions.
Definition context.h:365
TrackEntry * data_tracks
Filtered list of data tracks (subset of trackEntries).
Definition context.h:253
uint8_t * wiiu_encrypted_block_cache
Cached re-encrypted 0x8000-byte physical sector.
Definition context.h:367
bool ec_recovery_in_progress
Recursion guard for recovery (prevents infinite loops).
Definition context.h:419
void * ngcw_junk_entries
Parsed NgcwJunkEntry array, NULL if not loaded.
Definition context.h:373
struct CacheHeader block_header_cache
LRU/Cache header for block headers.
Definition context.h:266
uint8_t * sector_ied
DVD sector IED (2 bytes) if present.
Definition context.h:213
uint8_t * sector_prefix
Raw per-sector prefix (e.g., sync+header) uncorrected.
Definition context.h:206
uint64_t wii_cached_physical_group
Physical group number of cached block.
Definition context.h:383
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
Definition context.h:192
uint8_t * sector_edc
DVD or Blu-ray sector EDC (4 bytes) if present (see DvdSectorEdc / BdSectorEdc data types).
Definition context.h:215
CdEccContext * ecc_cd_context
CD ECC/EDC helper tables (allocated on demand).
Definition context.h:258
struct CacheHeader block_cache
LRU/Cache header for block payloads.
Definition context.h:267
bool ps3_encryption_initialized
Whether lazy init has occurred.
Definition context.h:360
uint64_t wiiu_cached_physical_sector
Physical sector number of cached block.
Definition context.h:368
uint32_t * sector_suffix_ddt
Legacy CD sector suffix DDT.
Definition context.h:190
uint8_t * sector_suffix
Raw per-sector suffix (EDC/ECC) uncorrected.
Definition context.h:208
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:181
int ddt_version
DDT version in use (1=legacy, 2=v2 hierarchical).
Definition context.h:200
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:180
uint64_t * sector_prefix_ddt2
CD sector prefix DDT V2.
Definition context.h:191
bool wii_building_crypto_block
True while gathering sectors for re-encryption (suppresses recursion).
Definition context.h:385
size_t sector_prefix_length
Length of sector_prefix.
Definition context.h:294
mediaTagEntry * mediaTags
Hash table of extra media tags (uthash root).
Definition context.h:274
uint32_t ngcw_junk_entry_count
Number of junk entries.
Definition context.h:374
uint32_t wii_partition_region_count
Number of partition regions.
Definition context.h:380
bool wiiu_encryption_initialized
Whether lazy init has occurred.
Definition context.h:366
uint8_t * sector_decrypted_title_key
DVD decrypted title key (5 bytes) if present.
Definition context.h:216
bool wii_encryption_initialized
Whether lazy init has occurred.
Definition context.h:381
uint8_t * sector_subchannel
Raw 96-byte subchannel (if captured).
Definition context.h:210
void * wii_partition_regions
Parsed WiiPartitionRegion array, NULL if not loaded.
Definition context.h:379
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:182
bool no_user_data_ddt
True if image intentionally has no user-data DDT (e.g. flux-only image). When set,...
Definition context.h:203
uint8_t * mode2_subheaders
MODE2 Form1/Form2 8-byte subheaders (concatenated).
Definition context.h:211
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:270
bool wii_cache_valid
Whether the encrypted group cache is valid.
Definition context.h:384
uint8_t * sector_id
DVD sector ID (4 bytes) if present.
Definition context.h:212
void * ps3_plaintext_regions
Parsed Ps3PlaintextRegion array (max 32), NULL if not loaded.
Definition context.h:358
uint32_t * sector_prefix_ddt
Legacy CD sector prefix DDT (deprecated by *2).
Definition context.h:189
bool wiiu_cache_valid
Whether the encrypted block cache is valid.
Definition context.h:369
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
Definition context.h:252
uint8_t number_of_data_tracks
Count of tracks considered "data" (sequence 1..99 heuristics).
Definition context.h:255
uint8_t * sector_suffix_corrected
Corrected suffix if stored separately.
Definition context.h:209
uint8_t * wii_encrypted_group_cache
Cached re-encrypted 0x8000-byte group.
Definition context.h:382
bool ngcw_junk_initialized
Whether junk map has been loaded.
Definition context.h:376
bool ec_recovery_available
True if ECMB loaded and recovery is possible.
Definition context.h:418
TracksHeader tracks_header
Tracks header (optical) if present.
Definition context.h:254
Hash table entry for an arbitrary media tag (e.g., proprietary drive/medium descriptor).
Definition context.h:125
uint8_t * data
Tag data blob (opaque to library core); length bytes long.
Definition context.h:126
uint32_t length
Length in bytes of data.
Definition context.h:128
LFG context holding the 521-word circular buffer and byte position.
Definition lfg.h:42
uint32_t buffer[521]
Definition lfg.h:43
const uint8_t * wii_get_sector_key(const WiiPartitionRegion *regions, uint32_t region_count, uint64_t logical_sector)
Get the encryption key for a given logical sector (2048-byte).
Definition wii_crypto.c:45
void wii_encrypt_group(const uint8_t key[16], const uint8_t *hash_block, const uint8_t *data_in, uint8_t *out)
Encrypt a Wii group (0x8000 bytes) from separate hash_block + data.
Definition wii_crypto.c:71
void wii_lazy_init(aaruformat_context *ctx)
Lazy initialization: load partition key map from media tags.
Definition wii_crypto.c:180
#define WII_GROUP_SIZE
Wii physical group size (32 KiB).
Definition wii_crypto.h:38
#define WII_SECTOR_SIZE
Logical sector size in bytes.
Definition wii_crypto.h:42
#define WII_GROUP_DATA_SIZE
User data size within a group (31 KiB).
Definition wii_crypto.h:40
#define WII_GROUP_HASH_SIZE
Hash block size within a group (1 KiB).
Definition wii_crypto.h:39
#define WII_LOGICAL_PER_GROUP
Number of 2048-byte logical sectors per group.
Definition wii_crypto.h:41
void wiiu_encrypt_physical_sector(const uint8_t key[16], uint8_t *data, uint32_t length)
Encrypt a full 0x8000-byte physical sector in-place.
Definition wiiu_crypto.c:72
void wiiu_lazy_init(aaruformat_context *ctx)
Lazy initialization: load disc key and partition key map from media tags.
const uint8_t * wiiu_get_sector_key(const WiiuPartitionRegion *regions, uint32_t region_count, uint64_t logical_sector)
Get the encryption key for a given logical sector (2048-byte).
Definition wiiu_crypto.c:43
#define WIIU_CRYPTO_SECTOR_SIZE
Wii U physical sector size (32 KiB).
Definition wiiu_crypto.h:35
#define WIIU_LOGICAL_PER_PHYSICAL
Number of 2048-byte logical sectors per physical sector.
Definition wiiu_crypto.h:36