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 if(negative && sector_address > ctx->user_data_ddt_header.negative)
400 {
401 FATAL("Sector address out of bounds");
402
403 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
405 }
406
407 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
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(ctx->ddt_version == 1)
416 {
417 if(negative)
418 {
419 FATAL("Negative sector addresses not supported in this image");
421 }
422
423 error_no = decode_ddt_entry_v1(ctx, sector_address, &offset, &block_offset, sector_status);
424 }
425 else if(ctx->ddt_version == 2)
426 error_no = decode_ddt_entry_v2(ctx, sector_address, negative, &offset, &block_offset, sector_status);
427
428 if(error_no != AARUF_STATUS_OK)
429 {
430 FATAL("Error %d decoding DDT entry", error_no);
431
432 TRACE("Exiting aaruf_read_sector() = %d", error_no);
433 return error_no;
434 }
435
436 // Partially written image... as we can't know the real sector size just assume it's common :/
437 if(*sector_status == SectorStatusNotDumped)
438 {
439 *length = ctx->image_info.SectorSize;
440
441 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_SECTOR_NOT_DUMPED");
443 }
444
445 // NGCW: SectorStatusGenerable — regenerate junk from seed, no block data exists
446 if(*sector_status == SectorStatusGenerable && (ctx->header.mediaType == GOD || ctx->header.mediaType == WOD))
447 {
448 if(!ctx->ngcw_junk_initialized)
449 {
451 ctx->ngcw_junk_initialized = true;
452 }
453
454 *length = ctx->image_info.SectorSize;
455
456 if(data == NULL)
457 {
458 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_BUFFER_TOO_SMALL (generable, NULL data)");
460 }
461
462 if(ctx->ngcw_junk_entries != NULL)
463 {
464 uint64_t disc_offset = sector_address * (uint64_t)ctx->image_info.SectorSize;
465
467 disc_offset, data, *length) == 0)
468 {
469 if(ctx->header.mediaType == GOD)
470 {
471 *sector_status = SectorStatusDumped;
472 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (GOD generable)");
473 return AARUF_STATUS_OK;
474 }
475
476 // WOD: regenerated junk needs Wii re-encryption.
477 // We have the plaintext in the data buffer — do re-encryption now and return.
479 {
480 wii_lazy_init(ctx);
481 ctx->wii_encryption_initialized = true;
482 }
483
484 if(ctx->wii_partition_regions != NULL && ctx->wii_encrypted_group_cache != NULL &&
486 {
487 const uint8_t *part_key = wii_get_sector_key((const WiiPartitionRegion *)ctx->wii_partition_regions,
488 ctx->wii_partition_region_count, sector_address);
489
490 if(part_key != NULL)
491 {
492 uint64_t phys_group = sector_address / WII_LOGICAL_PER_GROUP;
493 uint32_t slice_index = (uint32_t)(sector_address % WII_LOGICAL_PER_GROUP);
494
495 if(!ctx->wii_cache_valid || ctx->wii_cached_physical_group != phys_group)
496 {
497 uint64_t first_logical = phys_group * WII_LOGICAL_PER_GROUP;
498
499 ctx->wii_building_crypto_block = true;
500
501 for(uint32_t s = 0; s < WII_LOGICAL_PER_GROUP; s++)
502 {
503 uint64_t logical = first_logical + s;
504
505 if(logical == sector_address)
506 {
507 memcpy(ctx->wii_encrypted_group_cache + s * (*length), data, *length);
508 }
509 else
510 {
511 uint32_t s_len = *length;
512 uint8_t s_status = 0;
513 int32_t s_ret = aaruf_read_sector(context, logical, false,
514 ctx->wii_encrypted_group_cache + s * s_len,
515 &s_len, &s_status);
516
517 if(s_ret != AARUF_STATUS_OK)
518 memset(ctx->wii_encrypted_group_cache + s * (*length), 0, *length);
519 }
520 }
521
522 ctx->wii_building_crypto_block = false;
523
524 // Reconstruct junk in user data area
526
530 ctx->wii_cached_physical_group = phys_group;
531 ctx->wii_cache_valid = true;
532 }
533
534 memcpy(data, ctx->wii_encrypted_group_cache + slice_index * (*length), *length);
535 }
536 }
537
538 *sector_status = SectorStatusDumped;
539 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (WOD generable re-encrypted)");
540 return AARUF_STATUS_OK;
541 }
542 else
543 {
544 // Not found in junk map — zero-fill
545 memset(data, 0, *length);
546 *sector_status = SectorStatusDumped;
547 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (generable not in map)");
548 return AARUF_STATUS_OK;
549 }
550 }
551 else
552 {
553 // No junk map loaded — zero-fill
554 memset(data, 0, *length);
555 *sector_status = SectorStatusDumped;
556 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK (no junk map)");
557 return AARUF_STATUS_OK;
558 }
559 }
560
561 // Check if block header is cached
562 TRACE("Checking if block header is cached");
563 block_header = find_in_cache_uint64(&ctx->block_header_cache, block_offset);
564
565 // Read block header
566 if(block_header == NULL)
567 {
568 TRACE("Allocating memory for block header");
569 block_header = malloc(sizeof(BlockHeader));
570 if(block_header == NULL)
571 {
572 FATAL("Not enough memory for block header");
573
574 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
576 }
577
578 TRACE("Reading block header");
579 if(aaruf_fseek(ctx->imageStream, (aaru_off_t)block_offset, SEEK_SET) != 0)
580 {
581 FATAL("Could not seek to block header");
582 free(block_header);
583
584 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
586 }
587
588 read_bytes = fread(block_header, 1, sizeof(BlockHeader), ctx->imageStream);
589
590 if(read_bytes != sizeof(BlockHeader))
591 {
592 FATAL("Error reading block header");
593 free(block_header);
594
595 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
597 }
598
599 TRACE("Adding block header to cache");
600 add_to_cache_uint64(&ctx->block_header_cache, block_offset, block_header);
601 }
602 else if(aaruf_fseek(ctx->imageStream, (aaru_off_t)(block_offset + sizeof(BlockHeader)), SEEK_SET) != 0)
603 {
604 FATAL("Could not seek past cached block header");
605
606 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_HEADER");
608 }
609
610 /* Sanity check: if the cached/read block header looks corrupt, skip directly to EC recovery.
611 * A corrupt header will have garbage sectorSize, compression, or identifier fields. */
612 if(block_header->identifier != DataBlock ||
613 block_header->sectorSize == 0 || block_header->sectorSize > 65536)
614 {
615 TRACE("Block header at offset %" PRIu64 " appears corrupt (id=0x%08X sectorSize=%u)",
616 block_offset, block_header->identifier, block_header->sectorSize);
617 goto ec_try_recovery;
618 }
619
620 if(data == NULL || *length < block_header->sectorSize)
621 {
622 TRACE("Buffer too small for sector, required %u bytes", block_header->sectorSize);
623 *length = block_header->sectorSize;
624
625 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_BUFFER_TOO_SMALL");
627 }
628
629 // Check if block is cached
630 TRACE("Checking if block is cached");
631 block = find_in_cache_uint64(&ctx->block_cache, block_offset);
632
633 if(block != NULL)
634 {
635 TRACE("Getting data from cache");
636 memcpy(data, block + offset * block_header->sectorSize, block_header->sectorSize);
637 *length = block_header->sectorSize;
638
639 // PS3 re-encryption: if stored decrypted, re-encrypt for caller
640 if(*sector_status == SectorStatusUnencrypted &&
641 (ctx->header.mediaType == PS3DVD || ctx->header.mediaType == PS3BD))
642 {
644 {
645 ps3_lazy_init(ctx);
646 ctx->ps3_encryption_initialized = true;
647 }
648
649 if(ctx->ps3_disc_key != NULL && ctx->ps3_plaintext_regions != NULL &&
651 ctx->ps3_plaintext_region_count, sector_address))
652 {
653 ps3_encrypt_sector(ctx->ps3_disc_key, sector_address, data, *length);
654 }
655
656 *sector_status = SectorStatusDumped;
657 }
658
659 // Wii U re-encryption: if stored decrypted, re-encrypt for caller
660 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD &&
662 {
664 {
665 wiiu_lazy_init(ctx);
666 ctx->wiiu_encryption_initialized = true;
667 }
668
669 if(ctx->wiiu_partition_regions != NULL && ctx->wiiu_encrypted_block_cache != NULL)
670 {
671 const uint8_t *part_key = wiiu_get_sector_key((const WiiuPartitionRegion *)ctx->wiiu_partition_regions,
672 ctx->wiiu_partition_region_count, sector_address);
673
674 if(part_key != NULL)
675 {
676 uint64_t phys_sector = sector_address / WIIU_LOGICAL_PER_PHYSICAL;
677 uint32_t slice_index = (uint32_t)(sector_address % WIIU_LOGICAL_PER_PHYSICAL);
678
679 if(!ctx->wiiu_cache_valid || ctx->wiiu_cached_physical_sector != phys_sector)
680 {
681 uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
682
683 // Read all 16 logical sectors via aaruf_read_sector with recursion guard
684 ctx->wiiu_building_crypto_block = true;
685
686 for(uint32_t s = 0; s < WIIU_LOGICAL_PER_PHYSICAL; s++)
687 {
688 uint64_t logical = first_logical + s;
689
690 if(logical == sector_address)
691 {
692 // Current sector is already in data buffer
693 memcpy(ctx->wiiu_encrypted_block_cache + s * (*length), data, *length);
694 }
695 else
696 {
697 uint32_t s_len = *length;
698 uint8_t s_status = 0;
699 int32_t s_ret =
700 aaruf_read_sector(context, logical, false,
701 ctx->wiiu_encrypted_block_cache + s * s_len, &s_len, &s_status);
702
703 if(s_ret != AARUF_STATUS_OK)
704 memset(ctx->wiiu_encrypted_block_cache + s * (*length), 0, *length);
705 }
706 }
707
708 ctx->wiiu_building_crypto_block = false;
709
712 ctx->wiiu_cached_physical_sector = phys_sector;
713 ctx->wiiu_cache_valid = true;
714 }
715
716 memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * (*length), *length);
717 }
718 }
719
720 *sector_status = SectorStatusDumped;
721 }
722
723 // Wii re-encryption: if stored decrypted, re-encrypt for caller
724 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WOD && !ctx->wii_building_crypto_block)
725 {
727 {
728 wii_lazy_init(ctx);
729 ctx->wii_encryption_initialized = true;
730 }
731
732 if(!ctx->ngcw_junk_initialized)
733 {
735 ctx->ngcw_junk_initialized = true;
736 }
737
738 if(ctx->wii_partition_regions != NULL && ctx->wii_encrypted_group_cache != NULL)
739 {
740 const uint8_t *part_key = wii_get_sector_key((const WiiPartitionRegion *)ctx->wii_partition_regions,
741 ctx->wii_partition_region_count, sector_address);
742
743 if(part_key != NULL)
744 {
745 uint64_t phys_group = sector_address / WII_LOGICAL_PER_GROUP;
746 uint32_t slice_index = (uint32_t)(sector_address % WII_LOGICAL_PER_GROUP);
747
748 if(!ctx->wii_cache_valid || ctx->wii_cached_physical_group != phys_group)
749 {
750 uint64_t first_logical = phys_group * WII_LOGICAL_PER_GROUP;
751
752 ctx->wii_building_crypto_block = true;
753
754 for(uint32_t s = 0; s < WII_LOGICAL_PER_GROUP; s++)
755 {
756 uint64_t logical = first_logical + s;
757
758 if(logical == sector_address)
759 {
760 memcpy(ctx->wii_encrypted_group_cache + s * (*length), data, *length);
761 }
762 else
763 {
764 uint32_t s_len = *length;
765 uint8_t s_status = 0;
766 int32_t s_ret =
767 aaruf_read_sector(context, logical, false,
768 ctx->wii_encrypted_group_cache + s * s_len, &s_len, &s_status);
769
770 if(s_ret != AARUF_STATUS_OK)
771 memset(ctx->wii_encrypted_group_cache + s * (*length), 0, *length);
772 }
773 }
774
775 ctx->wii_building_crypto_block = false;
776
777 // Reconstruct junk in user data area
779
783 ctx->wii_cached_physical_group = phys_group;
784 ctx->wii_cache_valid = true;
785 }
786
787 memcpy(data, ctx->wii_encrypted_group_cache + slice_index * (*length), *length);
788 }
789 }
790
791 *sector_status = SectorStatusDumped;
792 }
793
794 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK");
795 return AARUF_STATUS_OK;
796 }
797
798 // Decompress block
799 switch(block_header->compression)
800 {
801 case kCompressionNone:
802 TRACE("Allocating memory for block");
803 block = (uint8_t *)malloc(block_header->length);
804 if(block == NULL)
805 {
806 FATAL("Not enough memory for block");
807
808 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
810 }
811
812 TRACE("Reading block into memory");
813 read_bytes = fread(block, 1, block_header->length, ctx->imageStream);
814
815 if(read_bytes != block_header->length)
816 {
817 FATAL("Could not read block");
818 free(block);
819
820 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_READ_BLOCK");
822 }
823
824 break;
825 case kCompressionLzma:
826 if(block_header->cmpLength <= LZMA_PROPERTIES_LENGTH || block_header->length == 0)
827 {
828 FATAL("Invalid LZMA block lengths (cmpLength=%u, length=%u)", block_header->cmpLength,
829 block_header->length);
830
831 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
832 goto ec_try_recovery;
833 }
834
835 lzma_size = block_header->cmpLength - LZMA_PROPERTIES_LENGTH;
836 TRACE("Allocating memory for compressed data of size %zu bytes", lzma_size);
837 cmp_data = malloc(lzma_size);
838
839 if(cmp_data == NULL)
840 {
841 FATAL("Cannot allocate memory for block...");
842
843 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
845 }
846
847 TRACE("Allocating memory for block of size %zu bytes", block_header->length);
848 block = malloc(block_header->length);
849 if(block == NULL)
850 {
851 FATAL("Cannot allocate memory for block...");
852 free(cmp_data);
853
854 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
856 }
857
858 read_bytes = fread(lzma_properties, 1, LZMA_PROPERTIES_LENGTH, ctx->imageStream);
859
860 if(read_bytes != LZMA_PROPERTIES_LENGTH)
861 {
862 FATAL("Could not read LZMA properties...");
863 free(block);
864 free(cmp_data);
865
866 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
867 goto ec_try_recovery;
868 }
869
870 read_bytes = fread(cmp_data, 1, lzma_size, ctx->imageStream);
871 if(read_bytes != lzma_size)
872 {
873 FATAL("Could not read compressed block...");
874 free(cmp_data);
875 free(block);
876
877 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
878 goto ec_try_recovery;
879 }
880
881 TRACE("Decompressing block of size %zu bytes", block_header->length);
882 read_bytes = block_header->length;
883 error_no = aaruf_lzma_decode_buffer(block, &read_bytes, cmp_data, &lzma_size, lzma_properties,
885
886 if(error_no != 0)
887 {
888 FATAL("Got error %d from LZMA...", error_no);
889 free(cmp_data);
890 free(block);
891
892 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
893 goto ec_try_recovery;
894 }
895
896 if(read_bytes != block_header->length)
897 {
898 FATAL("Error decompressing block, should be {0} bytes but got {1} bytes...");
899 free(cmp_data);
900 free(block);
901
902 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
903 goto ec_try_recovery;
904 }
905
906 free(cmp_data);
907
908 break;
909 case kCompressionZstd:
910 if(block_header->cmpLength == 0 || block_header->length == 0)
911 {
912 FATAL("Invalid zstd block lengths (cmpLength=%u, length=%u)", block_header->cmpLength,
913 block_header->length);
914 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
915 goto ec_try_recovery;
916 }
917
918 TRACE("Allocating memory for block of size %zu bytes", block_header->length);
919 block = (uint8_t *)malloc(block_header->length);
920 if(block == NULL)
921 {
922 FATAL("Not enough memory for block");
923 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
925 }
926
927 TRACE("Allocating memory for compressed data of size %zu bytes", block_header->cmpLength);
928 cmp_data = malloc(block_header->cmpLength);
929 if(cmp_data == NULL)
930 {
931 FATAL("Not enough memory for compressed data");
932 free(block);
933 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
935 }
936
937 aaruf_fseek(ctx->imageStream, (aaru_off_t)(block_offset + sizeof(BlockHeader)), SEEK_SET);
938
939 read_bytes = fread(cmp_data, 1, block_header->cmpLength, ctx->imageStream);
940 if(read_bytes != block_header->cmpLength)
941 {
942 FATAL("Could not read compressed block");
943 free(cmp_data);
944 free(block);
945 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
946 goto ec_try_recovery;
947 }
948
949 read_bytes = aaruf_zstd_decode_buffer(block, block_header->length, cmp_data, block_header->cmpLength);
950 if(read_bytes != block_header->length)
951 {
952 FATAL("Error decompressing zstd block, expected %u bytes got %zu", block_header->length, read_bytes);
953 free(cmp_data);
954 free(block);
955 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
956 goto ec_try_recovery;
957 }
958
959 free(cmp_data);
960
961 break;
962 case kCompressionFlac:
963 TRACE("Allocating memory for compressed data of size %zu bytes", block_header->cmpLength);
964 cmp_data = malloc(block_header->cmpLength);
965
966 if(cmp_data == NULL)
967 {
968 FATAL("Cannot allocate memory for block...");
969
970 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
972 }
973
974 TRACE("Allocating memory for block of size %zu bytes", block_header->length);
975 block = malloc(block_header->length);
976 if(block == NULL)
977 {
978 FATAL("Cannot allocate memory for block...");
979 free(cmp_data);
980
981 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
983 }
984
985 TRACE("Reading compressed data into memory");
986 read_bytes = fread(cmp_data, 1, block_header->cmpLength, ctx->imageStream);
987 if(read_bytes != block_header->cmpLength)
988 {
989 FATAL("Could not read compressed block...");
990 free(cmp_data);
991 free(block);
992
993 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
994 goto ec_try_recovery;
995 }
996
997 TRACE("Decompressing block of size %zu bytes", block_header->length);
998 read_bytes =
999 aaruf_flac_decode_redbook_buffer(block, block_header->length, cmp_data, block_header->cmpLength);
1000
1001 if(read_bytes != block_header->length)
1002 {
1003 FATAL("Error decompressing block, should be {0} bytes but got {1} bytes...");
1004 free(cmp_data);
1005 free(block);
1006
1007 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
1008 goto ec_try_recovery;
1009 }
1010
1011 free(cmp_data);
1012
1013 break;
1014 default:
1015 FATAL("Unsupported compression %d", block_header->compression);
1016 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_UNSUPPORTED_COMPRESSION");
1017 goto ec_try_recovery;
1018 }
1019
1020 // Add block to cache
1021 TRACE("Adding block to cache");
1022 add_to_cache_uint64(&ctx->block_cache, block_offset, block);
1023
1024 memcpy(data, block + offset * block_header->sectorSize, block_header->sectorSize);
1025 *length = block_header->sectorSize;
1026
1027 // PS3 re-encryption: if stored decrypted, re-encrypt for caller
1028 if(*sector_status == SectorStatusUnencrypted && (ctx->header.mediaType == PS3DVD || ctx->header.mediaType == PS3BD))
1029 {
1031 {
1032 ps3_lazy_init(ctx);
1033 ctx->ps3_encryption_initialized = true;
1034 }
1035
1036 if(ctx->ps3_disc_key != NULL && ctx->ps3_plaintext_regions != NULL &&
1038 ctx->ps3_plaintext_region_count, sector_address))
1039 {
1040 ps3_encrypt_sector(ctx->ps3_disc_key, sector_address, data, *length);
1041 }
1042
1043 *sector_status = SectorStatusDumped;
1044 }
1045
1046 // Wii U re-encryption: if stored decrypted, re-encrypt for caller
1047 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WUOD && !ctx->wiiu_building_crypto_block)
1048 {
1050 {
1051 wiiu_lazy_init(ctx);
1052 ctx->wiiu_encryption_initialized = true;
1053 }
1054
1055 if(ctx->wiiu_partition_regions != NULL && ctx->wiiu_encrypted_block_cache != NULL)
1056 {
1057 const uint8_t *part_key = wiiu_get_sector_key((const WiiuPartitionRegion *)ctx->wiiu_partition_regions,
1058 ctx->wiiu_partition_region_count, sector_address);
1059
1060 if(part_key != NULL)
1061 {
1062 uint64_t phys_sector = sector_address / WIIU_LOGICAL_PER_PHYSICAL;
1063 uint32_t slice_index = (uint32_t)(sector_address % WIIU_LOGICAL_PER_PHYSICAL);
1064
1065 if(!ctx->wiiu_cache_valid || ctx->wiiu_cached_physical_sector != phys_sector)
1066 {
1067 uint64_t first_logical = phys_sector * WIIU_LOGICAL_PER_PHYSICAL;
1068
1069 // Read all 16 logical sectors via aaruf_read_sector with recursion guard
1070 ctx->wiiu_building_crypto_block = true;
1071
1072 for(uint32_t s = 0; s < WIIU_LOGICAL_PER_PHYSICAL; s++)
1073 {
1074 uint64_t logical = first_logical + s;
1075
1076 if(logical == sector_address)
1077 {
1078 // Current sector is already in data buffer
1079 memcpy(ctx->wiiu_encrypted_block_cache + s * (*length), data, *length);
1080 }
1081 else
1082 {
1083 uint32_t s_len = *length;
1084 uint8_t s_status = 0;
1085 int32_t s_ret =
1086 aaruf_read_sector(context, logical, false, ctx->wiiu_encrypted_block_cache + s * s_len,
1087 &s_len, &s_status);
1088
1089 if(s_ret != AARUF_STATUS_OK)
1090 memset(ctx->wiiu_encrypted_block_cache + s * (*length), 0, *length);
1091 }
1092 }
1093
1094 ctx->wiiu_building_crypto_block = false;
1095
1097 ctx->wiiu_cached_physical_sector = phys_sector;
1098 ctx->wiiu_cache_valid = true;
1099 }
1100
1101 memcpy(data, ctx->wiiu_encrypted_block_cache + slice_index * (*length), *length);
1102 }
1103 }
1104
1105 *sector_status = SectorStatusDumped;
1106 }
1107
1108 // Wii re-encryption: if stored decrypted, re-encrypt for caller
1109 if(*sector_status == SectorStatusUnencrypted && ctx->header.mediaType == WOD && !ctx->wii_building_crypto_block)
1110 {
1112 {
1113 wii_lazy_init(ctx);
1114 ctx->wii_encryption_initialized = true;
1115 }
1116
1117 if(!ctx->ngcw_junk_initialized)
1118 {
1120 ctx->ngcw_junk_initialized = true;
1121 }
1122
1123 if(ctx->wii_partition_regions != NULL && ctx->wii_encrypted_group_cache != NULL)
1124 {
1125 const uint8_t *part_key = wii_get_sector_key((const WiiPartitionRegion *)ctx->wii_partition_regions,
1126 ctx->wii_partition_region_count, sector_address);
1127
1128 if(part_key != NULL)
1129 {
1130 uint64_t phys_group = sector_address / WII_LOGICAL_PER_GROUP;
1131 uint32_t slice_index = (uint32_t)(sector_address % WII_LOGICAL_PER_GROUP);
1132
1133 if(!ctx->wii_cache_valid || ctx->wii_cached_physical_group != phys_group)
1134 {
1135 uint64_t first_logical = phys_group * WII_LOGICAL_PER_GROUP;
1136
1137 ctx->wii_building_crypto_block = true;
1138
1139 for(uint32_t s = 0; s < WII_LOGICAL_PER_GROUP; s++)
1140 {
1141 uint64_t logical = first_logical + s;
1142
1143 if(logical == sector_address)
1144 {
1145 memcpy(ctx->wii_encrypted_group_cache + s * (*length), data, *length);
1146 }
1147 else
1148 {
1149 uint32_t s_len = *length;
1150 uint8_t s_status = 0;
1151 int32_t s_ret = aaruf_read_sector(
1152 context, logical, false, ctx->wii_encrypted_group_cache + s * s_len, &s_len, &s_status);
1153
1154 if(s_ret != AARUF_STATUS_OK)
1155 memset(ctx->wii_encrypted_group_cache + s * (*length), 0, *length);
1156 }
1157 }
1158
1159 ctx->wii_building_crypto_block = false;
1160
1161 // Reconstruct junk in user data area
1163
1167 ctx->wii_cached_physical_group = phys_group;
1168 ctx->wii_cache_valid = true;
1169 }
1170
1171 memcpy(data, ctx->wii_encrypted_group_cache + slice_index * (*length), *length);
1172 }
1173 }
1174
1175 *sector_status = SectorStatusDumped;
1176 }
1177
1178 TRACE("Exiting aaruf_read_sector() = AARUF_STATUS_OK");
1179 return AARUF_STATUS_OK;
1180
1181 /* Erasure coding recovery: attempt to reconstruct a block that failed
1182 * decompression due to on-disk corruption. ec_recover_data_block()
1183 * reads the stripe, RS-decodes the erased shard, decompresses it,
1184 * and extracts the requested sector. */
1185ec_try_recovery:
1187 {
1188 TRACE("Attempting erasure coding recovery for block at offset %" PRIu64, block_offset);
1189 int32_t rc = ec_recover_data_block(ctx, block_offset, offset, data, length, *sector_status);
1190 if(rc == AARUF_STATUS_OK)
1191 {
1192 TRACE("Erasure coding recovery succeeded");
1193 return AARUF_STATUS_OK;
1194 }
1195 TRACE("Erasure coding recovery failed: %d", rc);
1196 }
1197
1198 TRACE("Exiting aaruf_read_sector() = AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK");
1200}
1201
1274AARU_EXPORT int32_t AARU_CALL aaruf_read_track_sector(void *context, uint8_t *data, const uint64_t sector_address,
1275 uint32_t *length, const uint8_t track, uint8_t *sector_status)
1276{
1277 const uint32_t initial_length = length == NULL ? 0U : *length;
1278
1279 TRACE("Entering aaruf_read_track_sector(%p, %p, %" PRIu64 ", %u, %d)", context, data, sector_address,
1280 initial_length, track);
1281
1282 if(context == NULL)
1283 {
1284 FATAL("Invalid context");
1285
1286 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_NOT_AARUFORMAT");
1288 }
1289
1290 aaruformat_context *ctx = context;
1291
1292 if(length == NULL)
1293 {
1294 FATAL("Invalid length pointer");
1295
1296 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1298 }
1299
1300 // Not a libaaruformat context
1301 if(ctx->magic != AARU_MAGIC)
1302 {
1303 FATAL("Invalid context");
1304
1305 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_NOT_AARUFORMAT");
1307 }
1308
1310 {
1311 FATAL("Incorrect media type %d, expected OpticalDisc", ctx->image_info.MetadataMediaType);
1312
1313 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
1315 }
1316
1317 for(int i = 0; i < ctx->number_of_data_tracks; i++)
1318 if(ctx->data_tracks[i].sequence == track)
1319 return aaruf_read_sector(context, ctx->data_tracks[i].start + sector_address, false, data, length,
1320 sector_status);
1321
1322 TRACE("Track %d not found", track);
1323 TRACE("Exiting aaruf_read_track_sector() = AARUF_ERROR_TRACK_NOT_FOUND");
1325}
1326
1430AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_long(void *context, const uint64_t sector_address, bool negative,
1431 uint8_t *data, uint32_t *length, uint8_t *sector_status)
1432{
1433 const uint32_t initial_length = length == NULL ? 0U : *length;
1434
1435 TRACE("Entering aaruf_read_sector_long(%p, %" PRIu64 ", %d, %p, %u)", context, sector_address, data,
1436 initial_length);
1437
1438 const aaruformat_context *ctx = NULL;
1439 uint32_t bare_length = 0;
1440 uint32_t tag_length = 0;
1441 uint8_t *bare_data = NULL;
1442 int32_t res = 0;
1443 int32_t query_status;
1444 TrackEntry trk;
1445 int i = 0;
1446 bool trk_found = false;
1447
1448 if(context == NULL)
1449 {
1450 FATAL("Invalid context");
1451
1452 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_AARUFORMAT");
1454 }
1455
1456 ctx = context;
1457
1458 if(length == NULL)
1459 {
1460 FATAL("Invalid length pointer");
1461
1462 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1464 }
1465
1466 // Not a libaaruformat context
1467 if(ctx->magic != AARU_MAGIC)
1468 {
1469 FATAL("Invalid context");
1470
1471 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_AARUFORMAT");
1473 }
1474
1475 if(negative && sector_address > ctx->user_data_ddt_header.negative)
1476 {
1477 FATAL("Sector address out of bounds");
1478
1479 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
1481 }
1482
1483 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
1484 {
1485 FATAL("Sector address out of bounds");
1486
1487 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
1489 }
1490
1491 uint64_t corrected_sector_address = sector_address;
1492
1493 // Calculate positive or negative sector
1494 if(negative)
1495 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
1496 else
1497 corrected_sector_address += ctx->user_data_ddt_header.negative;
1498
1499 switch(ctx->image_info.MetadataMediaType)
1500 {
1501 case OpticalDisc:
1502 if(ctx->image_info.MediaType == DVDROM || ctx->image_info.MediaType == PS2DVD ||
1503 ctx->image_info.MediaType == SACD || ctx->image_info.MediaType == PS3DVD ||
1504 ctx->image_info.MediaType == DVDR || ctx->image_info.MediaType == DVDRW ||
1505 ctx->image_info.MediaType == DVDPR || ctx->image_info.MediaType == DVDPRW ||
1509 ctx->image_info.MediaType == Nuon)
1510 {
1511 if(ctx->sector_id == NULL || ctx->sector_ied == NULL || ctx->sector_cpr_mai == NULL ||
1512 ctx->sector_edc == NULL)
1513 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1514
1515 if(*length < 2064 || data == NULL)
1516 {
1517 *length = 2064;
1518 FATAL("Buffer too small for sector, required %u bytes", *length);
1519
1520 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1522 }
1523
1524 bare_length = 0;
1525 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1526
1527 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1528 {
1529 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1530 return query_status;
1531 }
1532
1533 if(bare_length == 0)
1534 {
1535 FATAL("Invalid bare sector length (0)");
1536
1537 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1539 }
1540
1541 TRACE("Allocating memory for bare data");
1542 bare_data = (uint8_t *)malloc(bare_length);
1543
1544 if(bare_data == NULL)
1545 {
1546 FATAL("Could not allocate memory for bare data");
1547
1548 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1550 }
1551
1552 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1553
1554 if(res != AARUF_STATUS_OK)
1555 {
1556 *length = 2064;
1557 free(bare_data);
1558
1559 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1560 return res;
1561 }
1562
1563 memcpy(data, ctx->sector_id + corrected_sector_address * 4, 4);
1564 memcpy(data + 4, ctx->sector_ied + corrected_sector_address * 2, 2);
1565 memcpy(data + 6, ctx->sector_cpr_mai + corrected_sector_address * 6, 6);
1566 memcpy(data + 12, bare_data, 2048);
1567 memcpy(data + 2060, ctx->sector_edc + corrected_sector_address * 4, 4);
1568
1569 *length = 2064;
1570
1571 free(bare_data);
1572 return AARUF_STATUS_OK;
1573 }
1574
1575 if(ctx->image_info.MediaType == GOD || ctx->image_info.MediaType == WOD)
1576 {
1577 if(ctx->sector_id == NULL || ctx->sector_ied == NULL || ctx->sector_cpr_mai == NULL ||
1578 ctx->sector_edc == NULL)
1579 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1580
1581 if(*length < 2064 || data == NULL)
1582 {
1583 *length = 2064;
1584 FATAL("Buffer too small for sector, required %u bytes", *length);
1585
1586 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1588 }
1589
1590 bare_length = 0;
1591 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1592
1593 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1594 {
1595 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1596 return query_status;
1597 }
1598
1599 if(bare_length == 0)
1600 {
1601 FATAL("Invalid bare sector length (0)");
1602
1603 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1605 }
1606
1607 TRACE("Allocating memory for bare data");
1608 bare_data = (uint8_t *)malloc(bare_length);
1609
1610 if(bare_data == NULL)
1611 {
1612 FATAL("Could not allocate memory for bare data");
1613
1614 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1616 }
1617
1618 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1619
1620 if(res != AARUF_STATUS_OK)
1621 {
1622 *length = 2064;
1623 free(bare_data);
1624
1625 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1626 return res;
1627 }
1628
1629 memcpy(data, ctx->sector_id + corrected_sector_address * 4, 4);
1630 memcpy(data + 4, ctx->sector_ied + corrected_sector_address * 2, 2);
1631 memcpy(data + 6, bare_data, 2048);
1632 memcpy(data + 2054, ctx->sector_cpr_mai + corrected_sector_address * 6, 6);
1633 memcpy(data + 2060, ctx->sector_edc + corrected_sector_address * 4, 4);
1634
1635 *length = 2064;
1636
1637 free(bare_data);
1638 return AARUF_STATUS_OK;
1639 }
1640
1641 if(ctx->image_info.MediaType == BDROM || ctx->image_info.MediaType == BDR ||
1642 ctx->image_info.MediaType == BDRE || ctx->image_info.MediaType == BDRXL ||
1643 ctx->image_info.MediaType == BDREXL || ctx->image_info.MediaType == UHDBD ||
1644 ctx->image_info.MediaType == XGD4 || ctx->image_info.MediaType == PS3BD ||
1646 {
1647 if(ctx->sector_edc == NULL) return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1648
1649 if(*length < 2052 || data == NULL)
1650 {
1651 *length = 2052;
1652 FATAL("Buffer too small for sector, required %u bytes", *length);
1653
1654 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1656 }
1657
1658 bare_length = 0;
1659 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1660
1661 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1662 {
1663 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1664 return query_status;
1665 }
1666
1667 if(bare_length == 0)
1668 {
1669 FATAL("Invalid bare sector length (0)");
1670
1671 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1673 }
1674
1675 TRACE("Allocating memory for bare data");
1676 bare_data = (uint8_t *)malloc(bare_length);
1677
1678 if(bare_data == NULL)
1679 {
1680 FATAL("Could not allocate memory for bare data");
1681
1682 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1684 }
1685
1686 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1687
1688 if(res != AARUF_STATUS_OK)
1689 {
1690 free(bare_data);
1691
1692 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1693 return res;
1694 }
1695
1696 memcpy(data, bare_data, 2048);
1697 memcpy(data + 2048, ctx->sector_edc + corrected_sector_address * 4, 4);
1698
1699 *length = 2052;
1700
1701 free(bare_data);
1702 return AARUF_STATUS_OK;
1703 }
1704
1705 if(*length < 2352 || data == NULL)
1706 {
1707 *length = 2352;
1708 FATAL("Buffer too small for sector, required %u bytes", *length);
1709
1710 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
1712 }
1713
1714 if((ctx->sector_suffix == NULL || ctx->sector_prefix == NULL) &&
1715 (ctx->sector_suffix_ddt == NULL || ctx->sector_prefix_ddt == NULL) &&
1716 (ctx->sector_suffix_ddt2 == NULL || ctx->sector_prefix_ddt2 == NULL))
1717 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
1718
1719 bare_length = 0;
1720 query_status = aaruf_read_sector(context, sector_address, negative, NULL, &bare_length, sector_status);
1721
1722 if(query_status != AARUF_ERROR_BUFFER_TOO_SMALL && query_status != AARUF_STATUS_OK)
1723 {
1724 TRACE("Exiting aaruf_read_sector_long() = %d", query_status);
1725 return query_status;
1726 }
1727
1728 if(bare_length == 0)
1729 {
1730 FATAL("Invalid bare sector length (0)");
1731
1732 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1734 }
1735
1736 TRACE("Allocating memory for bare data");
1737 bare_data = (uint8_t *)malloc(bare_length);
1738
1739 if(bare_data == NULL)
1740 {
1741 FATAL("Could not allocate memory for bare data");
1742
1743 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1745 }
1746
1747 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
1748
1749 if(res != AARUF_STATUS_OK)
1750 {
1751 free(bare_data);
1752
1753 TRACE("Exiting aaruf_read_sector_long() = %d", res);
1754 return res;
1755 }
1756
1757 trk_found = false;
1758
1759 for(i = 0; i < ctx->number_of_data_tracks; i++)
1760 if(sector_address >= ctx->data_tracks[i].start && sector_address <= ctx->data_tracks[i].end)
1761 {
1762 trk_found = true;
1763 trk = ctx->data_tracks[i];
1764 break;
1765 }
1766
1767 if(!trk_found)
1768 {
1769 FATAL("Track not found");
1770 free(bare_data);
1771
1772 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_TRACK_NOT_FOUND");
1774 }
1775
1776 switch(trk.type)
1777 {
1778 case kTrackTypeAudio:
1779 case kTrackTypeData:
1780 memcpy(data, bare_data, bare_length);
1781 *length = bare_length;
1782 free(bare_data);
1783 return res;
1784 case kTrackTypeCdMode1:
1785 memcpy(data + 16, bare_data, 2048);
1786
1787 if(ctx->sector_prefix_ddt2 != NULL)
1788 {
1789 const uint64_t prefix_ddt_entry = ctx->sector_prefix_ddt2[corrected_sector_address];
1790 const uint32_t prefix_status = prefix_ddt_entry >> 60;
1791 const uint64_t prefix_index = prefix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1792
1793 if(prefix_status == SectorStatusMode1Correct)
1794 {
1795 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
1796 res = AARUF_STATUS_OK;
1797 }
1798 else if(prefix_status == SectorStatusNotDumped)
1800 else
1801 memcpy(data, ctx->sector_prefix + prefix_index * 16, 16);
1802 }
1803 else if(ctx->sector_prefix != NULL)
1804 memcpy(data, ctx->sector_prefix + corrected_sector_address * 16, 16);
1805 else if(ctx->sector_prefix_ddt != NULL)
1806 {
1807 if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
1808 {
1809 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
1810 res = AARUF_STATUS_OK;
1811 }
1812 else if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
1814 else
1815 memcpy(data,
1817 ((ctx->sector_prefix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 16,
1818 16);
1819 }
1820 else
1821 {
1822 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
1823 free(bare_data);
1825 }
1826
1827 if(res != AARUF_STATUS_OK)
1828 {
1829 *length = 2352;
1830 free(bare_data);
1831 return res;
1832 }
1833
1834 if(ctx->sector_suffix_ddt2 != NULL)
1835 {
1836 const uint64_t suffix_ddt_entry = ctx->sector_suffix_ddt2[corrected_sector_address];
1837 const uint64_t suffix_status = suffix_ddt_entry >> 60;
1838 const uint64_t suffix_index = suffix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1839
1840 if(suffix_status == SectorStatusMode1Correct)
1841 {
1843 res = AARUF_STATUS_OK;
1844 }
1845 else if(suffix_status == SectorStatusNotDumped)
1847 else
1848 memcpy(data + 2064, ctx->sector_suffix + suffix_index * 288, 288);
1849 }
1850 else if(ctx->sector_suffix != NULL)
1851 memcpy(data + 2064, ctx->sector_suffix + corrected_sector_address * 288, 288);
1852 else if(ctx->sector_suffix_ddt != NULL)
1853 {
1854 if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
1855 {
1857 res = AARUF_STATUS_OK;
1858 }
1859 else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
1861 else
1862 memcpy(data + 2064,
1864 ((ctx->sector_suffix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 288,
1865 288);
1866 }
1867 else
1868 {
1869 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
1870 free(bare_data);
1872 }
1873
1874 *length = 2352;
1875 free(bare_data);
1876 return res;
1880 if(ctx->sector_prefix_ddt2 != NULL)
1881 {
1882 const uint64_t prefix_ddt_entry = ctx->sector_prefix_ddt2[corrected_sector_address];
1883 const uint64_t prefix_status = prefix_ddt_entry >> 60;
1884 const uint64_t prefix_index = prefix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1885
1886 if(prefix_status == SectorStatusMode2Form1Ok || prefix_status == SectorStatusMode2Form2Ok)
1887 {
1888 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
1889 res = AARUF_STATUS_OK;
1890 }
1891 else if(prefix_status == SectorStatusNotDumped)
1893 else
1894 memcpy(data, ctx->sector_prefix + prefix_index * 16, 16);
1895 }
1896 else if(ctx->sector_prefix != NULL)
1897 memcpy(data, ctx->sector_prefix + corrected_sector_address * 16, 16);
1898 else if(ctx->sector_prefix_ddt != NULL)
1899 {
1900 if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Correct)
1901 {
1902 aaruf_ecc_cd_reconstruct_prefix(data, trk.type, sector_address);
1903 res = AARUF_STATUS_OK;
1904 }
1905 else if((ctx->sector_prefix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
1907 else
1908 memcpy(data,
1910 ((ctx->sector_prefix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1) * 16,
1911 16);
1912 }
1913 else
1914 {
1915 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_REACHED_UNREACHABLE_CODE");
1916 free(bare_data);
1918 }
1919
1920 if(res != AARUF_STATUS_OK)
1921 {
1922 *length = 2352;
1923 free(bare_data);
1924 return res;
1925 }
1926
1927 if(ctx->mode2_subheaders != NULL && ctx->sector_suffix_ddt2 != NULL)
1928 {
1929 memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
1930 const uint64_t suffix_ddt_entry = ctx->sector_suffix_ddt2[corrected_sector_address];
1931 const uint64_t suffix_status = suffix_ddt_entry >> 60;
1932 const uint64_t suffix_index = suffix_ddt_entry & 0x0FFFFFFFFFFFFFFF;
1933
1934 if(suffix_status == SectorStatusMode2Form1Ok)
1935 {
1936 memcpy(data + 24, bare_data, 2048);
1938 }
1939 else if(suffix_status == SectorStatusMode2Form2Ok ||
1940 suffix_status == SectorStatusMode2Form2NoCrc)
1941 {
1942 memcpy(data + 24, bare_data, 2324);
1943 if(suffix_status == SectorStatusMode2Form2Ok)
1945 else
1946 memset(data + 2348, 0, 4);
1947 }
1948 else if(suffix_status == SectorStatusNotDumped)
1950 else
1951 {
1952 // Mode 2 where ECC/EDC failed — restore user data + stored suffix.
1953 // Check both subheader copies to match write path form detection.
1954 if((data[0x12] & 0x20) || (data[0x16] & 0x20))
1955 {
1956 // Form 2: 2324 bytes user data, 4 bytes EDC suffix
1957 memcpy(data + 24, bare_data, 2324);
1958 memcpy(data + 2348, ctx->sector_suffix + suffix_index * 288, 4);
1959 }
1960 else
1961 {
1962 // Form 1: 2048 bytes user data, 280 bytes EDC+ECC suffix
1963 memcpy(data + 24, bare_data, 2048);
1964 memcpy(data + 2072, ctx->sector_suffix + suffix_index * 288, 280);
1965 }
1966 }
1967 }
1968 else if(ctx->mode2_subheaders != NULL && ctx->sector_suffix_ddt != NULL)
1969 {
1970 memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
1971
1972 if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form1Ok)
1973 {
1974 memcpy(data + 24, bare_data, 2048);
1976 }
1977 else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2Ok ||
1978 (ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2NoCrc)
1979 {
1980 memcpy(data + 24, bare_data, 2324);
1981 if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == Mode2Form2Ok)
1983 else
1984 memset(data + 2348, 0, 4);
1985 }
1986 else if((ctx->sector_suffix_ddt[corrected_sector_address] & CD_XFIX_MASK) == NotDumped)
1988 else
1989 {
1990 // Mode 2 where ECC/EDC failed — restore user data + stored suffix.
1991 // Check both subheader copies to match write path form detection.
1992 const uint32_t sfx_index =
1993 (ctx->sector_suffix_ddt[corrected_sector_address] & CD_DFIX_MASK) - 1;
1994 if((data[0x12] & 0x20) || (data[0x16] & 0x20))
1995 {
1996 memcpy(data + 24, bare_data, 2324);
1997 memcpy(data + 2348, ctx->sector_suffix_corrected + sfx_index * 288, 4);
1998 }
1999 else
2000 {
2001 memcpy(data + 24, bare_data, 2048);
2002 memcpy(data + 2072, ctx->sector_suffix_corrected + sfx_index * 288, 280);
2003 }
2004 }
2005 }
2006 else if(ctx->mode2_subheaders != NULL)
2007 {
2008 memcpy(data + 16, ctx->mode2_subheaders + corrected_sector_address * 8, 8);
2009 memcpy(data + 24, bare_data, 2328);
2010 }
2011 else
2012 memcpy(data + 16, bare_data, 2336);
2013
2014 *length = 2352;
2015 free(bare_data);
2016 return res;
2017 default:
2018 FATAL("Invalid track type %d", trk.type);
2019 free(bare_data);
2020
2021 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INVALID_TRACK_FORMAT");
2023 }
2024 case BlockMedia:
2025 switch(ctx->image_info.MediaType)
2026 {
2027 case AppleFileWare:
2028 case AppleProfile:
2029 case AppleSonySS:
2030 case AppleSonyDS:
2031 case AppleWidget:
2032 case PriamDataTower:
2033 if(ctx->sector_subchannel == NULL)
2034 return aaruf_read_sector(context, sector_address, negative, data, length, sector_status);
2035
2036 switch(ctx->image_info.MediaType)
2037 {
2038 case AppleFileWare:
2039 case AppleProfile:
2040 case AppleWidget:
2041 tag_length = 20;
2042 break;
2043 case AppleSonySS:
2044 case AppleSonyDS:
2045 tag_length = 12;
2046 break;
2047 case PriamDataTower:
2048 tag_length = 24;
2049 break;
2050 default:
2051 FATAL("Unsupported media type %d", ctx->image_info.MediaType);
2052
2053 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2055 }
2056
2057 bare_length = 512;
2058
2059 if(*length < tag_length + bare_length || data == NULL)
2060 {
2061 *length = tag_length + bare_length;
2062 FATAL("Buffer too small for sector, required %u bytes", *length);
2063
2064 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_BUFFER_TOO_SMALL");
2066 }
2067
2068 TRACE("Allocating memory for bare data of size %u bytes", bare_length);
2069 bare_data = malloc(bare_length);
2070
2071 if(bare_data == NULL)
2072 {
2073 FATAL("Could not allocate memory for bare data");
2074
2075 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2077 }
2078
2079 res = aaruf_read_sector(context, sector_address, negative, bare_data, &bare_length, sector_status);
2080
2081 if(res != AARUF_STATUS_OK)
2082 {
2083 free(bare_data);
2084
2085 TRACE("Exiting aaruf_read_sector_long() = %d", res);
2086 return res;
2087 }
2088
2089 if(bare_length != 512)
2090 {
2091 FATAL("Bare data length is %u, expected 512", bare_length);
2092 free(bare_data);
2093
2094 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2096 }
2097
2098 memcpy(data + bare_length, ctx->sector_subchannel + corrected_sector_address * tag_length,
2099 tag_length);
2100 memcpy(data, bare_data, bare_length);
2101 *length = tag_length + bare_length;
2102
2103 free(bare_data);
2104
2105 TRACE("Exiting aaruf_read_sector_long() = AARUF_STATUS_OK");
2106 return AARUF_STATUS_OK;
2107 default:
2108 FATAL("Incorrect media type %d for long sector reading", ctx->image_info.MediaType);
2109
2110 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2112 }
2113 default:
2114 FATAL("Incorrect media type %d for long sector reading", ctx->image_info.MediaType);
2115
2116 TRACE("Exiting aaruf_read_sector_long() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2118 }
2119}
2120
2240AARU_EXPORT int32_t AARU_CALL aaruf_read_sector_tag(const void *context, const uint64_t sector_address,
2241 const bool negative, uint8_t *buffer, uint32_t *length,
2242 const int32_t tag)
2243{
2244 const uint32_t initial_length = length == NULL ? 0U : *length;
2245
2246 TRACE("Entering aaruf_read_sector_tag(%p, %" PRIu64 ", %d, %p, %u, %d)", context, sector_address, negative, buffer,
2247 initial_length, tag);
2248
2249 const aaruformat_context *ctx = NULL;
2250
2251 if(context == NULL)
2252 {
2253 FATAL("Invalid context");
2254
2255 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2257 }
2258
2259 ctx = context;
2260
2261 if(length == NULL)
2262 {
2263 FATAL("Invalid length pointer");
2264
2265 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2267 }
2268
2269 // Not a libaaruformat context
2270 if(ctx->magic != AARU_MAGIC)
2271 {
2272 FATAL("Invalid context");
2273
2274 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2276 }
2277
2278 if(negative && sector_address > ctx->user_data_ddt_header.negative)
2279 {
2280 FATAL("Sector address out of bounds");
2281
2282 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2284 }
2285
2286 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
2287 {
2288 FATAL("Sector address out of bounds");
2289
2290 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2292 }
2293
2294 uint64_t corrected_sector_address = sector_address;
2295
2296 // Calculate positive or negative sector
2297 if(negative)
2298 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
2299 else
2300 corrected_sector_address += ctx->user_data_ddt_header.negative;
2301
2302 switch(tag)
2303 {
2306 {
2307 FATAL("Invalid media type for tag");
2308 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2310 }
2311
2312 if(*length != 1 || buffer == NULL)
2313 {
2314 *length = 1;
2315 FATAL("Incorrect tag size");
2316 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2318 }
2319
2320 for(int i = 0; i < ctx->tracks_header.entries; i++)
2321 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2322 {
2323 buffer[0] = ctx->track_entries[i].flags;
2324 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2325 return AARUF_STATUS_OK;
2326 }
2327
2328 FATAL("Track not found");
2332 {
2333 FATAL("Invalid media type for tag");
2334 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2336 }
2337
2338 if(*length != 12 || buffer == NULL)
2339 {
2340 *length = 12;
2341 FATAL("Incorrect tag size");
2342 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2344 }
2345
2346 for(int i = 0; i < ctx->tracks_header.entries; i++)
2347 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2348 {
2349 memcpy(buffer, ctx->track_entries[i].isrc, 12);
2350 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2351 return AARUF_STATUS_OK;
2352 }
2353
2354 FATAL("Track not found");
2358 {
2359 FATAL("Invalid media type for tag");
2360 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2362 }
2363
2364 if(*length != 96 || buffer == NULL)
2365 {
2366 *length = 96;
2367 FATAL("Incorrect tag size");
2368 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2370 }
2371
2372 if(ctx->sector_subchannel == NULL)
2373 {
2374 FATAL("Sector tag not found");
2375 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2377 }
2378
2379 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 96, 96);
2380 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2381 return AARUF_STATUS_OK;
2382 case kSectorTagDvdCmi:
2384 {
2385 FATAL("Invalid media type for tag");
2386 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2388 }
2389
2390 if(*length != 1 || buffer == NULL)
2391 {
2392 *length = 1;
2393 FATAL("Incorrect tag size");
2394 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2396 }
2397
2398 if(ctx->sector_cpr_mai == NULL)
2399 {
2400 FATAL("Sector tag not found");
2401 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2403 }
2404
2405 memcpy(buffer, ctx->sector_cpr_mai + corrected_sector_address * 6, 1);
2406 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2407 return AARUF_STATUS_OK;
2410 {
2411 FATAL("Invalid media type for tag");
2412 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2414 }
2415
2416 if(*length != 1 || buffer == NULL)
2417 {
2418 *length = 1;
2419 FATAL("Incorrect tag size");
2420 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2422 }
2423
2424 if(ctx->sector_id == NULL)
2425 {
2426 FATAL("Sector tag not found");
2427 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2429 }
2430
2431 memcpy(buffer, ctx->sector_id + corrected_sector_address * 4, 1);
2432 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2433 return AARUF_STATUS_OK;
2436 {
2437 FATAL("Invalid media type for tag");
2438 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2440 }
2441
2442 if(*length != 3 || buffer == NULL)
2443 {
2444 *length = 3;
2445 FATAL("Incorrect tag size");
2446 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2448 }
2449
2450 if(ctx->sector_id == NULL)
2451 {
2452 FATAL("Sector tag not found");
2453 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2455 }
2456
2457 memcpy(buffer, ctx->sector_id + corrected_sector_address * 4 + 1, 3);
2458 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2459 return AARUF_STATUS_OK;
2462 {
2463 FATAL("Invalid media type for tag");
2464 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2466 }
2467
2468 if(*length != 2 || buffer == NULL)
2469 {
2470 *length = 2;
2471 FATAL("Incorrect tag size");
2472 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2474 }
2475
2476 if(ctx->sector_ied == NULL)
2477 {
2478 FATAL("Sector tag not found");
2479 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2481 }
2482
2483 memcpy(buffer, ctx->sector_ied + corrected_sector_address * 2, 2);
2484 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2485 return AARUF_STATUS_OK;
2488 {
2489 FATAL("Invalid media type for tag");
2490 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2492 }
2493
2494 if(*length != 4 || buffer == NULL)
2495 {
2496 *length = 4;
2497 FATAL("Incorrect tag size");
2498 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2500 }
2501
2502 if(ctx->sector_edc == NULL)
2503 {
2504 FATAL("Sector tag not found");
2505 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2507 }
2508
2509 memcpy(buffer, ctx->sector_edc + corrected_sector_address * 4, 4);
2510 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2511 return AARUF_STATUS_OK;
2514 {
2515 FATAL("Invalid media type for tag");
2516 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2518 }
2519
2520 if(*length != 5 || buffer == NULL)
2521 {
2522 *length = 5;
2523 FATAL("Incorrect tag size");
2524 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2526 }
2527
2528 if(ctx->sector_decrypted_title_key == NULL)
2529 {
2530 FATAL("Sector tag not found");
2531 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2533 }
2534
2535 memcpy(buffer, ctx->sector_decrypted_title_key + corrected_sector_address * 5, 5);
2536 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2537 return AARUF_STATUS_OK;
2540 {
2541 FATAL("Invalid media type for tag");
2542 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2544 }
2545
2546 if(*length != 12 || buffer == NULL)
2547 {
2548 *length = 12;
2549 FATAL("Incorrect tag size");
2550 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2552 }
2553
2554 if(ctx->sector_subchannel == NULL)
2555 {
2556 FATAL("Sector tag not found");
2557 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2559 }
2560
2561 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 12, 12);
2562 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2563 return AARUF_STATUS_OK;
2566 {
2567 FATAL("Invalid media type for tag");
2568 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2570 }
2571
2572 if(*length != 20 || buffer == NULL)
2573 {
2574 *length = 20;
2575 FATAL("Incorrect tag size");
2576 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2578 }
2579
2580 if(ctx->sector_subchannel == NULL)
2581 {
2582 FATAL("Sector tag not found");
2583 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2585 }
2586
2587 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 20, 20);
2588 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2589 return AARUF_STATUS_OK;
2592 {
2593 FATAL("Invalid media type for tag");
2594 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2596 }
2597
2598 if(*length != 24 || buffer == NULL)
2599 {
2600 *length = 24;
2601 FATAL("Incorrect tag size");
2602 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2604 }
2605
2606 if(ctx->sector_subchannel == NULL)
2607 {
2608 FATAL("Sector tag not found");
2609 TRACE("Exiting aaruf_read_sector_tag() = AARUF_ERROR_SECTOR_TAG_NOT_PRESENT");
2611 }
2612
2613 memcpy(buffer, ctx->sector_subchannel + corrected_sector_address * 24, 24);
2614 TRACE("Exiting aaruf_read_sector_tag() = AARUF_STATUS_OK");
2615 return AARUF_STATUS_OK;
2616 default:
2617 TRACE("Do not know how to read sector tag %d", tag);
2619 }
2620}
#define CD_DFIX_MASK
Mask for extracting positional index (lower 24 bits) in Compact Disc suffix/prefix deduplicated block...
Definition consts.h:112
#define LZMA_PROPERTIES_LENGTH
Size in bytes of the fixed LZMA properties header (lc/lp/pb + dictionary size).
Definition consts.h:82
#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:100
#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
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
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
@ 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:1145
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:81
#define AARUF_ERROR_INCORRECT_MEDIA_TYPE
Operation incompatible with image media type.
Definition errors.h:51
#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:82
#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:662
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)
Adds a value to the cache with a uint64_t key, evicting LRU if full.
Definition lru.c:48
void * find_in_cache_uint64(struct CacheHeader *cache, uint64_t key)
Finds a value in the cache by uint64_t key.
Definition lru.c:24
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
int32_t aaruf_read_sector(void *context, const uint64_t sector_address, bool negative, uint8_t *data, uint32_t *length, uint8_t *sector_status)
Reads a sector from the AaruFormat image.
Definition read.c:352
int32_t aaruf_read_sector_long(void *context, const uint64_t sector_address, bool negative, uint8_t *data, uint32_t *length, uint8_t *sector_status)
Reads a complete sector with all metadata from the AaruFormat image.
Definition read.c:1430
int32_t aaruf_read_track_sector(void *context, uint8_t *data, const uint64_t sector_address, uint32_t *length, const uint8_t track, uint8_t *sector_status)
Reads a sector from a specific track in the AaruFormat image.
Definition read.c:1274
int32_t aaruf_read_media_tag(void *context, uint8_t *data, const int32_t tag, uint32_t *length)
Reads a media tag from the AaruFormat image.
Definition read.c:184
int32_t aaruf_read_sector_tag(const void *context, const uint64_t sector_address, const bool negative, uint8_t *buffer, uint32_t *length, const int32_t tag)
Reads a specific sector tag from the AaruFormat image.
Definition read.c:2240
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:80
uint8_t sequence
Track number (1..99 typical for CD audio/data). 0 may indicate placeholder/non-standard.
Definition optical.h:73
int64_t start
Inclusive starting LBA of the track.
Definition optical.h:75
uint8_t type
Track type (value from TrackType).
Definition optical.h:74
uint8_t isrc[13]
ISRC raw 13-byte code (no null terminator). All zeros if not present.
Definition optical.h:79
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:175
uint8_t * ps3_disc_key
Cached disc key (16 bytes), NULL if not loaded.
Definition context.h:348
bool wiiu_building_crypto_block
True while gathering sectors for re-encryption (suppresses recursion).
Definition context.h:361
DdtHeader2 user_data_ddt_header
Active user data DDT v2 header (primary table meta).
Definition context.h:192
void * wiiu_partition_regions
Parsed WiiuPartitionRegion array, NULL if not loaded.
Definition context.h:355
uint8_t * sector_cpr_mai
DVD sector CPR_MAI (6 bytes) if present.
Definition context.h:210
uint32_t ps3_plaintext_region_count
Number of plaintext regions.
Definition context.h:350
uint8_t * sector_prefix_corrected
Corrected variant (post error correction) if stored.
Definition context.h:203
uint32_t wiiu_partition_region_count
Number of partition regions.
Definition context.h:356
TrackEntry * data_tracks
Filtered list of data tracks (subset of trackEntries).
Definition context.h:246
uint8_t * wiiu_encrypted_block_cache
Cached re-encrypted 0x8000-byte physical sector.
Definition context.h:358
bool ec_recovery_in_progress
Recursion guard for recovery (prevents infinite loops).
Definition context.h:398
void * ngcw_junk_entries
Parsed NgcwJunkEntry array, NULL if not loaded.
Definition context.h:364
struct CacheHeader block_header_cache
LRU/Cache header for block headers.
Definition context.h:259
uint8_t * sector_ied
DVD sector IED (2 bytes) if present.
Definition context.h:209
uint8_t * sector_prefix
Raw per-sector prefix (e.g., sync+header) uncorrected.
Definition context.h:202
uint64_t wii_cached_physical_group
Physical group number of cached block.
Definition context.h:374
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
Definition context.h:189
uint8_t * sector_edc
DVD sector EDC (4 bytes) if present.
Definition context.h:211
CdEccContext * ecc_cd_context
CD ECC/EDC helper tables (allocated on demand).
Definition context.h:251
struct CacheHeader block_cache
LRU/Cache header for block payloads.
Definition context.h:260
bool ps3_encryption_initialized
Whether lazy init has occurred.
Definition context.h:351
uint64_t wiiu_cached_physical_sector
Physical sector number of cached block.
Definition context.h:359
uint32_t * sector_suffix_ddt
Legacy CD sector suffix DDT.
Definition context.h:187
uint8_t * sector_suffix
Raw per-sector suffix (EDC/ECC) uncorrected.
Definition context.h:204
AaruHeaderV2 header
Parsed container header (v2).
Definition context.h:178
int ddt_version
DDT version in use (1=legacy, 2=v2 hierarchical).
Definition context.h:197
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:177
uint64_t * sector_prefix_ddt2
CD sector prefix DDT V2.
Definition context.h:188
bool wii_building_crypto_block
True while gathering sectors for re-encryption (suppresses recursion).
Definition context.h:376
mediaTagEntry * mediaTags
Hash table of extra media tags (uthash root).
Definition context.h:267
uint32_t ngcw_junk_entry_count
Number of junk entries.
Definition context.h:365
uint32_t wii_partition_region_count
Number of partition regions.
Definition context.h:371
bool wiiu_encryption_initialized
Whether lazy init has occurred.
Definition context.h:357
uint8_t * sector_decrypted_title_key
DVD decrypted title key (5 bytes) if present.
Definition context.h:212
bool wii_encryption_initialized
Whether lazy init has occurred.
Definition context.h:372
uint8_t * sector_subchannel
Raw 96-byte subchannel (if captured).
Definition context.h:206
void * wii_partition_regions
Parsed WiiPartitionRegion array, NULL if not loaded.
Definition context.h:370
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:179
uint8_t * mode2_subheaders
MODE2 Form1/Form2 8-byte subheaders (concatenated).
Definition context.h:207
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:263
bool wii_cache_valid
Whether the encrypted group cache is valid.
Definition context.h:375
uint8_t * sector_id
DVD sector ID (4 bytes) if present.
Definition context.h:208
void * ps3_plaintext_regions
Parsed Ps3PlaintextRegion array (max 32), NULL if not loaded.
Definition context.h:349
uint32_t * sector_prefix_ddt
Legacy CD sector prefix DDT (deprecated by *2).
Definition context.h:186
bool wiiu_cache_valid
Whether the encrypted block cache is valid.
Definition context.h:360
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
Definition context.h:245
uint8_t number_of_data_tracks
Count of tracks considered "data" (sequence 1..99 heuristics).
Definition context.h:248
uint8_t * sector_suffix_corrected
Corrected suffix if stored separately.
Definition context.h:205
uint8_t * wii_encrypted_group_cache
Cached re-encrypted 0x8000-byte group.
Definition context.h:373
bool ngcw_junk_initialized
Whether junk map has been loaded.
Definition context.h:367
bool ec_recovery_available
True if ECMB loaded and recovery is possible.
Definition context.h:397
TracksHeader tracks_header
Tracks header (optical) if present.
Definition context.h:247
Hash table entry for an arbitrary media tag (e.g., proprietary drive/medium descriptor).
Definition context.h:122
uint8_t * data
Tag data blob (opaque to library core); length bytes long.
Definition context.h:123
uint32_t length
Length in bytes of data.
Definition context.h:125
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