libaaruformat 1.0
Aaru Data Preservation Suite - Format Library
Loading...
Searching...
No Matches
write.c
Go to the documentation of this file.
1/*
2 * This file is part of the Aaru Data Preservation Suite.
3 * Copyright (c) 2019-2025 Natalia Portillo.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 */
18#include <errno.h>
19#include <stdbool.h>
20#include <stdint.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "aaruformat.h"
26#include "internal.h"
27#include "log.h"
28#include "structs/lisa_tag.h"
29#include "xxhash.h"
30
98AARU_EXPORT int32_t AARU_CALL aaruf_write_sector(void *context, uint64_t sector_address, bool negative,
99 const uint8_t *data, uint8_t sector_status, uint32_t length)
100{
101 TRACE("Entering aaruf_write_sector(%p, %" PRIu64 ", %d, %p, %u, %u)", context, sector_address, negative, data,
102 sector_status, length);
103
104 // Check context is correct AaruFormat context
105 if(context == NULL)
106 {
107 FATAL("Invalid context");
108
109 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
111 }
112
113 aaruformat_context *ctx = context;
114
115 // Not a libaaruformat context
116 if(ctx->magic != AARU_MAGIC)
117 {
118 FATAL("Invalid context");
119
120 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
122 }
123
124 // Check we are writing
125 if(!ctx->is_writing)
126 {
127 FATAL("Trying to write a read-only image");
128
129 TRACE("Exiting aaruf_write_sector() = AARUF_READ_ONLY");
130 return AARUF_READ_ONLY;
131 }
132
133 if(negative && sector_address > ctx->user_data_ddt_header.negative)
134 {
135 FATAL("Sector address out of bounds");
136
137 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
139 }
140
141 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
142 {
143 FATAL("Sector address out of bounds");
144
145 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
147 }
148
149 if(!ctx->rewinded)
150 {
151 if(sector_address <= ctx->last_written_block)
152 {
153 if(sector_address == 0 && !ctx->block_zero_written)
154 ctx->block_zero_written = true;
155 else
156 {
157 TRACE("Rewinded");
158 ctx->rewinded = true;
159
160 // Disable MD5 calculation
161 if(ctx->calculating_md5) ctx->calculating_md5 = false;
162 // Disable SHA1 calculation
163 if(ctx->calculating_sha1) ctx->calculating_sha1 = false;
164 // Disable SHA256 calculation
165 if(ctx->calculating_sha256) ctx->calculating_sha256 = false;
166 // Disable SpamSum calculation
167 if(ctx->calculating_spamsum) ctx->calculating_spamsum = false;
168 // Disable BLAKE3 calculation
169 if(ctx->calculating_blake3) ctx->calculating_blake3 = false;
170 }
171 }
172 else
173 ctx->last_written_block = sector_address;
174 }
175
176 // Calculate MD5 on-the-fly if requested and sector is within user sectors (not negative or overflow)
177 if(ctx->calculating_md5 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
178 aaruf_md5_update(&ctx->md5_context, data, length);
179 // Calculate SHA1 on-the-fly if requested and sector is within user sectors (not negative or overflow)
180 if(ctx->calculating_sha1 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
181 aaruf_sha1_update(&ctx->sha1_context, data, length);
182 // Calculate SHA256 on-the-fly if requested and sector is within user sectors (not negative or overflow)
183 if(ctx->calculating_sha256 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
184 aaruf_sha256_update(&ctx->sha256_context, data, length);
185 // Calculate SpamSum on-the-fly if requested and sector is within user sectors (not negative or overflow)
186 if(ctx->calculating_spamsum && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
187 aaruf_spamsum_update(ctx->spamsum_context, data, length);
188 // Calculate BLAKE3 on-the-fly if requested and sector is within user sectors (not negative or overflow)
189 if(ctx->calculating_blake3 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
190 blake3_hasher_update(ctx->blake3_context, data, length);
191
192 // Mark checksum block as dirty if any checksums are being calculated
194 ctx->calculating_blake3) &&
195 !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
196 ctx->dirty_checksum_block = true;
197
198 // Close current block first
199 if(ctx->writing_buffer != NULL &&
200 // When sector size changes or block reaches maximum size
201 (ctx->current_block_header.sectorSize != length ||
203 {
204 TRACE("Closing current block before writing new data");
205 int error = aaruf_close_current_block(ctx);
206
207 if(error != AARUF_STATUS_OK)
208 {
209 FATAL("Error closing current block: %d", error);
210
211 TRACE("Exiting aaruf_write_sector() = %d", error);
212 return error;
213 }
214 }
215
216 uint64_t ddt_entry = 0;
217 bool ddt_ok;
218
219 if(ctx->deduplicate)
220 {
221 // Calculate 64-bit XXH3 hash of the sector
222 TRACE("Hashing sector data for deduplication");
223 uint64_t hash = XXH3_64bits(data, length);
224
225 // Check if the hash is already in the map
226 bool existing = lookup_map(ctx->sector_hash_map, hash, &ddt_entry);
227 TRACE("Block does %s exist in deduplication map", existing ? "already" : "not yet");
228
229 ddt_ok = set_ddt_entry_v2(ctx, sector_address, negative, ctx->current_block_offset, ctx->next_block_position,
230 sector_status, &ddt_entry);
231 if(!ddt_ok)
232 {
233 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_CANNOT_SET_DDT_ENTRY");
235 }
236
237 if(existing)
238 {
239 TRACE("Sector exists, so not writing to image");
240 TRACE("Exiting aaruf_write_sector() = AARUF_STATUS_OK");
241 return AARUF_STATUS_OK;
242 }
243
244 TRACE("Inserting sector hash into deduplication map, proceeding to write into image as normal");
245 insert_map(ctx->sector_hash_map, hash, ddt_entry);
246 }
247 else
248 ddt_ok = set_ddt_entry_v2(ctx, sector_address, negative, ctx->current_block_offset, ctx->next_block_position,
249 sector_status, &ddt_entry);
250
251 if(!ddt_ok)
252 {
253 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_CANNOT_SET_DDT_ENTRY");
255 }
256
257 // No block set
258 if(ctx->writing_buffer_position == 0)
259 {
260 TRACE("Creating new writing block");
263 ctx->current_block_header.sectorSize = length;
264
265 // We need to save the track type for later compression
266 if(ctx->image_info.MetadataMediaType == OpticalDisc && ctx->track_entries != NULL)
267 {
268 const TrackEntry *track = NULL;
269 for(int i = 0; i < ctx->tracks_header.entries; i++)
270 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
271 {
272 track = &ctx->track_entries[i];
273 break;
274 }
275
276 if(track != NULL)
277 {
278 ctx->current_track_type = track->type;
279
280 if(track->sequence == 0 && track->start == 0 && track->end == 0) ctx->current_track_type = Data;
281 }
282 else
284
285 if(ctx->current_track_type == Audio &&
286 // JaguarCD stores data in audio tracks. FLAC is too inefficient, we need to use LZMA as data.
287 (ctx->image_info.MediaType == JaguarCD && track->session > 1 ||
288 // VideoNow stores video in audio tracks, and LZMA works better too.
292
293 if(ctx->compression_enabled)
294 {
295 if(ctx->current_track_type == Audio)
297 else
299 }
300 else
302 }
303 else
304 {
306 if(ctx->compression_enabled)
308 else
310 }
311
312 uint32_t max_buffer_size =
314 TRACE("Setting max buffer size to %u bytes", max_buffer_size);
315
316 TRACE("Allocating memory for writing buffer");
317 ctx->writing_buffer = (uint8_t *)calloc(1, max_buffer_size);
318 if(ctx->writing_buffer == NULL)
319 {
320 FATAL("Could not allocate memory");
321
322 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
324 }
325 }
326
327 TRACE("Copying data to writing buffer at position %zu", ctx->writing_buffer_position);
328 memcpy(ctx->writing_buffer + ctx->writing_buffer_position, data, length);
329 TRACE("Advancing writing buffer position to %zu", ctx->writing_buffer_position + length);
330 ctx->writing_buffer_position += length;
331 TRACE("Advancing current block offset to %zu", ctx->current_block_offset + 1);
333
334 TRACE("Exiting aaruf_write_sector() = AARUF_STATUS_OK");
335 return AARUF_STATUS_OK;
336}
337
544AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t sector_address, bool negative,
545 const uint8_t *data, uint8_t sector_status, uint32_t length)
546{
547 TRACE("Entering aaruf_write_sector_long(%p, %" PRIu64 ", %d, %p, %u, %u)", context, sector_address, negative, data,
548 sector_status, length);
549
550 // Check context is correct AaruFormat context
551 if(context == NULL)
552 {
553 FATAL("Invalid context");
554
555 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
557 }
558
559 aaruformat_context *ctx = context;
560
561 // Not a libaaruformat context
562 if(ctx->magic != AARU_MAGIC)
563 {
564 FATAL("Invalid context");
565
566 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
568 }
569
570 // Check we are writing
571 if(!ctx->is_writing)
572 {
573 FATAL("Trying to write a read-only image");
574
575 TRACE("Exiting aaruf_write_sector() = AARUF_READ_ONLY");
576 return AARUF_READ_ONLY;
577 }
578
579 if(negative && sector_address > ctx->user_data_ddt_header.negative)
580 {
581 FATAL("Sector address out of bounds");
582
583 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
585 }
586
587 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
588 {
589 FATAL("Sector address out of bounds");
590
591 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
593 }
594
595 switch(ctx->image_info.MetadataMediaType)
596 {
597 case OpticalDisc:
598 {
599 TrackEntry track = {0};
600
601 for(int i = 0; i < ctx->tracks_header.entries; i++)
602 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
603 {
604 track = ctx->track_entries[i];
605 break;
606 }
607
608 if(track.sequence == 0 && track.start == 0 && track.end == 0) track.type = Data;
609
610 uint64_t corrected_sector_address = sector_address;
611
612 // Calculate positive or negative sector
613 if(negative)
614 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
615 else
616 corrected_sector_address += ctx->user_data_ddt_header.negative;
617
618 uint64_t total_sectors =
620
621 // DVD long sector
622 if(length == 2064 && (ctx->image_info.MediaType == DVDROM || ctx->image_info.MediaType == PS2DVD ||
623 ctx->image_info.MediaType == SACD || ctx->image_info.MediaType == PS3DVD ||
624 ctx->image_info.MediaType == DVDR || ctx->image_info.MediaType == DVDRW ||
629 ctx->image_info.MediaType == Nuon))
630 {
631 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
632 if(ctx->sector_ied == NULL) ctx->sector_ied = calloc(1, 2 * total_sectors);
633 if(ctx->sector_cpr_mai == NULL) ctx->sector_cpr_mai = calloc(1, 6 * total_sectors);
634 if(ctx->sector_edc == NULL) ctx->sector_edc = calloc(1, 4 * total_sectors);
635
636 memcpy(ctx->sector_id + corrected_sector_address * 4, data, 4);
637 memcpy(ctx->sector_ied + corrected_sector_address * 2, data + 4, 2);
638 memcpy(ctx->sector_cpr_mai + corrected_sector_address * 6, data + 6, 6);
639 memcpy(ctx->sector_edc + corrected_sector_address * 4, data + 2060, 4);
640
641 return aaruf_write_sector(context, sector_address, negative, data + 12, sector_status, 2048);
642 }
643
644 if(length != 2352)
645 {
646 FATAL("Incorrect sector size");
647 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
649 }
650
651 ctx->writing_long = true;
652
653 if(!ctx->rewinded)
654 {
655 if(sector_address <= ctx->last_written_block)
656 {
657 if(sector_address == 0 && !ctx->block_zero_written)
658 ctx->block_zero_written = true;
659 else
660 {
661 TRACE("Rewinded");
662 ctx->rewinded = true;
663
664 // Disable MD5 calculation
665 if(ctx->calculating_md5) ctx->calculating_md5 = false;
666 // Disable SHA1 calculation
667 if(ctx->calculating_sha1) ctx->calculating_sha1 = false;
668 // Disable SHA256 calculation
669 if(ctx->calculating_sha256) ctx->calculating_sha256 = false;
670 // Disable SpamSum calculation
671 if(ctx->calculating_spamsum) ctx->calculating_spamsum = false;
672 // Disable BLAKE3 calculation
673 if(ctx->calculating_blake3) ctx->calculating_blake3 = false;
674 }
675 }
676 else
677 ctx->last_written_block = sector_address;
678 }
679
680 // Calculate MD5 on-the-fly if requested and sector is within user sectors (not negative or overflow)
681 if(ctx->calculating_md5 && !negative && sector_address <= ctx->image_info.Sectors)
682 aaruf_md5_update(&ctx->md5_context, data, length);
683 // Calculate SHA1 on-the-fly if requested and sector is within user sectors (not negative or overflow)
684 if(ctx->calculating_sha1 && !negative && sector_address <= ctx->image_info.Sectors)
685 aaruf_sha1_update(&ctx->sha1_context, data, length);
686 // Calculate SHA256 on-the-fly if requested and sector is within user sectors (not negative or overflow)
687 if(ctx->calculating_sha256 && !negative && sector_address <= ctx->image_info.Sectors)
688 aaruf_sha256_update(&ctx->sha256_context, data, length);
689 // Calculate SpamSum on-the-fly if requested and sector is within user sectors (not negative or overflow)
690 if(ctx->calculating_spamsum && !negative && sector_address <= ctx->image_info.Sectors)
691 aaruf_spamsum_update(ctx->spamsum_context, data, length);
692 // Calculate BLAKE3 on-the-fly if requested and sector is within user sectors (not negative or overflow)
693 if(ctx->calculating_blake3 && !negative && sector_address <= ctx->image_info.Sectors)
694 blake3_hasher_update(ctx->blake3_context, data, length);
695
696 bool prefix_correct;
697
698 // Split raw cd sector data in prefix (sync, header), user data and suffix (edc, ecc p, ecc q)
699 switch(track.type)
700 {
701 case Audio:
702 case Data:
703 return aaruf_write_sector(context, sector_address, negative, data, sector_status, length);
704 case CdMode1:
705
706 // If we do not have a DDT V2 for sector prefix, create one
707 if(ctx->sector_prefix_ddt2 == NULL)
708 {
709 ctx->sector_prefix_ddt2 =
710 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
712
713 if(ctx->sector_prefix_ddt2 == NULL)
714 {
715 FATAL("Could not allocate memory for CD sector prefix DDT");
716
717 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
719 }
720 }
721
722 // If we do not have a DDT V2 for sector suffix, create one
723 if(ctx->sector_suffix_ddt2 == NULL)
724 {
725 ctx->sector_suffix_ddt2 =
726 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
728
729 if(ctx->sector_suffix_ddt2 == NULL)
730 {
731 FATAL("Could not allocate memory for CD sector prefix DDT");
732
733 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
735 }
736 }
737
738 if(ctx->sector_prefix == NULL)
739 {
742 ctx->sector_prefix = malloc(ctx->sector_prefix_length);
743
744 if(ctx->sector_prefix == NULL)
745 {
746 FATAL("Could not allocate memory for CD sector prefix buffer");
747
748 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
750 }
751 }
752
753 if(ctx->sector_suffix == NULL)
754 {
758 ctx->sector_suffix = malloc(ctx->sector_suffix_length);
759
760 if(ctx->sector_suffix == NULL)
761 {
762 FATAL("Could not allocate memory for CD sector suffix buffer");
763
764 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
766 }
767 }
768
769 bool empty = true;
770
771 for(int i = 0; i < length; i++)
772 if(data[i] != 0)
773 {
774 empty = false;
775 break;
776 }
777
778 if(empty)
779 {
780 ctx->sector_prefix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
781 ctx->sector_suffix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
782 ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty
783 ctx->dirty_sector_suffix_ddt = true; // Mark suffix DDT as dirty
784 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
785 2048);
786 }
787
788 prefix_correct = true;
789
790 if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
791 data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
792 data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
793 data[0x0F] != 0x01)
794 prefix_correct = false;
795
796 if(prefix_correct)
797 {
798 const int minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
799 const int second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
800 const int frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
801 const int stored_lba = minute * 60 * 75 + second * 75 + frame - 150;
802 prefix_correct = stored_lba == sector_address;
803 }
804
805 if(prefix_correct)
806 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode1Correct << 60;
807 else
808 {
809 // Copy CD prefix from data buffer to prefix buffer
810 memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
811 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_prefix_offset / 16);
812 ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
813 ctx->sector_prefix_offset += 16;
814 ctx->dirty_sector_prefix_block = true; // Mark prefix block as dirty
815
816 // Grow prefix buffer if needed
818 {
819 ctx->sector_prefix_length *= 2;
820 ctx->sector_prefix = realloc(ctx->sector_prefix, ctx->sector_prefix_length);
821
822 if(ctx->sector_prefix == NULL)
823 {
824 FATAL("Could not allocate memory for CD sector prefix buffer");
825
826 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
828 }
829 }
830 }
831 ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty
832
833 const bool suffix_correct = aaruf_ecc_cd_is_suffix_correct(ctx->ecc_cd_context, data);
834
835 if(suffix_correct)
836 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode1Correct << 60;
837 else
838 {
839 // Copy CD suffix from data buffer to suffix buffer
840 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2064, 288);
841 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288);
842 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
843 ctx->sector_suffix_offset += 288;
844 ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty
845
846 // Grow suffix buffer if needed
848 {
849 ctx->sector_suffix_length *= 2;
850 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
851
852 if(ctx->sector_suffix == NULL)
853 {
854 FATAL("Could not allocate memory for CD sector suffix buffer");
855
856 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
858 }
859 }
860 }
861 ctx->dirty_sector_suffix_ddt = true; // Mark suffix DDT as dirty
862
863 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusMode1Correct,
864 2048);
865 case CdMode2Form1:
866 case CdMode2Form2:
867 case CdMode2Formless:
868 // If we do not have a DDT V2 for sector prefix, create one
869 if(ctx->sector_prefix_ddt2 == NULL)
870 {
871 ctx->sector_prefix_ddt2 =
872 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
874
875 if(ctx->sector_prefix_ddt2 == NULL)
876 {
877 FATAL("Could not allocate memory for CD sector prefix DDT");
878
879 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
881 }
882 }
883
884 // If we do not have a DDT V2 for sector suffix, create one
885 if(ctx->sector_suffix_ddt2 == NULL)
886 {
887 ctx->sector_suffix_ddt2 =
888 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
890
891 if(ctx->sector_suffix_ddt2 == NULL)
892 {
893 FATAL("Could not allocate memory for CD sector prefix DDT");
894
895 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
897 }
898 }
899
900 if(ctx->sector_prefix == NULL)
901 {
904 ctx->sector_prefix = malloc(ctx->sector_prefix_length);
905
906 if(ctx->sector_prefix == NULL)
907 {
908 FATAL("Could not allocate memory for CD sector prefix buffer");
909
910 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
912 }
913 }
914
915 if(ctx->sector_suffix == NULL)
916 {
920 ctx->sector_suffix = malloc(ctx->sector_suffix_length);
921
922 if(ctx->sector_suffix == NULL)
923 {
924 FATAL("Could not allocate memory for CD sector suffix buffer");
925
926 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
928 }
929 }
930
931 empty = true;
932
933 for(int i = 0; i < length; i++)
934 if(data[i] != 0)
935 {
936 empty = false;
937 break;
938 }
939
940 if(empty)
941 {
942 ctx->sector_prefix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
943 ctx->sector_suffix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
944 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
945 2328);
946 }
947
948 const bool form2 = (data[18] & 0x20) == 0x20 || (data[22] & 0x20) == 0x20;
949
950 prefix_correct = true;
951
952 if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
953 data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
954 data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
955 data[0x0F] != 0x02)
956 prefix_correct = false;
957
958 if(prefix_correct)
959 {
960 const int minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
961 const int second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
962 const int frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
963 const int stored_lba = minute * 60 * 75 + second * 75 + frame - 150;
964 prefix_correct = stored_lba == sector_address;
965 }
966
967 if(prefix_correct)
968 ctx->sector_prefix_ddt2[corrected_sector_address] =
969 (uint64_t)(form2 ? SectorStatusMode2Form2Ok : SectorStatusMode2Form1Ok) << 60;
970 else
971 {
972 // Copy CD prefix from data buffer to prefix buffer
973 memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
974 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint32_t)(ctx->sector_prefix_offset / 16);
975 ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
976 ctx->sector_prefix_offset += 16;
977 ctx->dirty_sector_prefix_block = true; // Mark prefix block as dirty
978
979 // Grow prefix buffer if needed
981 {
982 ctx->sector_prefix_length *= 2;
983 ctx->sector_prefix = realloc(ctx->sector_prefix, ctx->sector_prefix_length);
984
985 if(ctx->sector_prefix == NULL)
986 {
987 FATAL("Could not allocate memory for CD sector prefix buffer");
988
989 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
991 }
992 }
993 }
994 ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty
995
996 if(ctx->mode2_subheaders == NULL)
997 {
998 ctx->mode2_subheaders =
999 calloc(1, 8 * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
1001
1002 if(ctx->mode2_subheaders == NULL)
1003 {
1004 FATAL("Could not allocate memory for CD mode 2 subheader buffer");
1005
1006 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1008 }
1009 }
1010
1011 if(form2)
1012 {
1013 const uint32_t computed_edc = aaruf_edc_cd_compute(ctx->ecc_cd_context, 0, data, 0x91C, 0x10);
1014 uint32_t edc = 0;
1015 memcpy(&edc, data + 0x92C, sizeof(edc));
1016 const bool correct_edc = computed_edc == edc;
1017
1018 if(correct_edc)
1019 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form2Ok
1020 << 60;
1021 else if(edc == 0)
1022 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form2NoCrc
1023 << 60;
1024 else
1025 {
1026 // Copy CD suffix from data buffer to suffix buffer
1027 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2348, 4);
1028 ctx->sector_suffix_ddt2[corrected_sector_address] =
1029 (uint64_t)(ctx->sector_suffix_offset / 288);
1030 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
1031 ctx->sector_suffix_offset += 288;
1032 ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty
1033
1034 // Grow suffix buffer if needed
1036 {
1037 ctx->sector_suffix_length *= 2;
1038 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
1039
1040 if(ctx->sector_suffix == NULL)
1041 {
1042 FATAL("Could not allocate memory for CD sector suffix buffer");
1043
1044 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1046 }
1047 }
1048 }
1049
1050 // Copy subheader from data buffer to subheader buffer
1051 memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8);
1052 ctx->dirty_sector_prefix_ddt = true;
1053 ctx->dirty_sector_suffix_ddt = true;
1054 ctx->dirty_mode2_subheaders_block = true;
1055 return aaruf_write_sector(context, sector_address, negative, data + 24,
1057 : correct_edc ? SectorStatusMode2Form2Ok
1059 2324);
1060 }
1061
1062 const bool correct_ecc = aaruf_ecc_cd_is_suffix_correct_mode2(ctx->ecc_cd_context, data);
1063 const uint32_t computed_edc = aaruf_edc_cd_compute(ctx->ecc_cd_context, 0, data, 0x808, 0x10);
1064 uint32_t edc = 0;
1065 memcpy(&edc, data + 0x818, sizeof(edc));
1066 const bool correct_edc = computed_edc == edc;
1067
1068 if(correct_ecc && correct_edc)
1069 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form1Ok << 60;
1070 else
1071 {
1072 // Copy CD suffix from data buffer to suffix buffer
1073 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2072, 280);
1074 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288);
1075 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
1076 ctx->sector_suffix_offset += 288;
1077 ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty
1078
1079 // Grow suffix buffer if needed
1081 {
1082 ctx->sector_suffix_length *= 2;
1083 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
1084
1085 if(ctx->sector_suffix == NULL)
1086 {
1087 FATAL("Could not allocate memory for CD sector suffix buffer");
1088
1089 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1091 }
1092 }
1093 }
1094
1095 // Copy subheader from data buffer to subheader buffer
1096 memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8);
1097 ctx->dirty_sector_prefix_ddt = true;
1098 ctx->dirty_sector_suffix_ddt = true;
1099 ctx->dirty_mode2_subheaders_block = true;
1100 return aaruf_write_sector(
1101 context, sector_address, negative, data + 24,
1102 correct_edc && correct_ecc ? SectorStatusMode2Form1Ok : SectorStatusErrored, 2048);
1103 }
1104
1105 break;
1106 }
1107 case BlockMedia:
1108 switch(ctx->image_info.MediaType)
1109 {
1110 case AppleFileWare:
1111 case AppleProfile:
1112 case AppleSonyDS:
1113 case AppleSonySS:
1114 case AppleWidget:
1115 case PriamDataTower:
1116 {
1117 uint8_t *newTag;
1118 int newTagSize = 0;
1119
1120 switch(length - 512)
1121 {
1122 // Sony tag
1123 case 12:
1124 {
1125 const sony_tag decoded_sony_tag = bytes_to_sony_tag(data + 512);
1126
1128 {
1129 const profile_tag decoded_profile_tag = sony_tag_to_profile(decoded_sony_tag);
1130 newTag = profile_tag_to_bytes(decoded_profile_tag);
1131 newTagSize = 20;
1132 }
1133 else if(ctx->image_info.MediaType == PriamDataTower)
1134 {
1135 const priam_tag decoded_priam_tag = sony_tag_to_priam(decoded_sony_tag);
1136 newTag = priam_tag_to_bytes(decoded_priam_tag);
1137 newTagSize = 24;
1138 }
1139 else if(ctx->image_info.MediaType == AppleSonyDS ||
1141 {
1142 newTag = malloc(12);
1143 memcpy(newTag, data + 512, 12);
1144 newTagSize = 12;
1145 }
1146 break;
1147 }
1148 // Profile tag
1149 case 20:
1150 {
1151 const profile_tag decoded_profile_tag = bytes_to_profile_tag(data + 512);
1152
1154 {
1155 newTag = malloc(20);
1156 memcpy(newTag, data + 512, 20);
1157 newTagSize = 20;
1158 }
1159 else if(ctx->image_info.MediaType == PriamDataTower)
1160 {
1161 const priam_tag decoded_priam_tag = profile_tag_to_priam(decoded_profile_tag);
1162 newTag = priam_tag_to_bytes(decoded_priam_tag);
1163 newTagSize = 24;
1164 }
1165 else if(ctx->image_info.MediaType == AppleSonyDS ||
1167 {
1168 const sony_tag decoded_sony_tag = profile_tag_to_sony(decoded_profile_tag);
1169 newTag = sony_tag_to_bytes(decoded_sony_tag);
1170 newTagSize = 12;
1171 }
1172 break;
1173 }
1174 // Priam tag
1175 case 24:
1176 {
1177 const priam_tag decoded_priam_tag = bytes_to_priam_tag(data + 512);
1179 {
1180 const profile_tag decoded_profile_tag = priam_tag_to_profile(decoded_priam_tag);
1181 newTag = profile_tag_to_bytes(decoded_profile_tag);
1182 newTagSize = 20;
1183 }
1184 else if(ctx->image_info.MediaType == PriamDataTower)
1185 {
1186 newTag = malloc(24);
1187 memcpy(newTag, data + 512, 24);
1188 newTagSize = 24;
1189 }
1190 else if(ctx->image_info.MediaType == AppleSonyDS ||
1192 {
1193 const sony_tag decoded_sony_tag = priam_tag_to_sony(decoded_priam_tag);
1194 newTag = sony_tag_to_bytes(decoded_sony_tag);
1195 newTagSize = 12;
1196 }
1197 break;
1198 }
1199 case 0:
1200 newTagSize = 0;
1201 break;
1202 default:
1203 FATAL("Incorrect sector size");
1204 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1206 }
1207
1208 if(newTagSize == 0)
1209 return aaruf_write_sector(context, sector_address, negative, data, sector_status, 512);
1210
1211 if(ctx->sector_subchannel == NULL)
1212 {
1213 ctx->sector_subchannel =
1214 calloc(1, newTagSize * (ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow));
1215
1216 if(ctx->sector_subchannel == NULL)
1217 {
1218 FATAL("Could not allocate memory for sector subchannel DDT");
1219
1220 free(newTag);
1221
1222 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1224 }
1225 }
1226
1227 memcpy(ctx->sector_subchannel + sector_address * newTagSize, newTag, newTagSize);
1228 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
1229 free(newTag);
1230
1231 return aaruf_write_sector(context, sector_address, negative, data, sector_status, 512);
1232 }
1233 default:
1235 }
1236 default:
1237 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
1239 }
1240
1241 // Fallback return when media type branch does not produce a value (satisfy non-void contract)
1243}
1244
1428{
1429 // Not a libaaruformat context
1430 if(ctx->magic != AARU_MAGIC) return AARUF_ERROR_NOT_AARUFORMAT;
1431
1432 // Check we are writing
1433 if(!ctx->is_writing) return AARUF_READ_ONLY;
1434
1436
1437 TRACE("Initializing CRC64 context");
1439 TRACE("Updating CRC64");
1442
1443 uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH] = {0};
1444 uint8_t *cmp_buffer = NULL;
1445
1447 {
1448 case None:
1449 break;
1450 case Flac:
1451 cmp_buffer = malloc(ctx->current_block_header.length * 2);
1452 if(cmp_buffer == NULL)
1453 {
1454 FATAL("Could not allocate buffer for compressed data");
1456 }
1457 const uint32_t current_samples = ctx->current_block_offset * SAMPLES_PER_SECTOR;
1458 uint32_t flac_block_size = ctx->current_block_offset * SAMPLES_PER_SECTOR;
1459
1460 if(flac_block_size > MAX_FLAKE_BLOCK) flac_block_size = MAX_FLAKE_BLOCK;
1461 if(flac_block_size < MIN_FLAKE_BLOCK) flac_block_size = MIN_FLAKE_BLOCK;
1462
1463 const long remaining = current_samples % flac_block_size;
1464
1465 // Fill FLAC block
1466 if(remaining != 0)
1467 for(int r = 0; r < remaining * 4; r++) ctx->writing_buffer[ctx->writing_buffer_position + r] = 0;
1468
1470 cmp_buffer, ctx->current_block_header.length * 2, ctx->writing_buffer, ctx->current_block_header.length,
1471 flac_block_size, true, false, "hamming", 12, 15, true, false, 0, 8, "Aaru", 4);
1472
1474 {
1476 free(cmp_buffer);
1477 }
1478
1479 break;
1480 case Lzma:
1481 cmp_buffer = malloc(ctx->current_block_header.length * 2);
1482 if(cmp_buffer == NULL)
1483 {
1484 FATAL("Could not allocate buffer for compressed data");
1486 }
1487
1488 size_t dst_size = ctx->current_block_header.length * 2;
1489 size_t props_size = LZMA_PROPERTIES_LENGTH;
1490 aaruf_lzma_encode_buffer(cmp_buffer, &dst_size, ctx->writing_buffer, ctx->current_block_header.length,
1491 lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
1492
1493 ctx->current_block_header.cmpLength = (uint32_t)dst_size;
1494
1496 {
1498 free(cmp_buffer);
1499 }
1500
1501 break;
1502 default:
1503 FATAL("Invalid compression type");
1505 }
1506
1508 {
1511 }
1512 else
1514
1516
1517 // Add to index
1518 TRACE("Adding block to index");
1519 IndexEntry index_entry;
1520 index_entry.blockType = DataBlock;
1521 index_entry.dataType = UserData;
1522 index_entry.offset = ctx->next_block_position;
1523
1524 utarray_push_back(ctx->index_entries, &index_entry);
1525 ctx->dirty_index_block = true; // Mark index block as dirty
1526 TRACE("Block added to index at offset %" PRIu64, index_entry.offset);
1527
1528 // Write block header to file
1529
1530 // Move to expected block position
1531 fseek(ctx->imageStream, ctx->next_block_position, SEEK_SET);
1532
1533 // Write block header
1534 if(fwrite(&ctx->current_block_header, sizeof(BlockHeader), 1, ctx->imageStream) != 1)
1536
1537 // Write block data
1539 fwrite(lzma_properties, LZMA_PROPERTIES_LENGTH, 1, ctx->imageStream) != 1)
1540 {
1541 free(cmp_buffer);
1543 }
1544
1546 {
1547 if(fwrite(ctx->writing_buffer, ctx->current_block_header.length, 1, ctx->imageStream) != 1)
1549 }
1550 else
1551 {
1552 if(fwrite(cmp_buffer, ctx->current_block_header.cmpLength, 1, ctx->imageStream) != 1)
1553 {
1554 free(cmp_buffer);
1556 }
1557
1558 free(cmp_buffer);
1559 }
1560
1561 // Update nextBlockPosition to point to the next available aligned position
1562 const uint64_t block_total_size = sizeof(BlockHeader) + ctx->current_block_header.cmpLength;
1563 const uint64_t alignment_mask = (1ULL << ctx->user_data_ddt_header.blockAlignmentShift) - 1;
1564 ctx->next_block_position = ctx->next_block_position + block_total_size + alignment_mask & ~alignment_mask;
1565 TRACE("Updated nextBlockPosition to %" PRIu64, ctx->next_block_position);
1566
1567 // Clear values
1568 free(ctx->writing_buffer);
1569 ctx->writing_buffer = NULL;
1570 ctx->current_block_offset = 0;
1571 memset(&ctx->current_block_header, 0, sizeof(BlockHeader));
1573 ctx->writing_buffer_position = 0;
1574
1575 return AARUF_STATUS_OK;
1576}
1577
1825AARU_EXPORT int32_t AARU_CALL aaruf_write_media_tag(void *context, const uint8_t *data, const int32_t type,
1826 const uint32_t length)
1827{
1828 TRACE("Entering aaruf_write_media_tag(%p, %p, %d, %d)", context, data, type, length);
1829
1830 // Check context is correct AaruFormat context
1831 if(context == NULL)
1832 {
1833 FATAL("Invalid context");
1834
1835 TRACE("Exiting aaruf_write_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
1837 }
1838
1839 aaruformat_context *ctx = context;
1840
1841 // Not a libaaruformat context
1842 if(ctx->magic != AARU_MAGIC)
1843 {
1844 FATAL("Invalid context");
1845
1846 TRACE("Exiting aaruf_write_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
1848 }
1849
1850 // Check we are writing
1851 if(!ctx->is_writing)
1852 {
1853 FATAL("Trying to write a read-only image");
1854
1855 TRACE("Exiting aaruf_write_media_tag() = AARUF_READ_ONLY");
1856 return AARUF_READ_ONLY;
1857 }
1858
1859 if(data == NULL || length == 0)
1860 {
1861 FATAL("Invalid data or length");
1863 }
1864
1865 uint8_t *new_data = malloc(length);
1866
1867 if(new_data == NULL)
1868 {
1869 FATAL("Could not allocate memory for media tag");
1871 }
1872 memcpy(new_data, data, length);
1873
1874 mediaTagEntry *media_tag = malloc(sizeof(mediaTagEntry));
1875 mediaTagEntry *old_media_tag = NULL;
1876
1877 if(media_tag == NULL)
1878 {
1879 TRACE("Cannot allocate memory for media tag entry.");
1880 free(new_data);
1882 }
1883
1884 memset(media_tag, 0, sizeof(mediaTagEntry));
1885
1886 media_tag->type = type;
1887 media_tag->data = new_data;
1888 media_tag->length = length;
1889
1890 HASH_REPLACE_INT(ctx->mediaTags, type, media_tag, old_media_tag);
1891
1892 if(old_media_tag != NULL)
1893 {
1894 TRACE("Replaced media tag with type %d", old_media_tag->type);
1895 free(old_media_tag->data);
1896 free(old_media_tag);
1897 old_media_tag = NULL;
1898 }
1899
1900 ctx->dirty_media_tags = true; // Mark media tags as dirty
1901 TRACE("Exiting aaruf_write_media_tag() = AARUF_STATUS_OK");
1902 return AARUF_STATUS_OK;
1903}
1904
2095AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64_t sector_address, const bool negative,
2096 const uint8_t *data, const size_t length, const int32_t tag)
2097{
2098 TRACE("Entering aaruf_write_sector_tag(%p, %" PRIu64 ", %d, %p, %zu, %d)", context, sector_address, negative, data,
2099 length, tag);
2100
2101 // Check context is correct AaruFormat context
2102 if(context == NULL)
2103 {
2104 FATAL("Invalid context");
2105
2106 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2108 }
2109
2110 aaruformat_context *ctx = context;
2111
2112 // Not a libaaruformat context
2113 if(ctx->magic != AARU_MAGIC)
2114 {
2115 FATAL("Invalid context");
2116
2117 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2119 }
2120
2121 // Check we are writing
2122 if(!ctx->is_writing)
2123 {
2124 FATAL("Trying to write a read-only image");
2125
2126 TRACE("Exiting aaruf_write_sector_tag() = AARUF_READ_ONLY");
2127 return AARUF_READ_ONLY;
2128 }
2129
2130 if(negative && sector_address > ctx->user_data_ddt_header.negative)
2131 {
2132 FATAL("Sector address out of bounds");
2133
2134 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2136 }
2137
2138 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
2139 {
2140 FATAL("Sector address out of bounds");
2141
2142 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2144 }
2145
2146 if(data == NULL || length == 0)
2147 {
2148 FATAL("Invalid data or length");
2150 }
2151
2152 uint64_t corrected_sector_address = sector_address;
2153
2154 // Calculate positive or negative sector
2155 if(negative)
2156 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
2157 else
2158 corrected_sector_address += ctx->user_data_ddt_header.negative;
2159
2160 const uint64_t total_sectors =
2162
2163 switch(tag)
2164 {
2165 case CdTrackFlags:
2167 {
2168 FATAL("Invalid media type for tag");
2169 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2171 }
2172
2173 if(length != 1)
2174 {
2175 FATAL("Incorrect tag size");
2176 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2178 }
2179
2180 for(int i = 0; i < ctx->tracks_header.entries; i++)
2181 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2182 {
2183 ctx->track_entries[i].flags = data[0];
2184 ctx->dirty_tracks_block = true; // Mark tracks block as dirty
2185 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2186 return AARUF_STATUS_OK;
2187 }
2188
2189 FATAL("Track not found");
2191 case CdTrackIsrc:
2193 {
2194 FATAL("Invalid media type for tag");
2195 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2197 }
2198
2199 if(length != 12)
2200 {
2201 FATAL("Incorrect tag size");
2202 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2204 }
2205
2206 for(int i = 0; i < ctx->tracks_header.entries; i++)
2207 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2208 {
2209 memcpy(ctx->track_entries[i].isrc, data, 12);
2210 ctx->dirty_tracks_block = true; // Mark tracks block as dirty
2211 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2212 return AARUF_STATUS_OK;
2213 }
2214
2215 FATAL("Track not found");
2219 {
2220 FATAL("Invalid media type for tag");
2221 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2223 }
2224
2225 if(length != 96)
2226 {
2227 FATAL("Incorrect tag size");
2228 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2230 }
2231
2232 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 96 * total_sectors);
2233
2234 if(ctx->sector_subchannel == NULL)
2235 {
2236 FATAL("Could not allocate memory for sector subchannel");
2237
2238 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2240 }
2241
2242 memcpy(ctx->sector_subchannel + corrected_sector_address * 96, data, 96);
2243 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2244 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2245 return AARUF_STATUS_OK;
2246 case DvdCmi:
2248 {
2249 FATAL("Invalid media type for tag");
2250 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2252 }
2253
2254 if(length != 1)
2255 {
2256 FATAL("Incorrect tag size");
2257 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2259 }
2260
2261 if(ctx->sector_cpr_mai == NULL) ctx->sector_cpr_mai = calloc(1, 6 * total_sectors);
2262
2263 if(ctx->sector_cpr_mai == NULL)
2264 {
2265 FATAL("Could not allocate memory for sector CPR/MAI");
2266
2267 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2269 }
2270
2271 memcpy(ctx->sector_cpr_mai + corrected_sector_address * 6, data, 1);
2272 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2273 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2274 return AARUF_STATUS_OK;
2277 {
2278 FATAL("Invalid media type for tag");
2279 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2281 }
2282
2283 if(length != 1)
2284 {
2285 FATAL("Incorrect tag size");
2286 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2288 }
2289
2290 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
2291
2292 if(ctx->sector_id == NULL)
2293 {
2294 FATAL("Could not allocate memory for sector ID");
2295
2296 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2298 }
2299
2300 memcpy(ctx->sector_id + corrected_sector_address * 4, data, 1);
2301 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2302 return AARUF_STATUS_OK;
2303 case DvdSectorNumber:
2305 {
2306 FATAL("Invalid media type for tag");
2307 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2309 }
2310
2311 if(length != 3)
2312 {
2313 FATAL("Incorrect tag size");
2314 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2316 }
2317
2318 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
2319
2320 if(ctx->sector_id == NULL)
2321 {
2322 FATAL("Could not allocate memory for sector ID");
2323
2324 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2326 }
2327
2328 memcpy(ctx->sector_id + corrected_sector_address * 4 + 1, data, 3);
2329 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2330 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2331 return AARUF_STATUS_OK;
2332 case DvdSectorIedAaru:
2334 {
2335 FATAL("Invalid media type for tag");
2336 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2338 }
2339
2340 if(length != 2)
2341 {
2342 FATAL("Incorrect tag size");
2343 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2345 }
2346
2347 if(ctx->sector_ied == NULL) ctx->sector_ied = calloc(1, 2 * total_sectors);
2348
2349 if(ctx->sector_ied == NULL)
2350 {
2351 FATAL("Could not allocate memory for sector IED");
2352
2353 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2355 }
2356
2357 memcpy(ctx->sector_ied + corrected_sector_address * 2, data, 2);
2358 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2359 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2360 return AARUF_STATUS_OK;
2361 case DvdSectorEdcAaru:
2363 {
2364 FATAL("Invalid media type for tag");
2365 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2367 }
2368
2369 if(length != 4)
2370 {
2371 FATAL("Incorrect tag size");
2372 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2374 }
2375
2376 if(ctx->sector_edc == NULL) ctx->sector_edc = calloc(1, 4 * total_sectors);
2377
2378 if(ctx->sector_edc == NULL)
2379 {
2380 FATAL("Could not allocate memory for sector EDC");
2381
2382 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2384 }
2385
2386 memcpy(ctx->sector_edc + corrected_sector_address * 4, data, 4);
2387 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2388 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2389 return AARUF_STATUS_OK;
2392 {
2393 FATAL("Invalid media type for tag");
2394 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2396 }
2397
2398 if(length != 5)
2399 {
2400 FATAL("Incorrect tag size");
2401 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2403 }
2404
2405 if(ctx->sector_decrypted_title_key == NULL) ctx->sector_decrypted_title_key = calloc(1, 5 * total_sectors);
2406
2407 if(ctx->sector_decrypted_title_key == NULL)
2408 {
2409 FATAL("Could not allocate memory for sector decrypted title key");
2410
2411 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2413 }
2414
2415 memcpy(ctx->sector_decrypted_title_key + corrected_sector_address * 5, data, 5);
2416 ctx->dirty_dvd_title_key_decrypted_block = true; // Mark title key block as dirty
2417 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2418 return AARUF_STATUS_OK;
2419 case AppleSonyTagAaru:
2421 {
2422 FATAL("Invalid media type for tag");
2423 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2425 }
2426
2427 if(length != 12)
2428 {
2429 FATAL("Incorrect tag size");
2430 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2432 }
2433
2434 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 12 * total_sectors);
2435
2436 if(ctx->sector_subchannel == NULL)
2437 {
2438 FATAL("Could not allocate memory for Apple Sony tag");
2439
2440 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2442 }
2443
2444 memcpy(ctx->sector_subchannel + corrected_sector_address * 12, data, 12);
2445 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2446 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2447 return AARUF_STATUS_OK;
2450 {
2451 FATAL("Invalid media type for tag");
2452 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2454 }
2455
2456 if(length != 20)
2457 {
2458 FATAL("Incorrect tag size");
2459 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2461 }
2462
2463 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 20 * total_sectors);
2464
2465 if(ctx->sector_subchannel == NULL)
2466 {
2467 FATAL("Could not allocate memory for Apple Profile tag");
2468
2469 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2471 }
2472
2473 memcpy(ctx->sector_subchannel + corrected_sector_address * 20, data, 20);
2474 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2475 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2476 return AARUF_STATUS_OK;
2479 {
2480 FATAL("Invalid media type for tag");
2481 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2483 }
2484
2485 if(length != 24)
2486 {
2487 FATAL("Incorrect tag size");
2488 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2490 }
2491
2492 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 24 * total_sectors);
2493
2494 if(ctx->sector_subchannel == NULL)
2495 {
2496 FATAL("Could not allocate memory for Priam Data Tower tag");
2497
2498 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2500 }
2501
2502 memcpy(ctx->sector_subchannel + corrected_sector_address * 24, data, 24);
2503 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2504 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2505 return AARUF_STATUS_OK;
2506 default:
2507 TRACE("Do not know how to write sector tag %d", tag);
2509 }
2510}
#define MAX_FLAKE_BLOCK
FLAC maximum block size used for encoding audio sectors.
Definition consts.h:94
#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 MIN_FLAKE_BLOCK
FLAC minimum block size.
Definition consts.h:96
#define SAMPLES_PER_SECTOR
Red Book (CD‑DA) PCM samples per 2352‑byte sector: 44,100 Hz / 75 sectors per second = 588 samples.
Definition consts.h:90
#define AARU_CALL
Definition decls.h:45
int32_t aaruf_lzma_encode_buffer(uint8_t *dst_buffer, size_t *dst_size, const uint8_t *src_buffer, size_t src_size, uint8_t *out_props, size_t *out_props_size, int32_t level, uint32_t dict_size, int32_t lc, int32_t lp, int32_t pb, int32_t fb, int32_t num_threads)
Encodes a buffer using LZMA compression.
Definition lzma.c:65
uint64_t aaruf_crc64_data(const uint8_t *data, uint32_t len)
Definition crc64.c:160
size_t aaruf_flac_encode_redbook_buffer(uint8_t *dst_buffer, size_t dst_size, const uint8_t *src_buffer, size_t src_size, uint32_t blocksize, int32_t do_mid_side_stereo, int32_t loose_mid_side_stereo, const char *apodization, uint32_t max_lpc_order, uint32_t qlp_coeff_precision, int32_t do_qlp_coeff_prec_search, int32_t do_exhaustive_model_search, uint32_t min_residual_partition_order, uint32_t max_residual_partition_order, const char *application_id, uint32_t application_id_len)
Encodes a Red Book audio buffer to FLAC format.
Definition flac.c:175
int aaruf_crc64_update(crc64_ctx *ctx, const uint8_t *data, uint32_t len)
Updates the CRC64 context with new data.
Definition crc64.c:55
void aaruf_crc64_free(crc64_ctx *ctx)
Frees a CRC64 context.
Definition crc64.c:155
int aaruf_spamsum_update(spamsum_ctx *ctx, const uint8_t *data, uint32_t len)
Updates the spamsum context with new data.
Definition spamsum.c:59
crc64_ctx * aaruf_crc64_init()
Initializes a CRC64 context.
Definition crc64.c:32
uint32_t aaruf_edc_cd_compute(void *context, uint32_t edc, const uint8_t *src, int size, int pos)
Computes the EDC (Error Detection Code) for a CD sector.
Definition ecc_cd.c:547
void aaruf_md5_update(md5_ctx *ctx, const void *data, unsigned long size)
Definition md5.c:447
#define AARU_EXPORT
Definition decls.h:54
void aaruf_sha256_update(sha256_ctx *ctx, const void *data, unsigned long size)
Definition sha256.c:90
bool aaruf_ecc_cd_is_suffix_correct_mode2(void *context, const uint8_t *sector)
Checks if the suffix (EDC/ECC) of a CD sector is correct (Mode 2).
Definition ecc_cd.c:165
void aaruf_sha1_update(sha1_ctx *ctx, const void *data, unsigned long size)
Definition sha1.c:89
int aaruf_crc64_final(crc64_ctx *ctx, uint64_t *crc)
Computes the final CRC64 value from the context.
Definition crc64.c:141
bool aaruf_ecc_cd_is_suffix_correct(void *context, const uint8_t *sector)
Checks if the suffix (EDC/ECC) of a CD sector is correct (Mode 1).
Definition ecc_cd.c:101
@ DataBlock
Block containing data.
Definition enums.h:142
@ SectorStatusNotDumped
Sector(s) not yet acquired during image dumping.
Definition enums.h:231
@ SectorStatusMode2Form2NoCrc
Suffix matches MODE 2 Form 2 but CRC empty/missing.
Definition enums.h:237
@ SectorStatusMode1Correct
Valid MODE 1 data with regenerable suffix/prefix.
Definition enums.h:234
@ SectorStatusMode2Form2Ok
Suffix matches MODE 2 Form 2 with valid CRC.
Definition enums.h:236
@ SectorStatusErrored
Error during dumping; data may be incomplete or corrupt.
Definition enums.h:233
@ SectorStatusMode2Form1Ok
Suffix verified/regenerable for MODE 2 Form 1.
Definition enums.h:235
@ OpticalDisc
Purely optical discs.
Definition enums.h:219
@ BlockMedia
Media that is physically block-based or abstracted like that.
Definition enums.h:220
@ CdMode1
Compact Disc Mode 1 data track.
Definition enums.h:198
@ Data
Generic data track (not further specified).
Definition enums.h:197
@ CdMode2Form2
Compact Disc Mode 2 Form 2 data track.
Definition enums.h:201
@ Audio
Audio track.
Definition enums.h:196
@ CdMode2Form1
Compact Disc Mode 2 Form 1 data track.
Definition enums.h:200
@ CdMode2Formless
Compact Disc Mode 2 (formless) data track.
Definition enums.h:199
@ UserData
User (main) data.
Definition enums.h:46
@ Lzma
LZMA compression.
Definition enums.h:34
@ None
Not compressed.
Definition enums.h:33
@ Flac
FLAC compression.
Definition enums.h:35
#define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA
Failure writing block payload.
Definition errors.h:63
#define AARUF_STATUS_OK
Sector present and read without uncorrectable errors.
Definition errors.h:75
#define AARUF_READ_ONLY
Operation requires write mode but context is read-only.
Definition errors.h:61
#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_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_INCORRECT_DATA_SIZE
Data size does not match expected size.
Definition errors.h:65
#define AARUF_ERROR_CANNOT_SET_DDT_ENTRY
Failed to encode/store a DDT entry (overflow or IO).
Definition errors.h:64
#define AARUF_ERROR_NOT_AARUFORMAT
Input file/stream failed magic or structural validation.
Definition errors.h:40
#define AARUF_ERROR_INVALID_TAG
Invalid or unsupported media or sector tag format.
Definition errors.h:66
#define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER
Failure writing block header.
Definition errors.h:62
@ AppleProfile
Definition aaru.h:698
@ VideoNowColor
Hasbro VideoNow Color disc.
Definition aaru.h:772
@ AppleSonySS
3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR
Definition aaru.h:247
@ DVDPRWDL
DVD+RW DL.
Definition aaru.h:141
@ DVDRW
DVD-RW.
Definition aaru.h:138
@ DVDRWDL
DVD-RW DL.
Definition aaru.h:145
@ SACD
Super Audio CD (Scarlet Book)
Definition aaru.h:121
@ DVDPRDL
DVD+R DL.
Definition aaru.h:143
@ DVDR
DVD-R.
Definition aaru.h:137
@ PS3DVD
Sony PlayStation 3 game DVD.
Definition aaru.h:206
@ JaguarCD
Atari Jaguar CD.
Definition aaru.h:232
@ PS2DVD
Sony PlayStation 2 game DVD.
Definition aaru.h:205
@ VideoNow
Hasbro VideoNow 85 mm proprietary video disc.
Definition aaru.h:771
@ VideoNowXp
Hasbro VideoNow XP higher capacity disc.
Definition aaru.h:773
@ PriamDataTower
Definition aaru.h:701
@ AppleFileWare
5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy
Definition aaru.h:249
@ DVDPR
DVD+R.
Definition aaru.h:139
@ AppleWidget
Definition aaru.h:699
@ DVDPRW
DVD+RW.
Definition aaru.h:140
@ Nuon
Nuon (DVD based videogame console)
Definition aaru.h:238
@ 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:248
@ DVDROM
DVD-ROM (applies to DVD Video and DVD Audio)
Definition aaru.h:136
@ DVDRAM
DVD-RAM.
Definition aaru.h:144
@ DvdSectorIedAaru
DVD sector ID error detection, 2 bytes.
Definition aaru.h:966
@ CdTrackFlags
Track flags (audio/data, copy permitted, pre-emphasis)
Definition aaru.h:959
@ DvdSectorEdcAaru
DVD sector EDC, 4 bytes.
Definition aaru.h:967
@ DvdCmi
DVD Copyright Management Information (CSS)
Definition aaru.h:960
@ CdSectorSubchannelAaru
96 raw subchannel bytes (P-W)
Definition aaru.h:956
@ DvdSectorNumber
DVD sector number, 3 bytes.
Definition aaru.h:965
@ CdTrackIsrc
Track ISRC (12 ASCII chars, no terminator)
Definition aaru.h:957
@ PriamDataTowerTagAaru
Priam DataTower sector tags, 24 bytes.
Definition aaru.h:969
@ AppleProfileTagAaru
Apple's Profile sector tags, 20 bytes.
Definition aaru.h:968
@ DvdSectorInformation
DVD sector information, 1 bytes.
Definition aaru.h:964
@ DvdTitleKeyDecrypted
Decrypted DVD sector title key, 5 bytes.
Definition aaru.h:963
@ AppleSonyTagAaru
Apple's Sony sector tags, 12 bytes (address prolog + checksum)
Definition aaru.h:948
bool lookup_map(const hash_map_t *map, uint64_t key, uint64_t *out_value)
Looks up a value by key in the hash map.
Definition hash_map.c:196
bool insert_map(hash_map_t *map, uint64_t key, uint64_t value)
Inserts a key-value pair into the hash map.
Definition hash_map.c:153
bool set_ddt_entry_v2(aaruformat_context *ctx, uint64_t sector_address, bool negative, uint64_t offset, uint64_t block_offset, uint8_t sector_status, uint64_t *ddt_entry)
Sets a DDT v2 entry for a given sector address.
Definition ddt_v2.c:988
Structure definitions and conversion/serialization function declarations for Lisa family disk tags.
uint8_t * priam_tag_to_bytes(priam_tag tag)
Serialize a priam_tag into a newly allocated 24-byte big-endian on-disk representation.
Definition lisa_tag.c:409
priam_tag bytes_to_priam_tag(const uint8_t *bytes)
Parse a 24-byte Priam tag record into a priam_tag structure.
Definition lisa_tag.c:112
sony_tag profile_tag_to_sony(profile_tag tag)
Convert a profile_tag to a sony_tag.
Definition lisa_tag.c:257
uint8_t * sony_tag_to_bytes(sony_tag tag)
Serialize a sony_tag into a newly allocated 12-byte big-endian on-disk representation.
Definition lisa_tag.c:466
profile_tag priam_tag_to_profile(priam_tag tag)
Convert a priam_tag to a profile_tag.
Definition lisa_tag.c:325
uint8_t * profile_tag_to_bytes(profile_tag tag)
Serialize a profile_tag into a newly allocated 20-byte big-endian on-disk representation.
Definition lisa_tag.c:357
profile_tag sony_tag_to_profile(sony_tag tag)
Convert a sony_tag to a profile_tag representation.
Definition lisa_tag.c:173
sony_tag bytes_to_sony_tag(const uint8_t *bytes)
Parse a 12-byte Sony tag record into a sony_tag structure.
Definition lisa_tag.c:82
profile_tag bytes_to_profile_tag(const uint8_t *bytes)
Parse a 20-byte Profile tag record into a profile_tag structure.
Definition lisa_tag.c:142
priam_tag sony_tag_to_priam(sony_tag tag)
Convert a sony_tag to a priam_tag representation.
Definition lisa_tag.c:201
priam_tag profile_tag_to_priam(profile_tag tag)
Convert a profile_tag to a priam_tag.
Definition lisa_tag.c:228
sony_tag priam_tag_to_sony(priam_tag tag)
Convert a priam_tag to a sony_tag.
Definition lisa_tag.c:291
#define FATAL(fmt,...)
Definition log.h:40
#define TRACE(fmt,...)
Definition log.h:25
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
uint64_t cmpCrc64
CRC64-ECMA of the compressed payload (cmpLength bytes).
Definition data.h:78
uint64_t crc64
CRC64-ECMA of the uncompressed payload (length bytes).
Definition data.h:79
uint16_t type
Logical data classification (value from DataType).
Definition data.h:73
uint16_t compression
Compression algorithm used (value from CompressionType).
Definition data.h:74
uint16_t overflow
Trailing dumped sectors beyond user area (overflow range), still mapped with entries.
Definition ddt.h:151
uint16_t negative
Leading negative LBA count; added to external L to build internal index.
Definition ddt.h:149
uint8_t blockAlignmentShift
2^blockAlignmentShift = block alignment boundary in bytes.
Definition ddt.h:154
uint8_t dataShift
2^dataShift = sectors represented per increment in blockIndex field.
Definition ddt.h:155
uint32_t MediaType
Media type identifier (see MediaType enum; 0=Unknown)
Definition aaru.h:933
uint8_t MetadataMediaType
Media type for sidecar generation (internal archival use)
Definition aaru.h:934
uint64_t Sectors
Total count of addressable logical sectors/blocks.
Definition aaru.h:926
Single index entry describing a block's type, (optional) data classification, and file offset.
Definition index.h:109
uint32_t blockType
Block identifier of the referenced block (value from BlockType).
Definition index.h:110
uint64_t offset
Absolute byte offset in the image where the referenced block header begins.
Definition index.h:112
uint16_t dataType
Data classification (value from DataType) or unused for untyped blocks.
Definition index.h:111
Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags).
Definition optical.h:72
uint8_t session
Session number (1-based). 1 for single-session discs.
Definition optical.h:78
uint8_t flags
Control / attribute bitfield (see file documentation for suggested bit mapping).
Definition optical.h:80
int64_t end
Inclusive ending LBA of the track.
Definition optical.h:76
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
Master context representing an open or in‑creation Aaru image.
Definition context.h:172
DdtHeader2 user_data_ddt_header
Active user data DDT v2 header (primary table meta).
Definition context.h:189
bool dirty_checksum_block
True if checksum block should be written during close.
Definition context.h:311
bool deduplicate
Storage deduplication active (duplicates coalesce).
Definition context.h:299
size_t sector_suffix_length
Length of sector_suffix.
Definition context.h:285
bool compression_enabled
True if block compression enabled (writing path).
Definition context.h:300
uint64_t last_written_block
Last written block number (write path).
Definition context.h:283
uint8_t * sector_cpr_mai
DVD sector CPR_MAI (6 bytes) if present.
Definition context.h:207
bool dirty_media_tags
True if media tags should be written during close.
Definition context.h:321
hash_map_t * sector_hash_map
Deduplication hash map (fingerprint->entry mapping).
Definition context.h:253
sha256_ctx sha256_context
Opaque SHA-256 context for streaming updates.
Definition context.h:272
bool calculating_sha256
True if whole-image SHA-256 being calculated on-the-fly.
Definition context.h:275
uint8_t * sector_ied
DVD sector IED (2 bytes) if present.
Definition context.h:206
md5_ctx md5_context
Opaque MD5 context for streaming updates.
Definition context.h:270
bool dirty_sector_suffix_block
True if sector suffix block should be written during close.
Definition context.h:316
uint8_t * sector_prefix
Raw per-sector prefix (e.g., sync+header) uncorrected.
Definition context.h:199
bool dirty_dvd_title_key_decrypted_block
True if decrypted title key block should be written during close.
Definition context.h:320
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
Definition context.h:186
bool dirty_mode2_subheaders_block
True if MODE2 subheader block should be written during close.
Definition context.h:313
uint8_t * sector_edc
DVD sector EDC (4 bytes) if present.
Definition context.h:208
bool calculating_sha1
True if whole-image SHA-1 being calculated on-the-fly.
Definition context.h:274
bool dirty_tracks_block
True if tracks block should be written during close.
Definition context.h:312
CdEccContext * ecc_cd_context
CD ECC/EDC helper tables (allocated on demand).
Definition context.h:248
bool rewinded
True if stream has been rewound after open (write path).
Definition context.h:293
bool dirty_sector_prefix_block
True if sector prefix block should be written during close.
Definition context.h:314
bool dirty_index_block
True if index block should be written during close.
Definition context.h:330
uint8_t * sector_suffix
Raw per-sector suffix (EDC/ECC) uncorrected.
Definition context.h:201
int current_block_offset
Logical offset inside block (units: bytes or sectors depending on path).
Definition context.h:288
bool is_writing
True if context opened/created for writing.
Definition context.h:292
spamsum_ctx * spamsum_context
Opaque SpamSum context for streaming updates.
Definition context.h:267
size_t sector_prefix_offset
Current position in sector_prefix.
Definition context.h:286
BlockHeader current_block_header
Header for block currently being assembled (write path).
Definition context.h:281
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:174
uint8_t * writing_buffer
Accumulation buffer for current block data.
Definition context.h:280
uint64_t * sector_prefix_ddt2
CD sector prefix DDT V2.
Definition context.h:185
bool calculating_spamsum
True if whole-image SpamSum being calculated on-the-fly.
Definition context.h:276
size_t sector_prefix_length
Length of sector_prefix.
Definition context.h:284
mediaTagEntry * mediaTags
Hash table of extra media tags (uthash root).
Definition context.h:264
blake3_hasher * blake3_context
Opaque BLAKE3 context for streaming updates.
Definition context.h:268
bool calculating_blake3
True if whole-image BLAKE3 being calculated on-the-fly.
Definition context.h:277
uint64_t next_block_position
Absolute file offset where next block will be written.
Definition context.h:282
bool calculating_md5
True if whole-image MD5 being calculated on-the-fly.
Definition context.h:273
bool dirty_sector_suffix_ddt
True if sector suffix DDT should be written during close.
Definition context.h:317
size_t sector_suffix_offset
Current position in sector_suffix.
Definition context.h:287
uint8_t * sector_decrypted_title_key
DVD decrypted title key (5 bytes) if present.
Definition context.h:209
int writing_buffer_position
Current size / position within writingBuffer.
Definition context.h:289
bool block_zero_written
True if block zero has been written (writing path).
Definition context.h:295
crc64_ctx * crc64_context
Opaque CRC64 context for streaming updates.
Definition context.h:249
uint8_t * sector_subchannel
Raw 96-byte subchannel (if captured).
Definition context.h:203
bool dirty_sector_subchannel_block
True if subchannel block should be written during close.
Definition context.h:318
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:176
bool dirty_dvd_long_sector_blocks
True if DVD long sector blocks should be written during close.
Definition context.h:319
bool dirty_sector_prefix_ddt
True if sector prefix DDT should be written during close.
Definition context.h:315
UT_array * index_entries
Flattened index entries (UT_array of IndexEntry).
Definition context.h:252
uint8_t * mode2_subheaders
MODE2 Form1/Form2 8-byte subheaders (concatenated).
Definition context.h:204
ImageInfo image_info
Exposed high-level image info summary.
Definition context.h:260
uint8_t * sector_id
DVD sector ID (4 bytes) if present.
Definition context.h:205
sha1_ctx sha1_context
Opaque SHA-1 context for streaming updates.
Definition context.h:271
uint32_t lzma_dict_size
LZMA dictionary size (writing path).
Definition context.h:298
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
Definition context.h:242
uint8_t current_track_type
Current track type (when writing optical images with tracks, needed for block compression type).
Definition context.h:290
bool writing_long
True if writing long sectors.
Definition context.h:294
TracksHeader tracks_header
Tracks header (optical) if present.
Definition context.h:244
Hash table entry for an arbitrary media tag (e.g., proprietary drive/medium descriptor).
Definition context.h:119
uint8_t * data
Tag data blob (opaque to library core); length bytes long.
Definition context.h:120
int32_t type
Numeric type identifier.
Definition context.h:121
uint32_t length
Length in bytes of data.
Definition context.h:122
int32_t aaruf_close_current_block(aaruformat_context *ctx)
Finalizes and writes the current data block to the AaruFormat image file.
Definition write.c:1427
int32_t aaruf_write_sector_tag(void *context, const uint64_t sector_address, const bool negative, const uint8_t *data, const size_t length, const int32_t tag)
Writes per-sector tag data (auxiliary metadata) for a specific sector.
Definition write.c:2095
int32_t aaruf_write_media_tag(void *context, const uint8_t *data, const int32_t type, const uint32_t length)
Writes a media tag to the AaruFormat image, storing medium-specific metadata and descriptors.
Definition write.c:1825
int32_t aaruf_write_sector(void *context, uint64_t sector_address, bool negative, const uint8_t *data, uint8_t sector_status, uint32_t length)
Writes a sector to the AaruFormat image.
Definition write.c:98
int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool negative, const uint8_t *data, uint8_t sector_status, uint32_t length)
Writes a full ("long") raw sector from optical or block media, parsing structure and validating conte...
Definition write.c:544