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-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#include <errno.h>
19#include <limits.h>
20#include <stdbool.h>
21#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include "aaruformat.h"
27#include "internal.h"
28#include "log.h"
29#include "structs/lisa_tag.h"
30#include "xxhash.h"
31
99AARU_EXPORT int32_t AARU_CALL aaruf_write_sector(void *context, uint64_t sector_address, bool negative,
100 const uint8_t *data, uint8_t sector_status, uint32_t length)
101{
102 TRACE("Entering aaruf_write_sector(%p, %" PRIu64 ", %d, %p, %u, %u)", context, sector_address, negative, data,
103 sector_status, length);
104
105 // Check context is correct AaruFormat context
106 if(context == NULL)
107 {
108 FATAL("Invalid context");
109
110 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
112 }
113
114 aaruformat_context *ctx = context;
115
116 // Not a libaaruformat context
117 if(ctx->magic != AARU_MAGIC)
118 {
119 FATAL("Invalid context");
120
121 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
123 }
124
125 // Check we are writing
126 if(!ctx->is_writing)
127 {
128 FATAL("Trying to write a read-only image");
129
130 TRACE("Exiting aaruf_write_sector() = AARUF_READ_ONLY");
131 return AARUF_READ_ONLY;
132 }
133
134 if(negative && sector_address > ctx->user_data_ddt_header.negative)
135 {
136 FATAL("Sector address out of bounds");
137
138 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
140 }
141
142 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
143 {
144 FATAL("Sector address out of bounds");
145
146 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
148 }
149
150 if(length > USHRT_MAX)
151 {
152 FATAL("Sector length too large");
153
154 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INVALID_SECTOR_LENGTH");
156 }
157
158 if(length > ctx->header.biggestSectorSize) ctx->header.biggestSectorSize = (uint16_t)length;
159
160 if(!ctx->rewinded)
161 {
162 if(sector_address <= ctx->last_written_block)
163 {
164 if(sector_address == 0 && !ctx->block_zero_written)
165 ctx->block_zero_written = true;
166 else
167 {
168 TRACE("Rewinded");
169 ctx->rewinded = true;
170
171 // Disable MD5 calculation
172 if(ctx->calculating_md5) ctx->calculating_md5 = false;
173 // Disable SHA1 calculation
174 if(ctx->calculating_sha1) ctx->calculating_sha1 = false;
175 // Disable SHA256 calculation
176 if(ctx->calculating_sha256) ctx->calculating_sha256 = false;
177 // Disable SpamSum calculation
178 if(ctx->calculating_spamsum) ctx->calculating_spamsum = false;
179 // Disable BLAKE3 calculation
180 if(ctx->calculating_blake3) ctx->calculating_blake3 = false;
181 }
182 }
183 else
184 ctx->last_written_block = sector_address;
185 }
186
187 // Calculate MD5 on-the-fly if requested and sector is within user sectors (not negative or overflow)
188 if(ctx->calculating_md5 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
189 aaruf_md5_update(&ctx->md5_context, data, length);
190 // Calculate SHA1 on-the-fly if requested and sector is within user sectors (not negative or overflow)
191 if(ctx->calculating_sha1 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
192 aaruf_sha1_update(&ctx->sha1_context, data, length);
193 // Calculate SHA256 on-the-fly if requested and sector is within user sectors (not negative or overflow)
194 if(ctx->calculating_sha256 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
195 aaruf_sha256_update(&ctx->sha256_context, data, length);
196 // Calculate SpamSum on-the-fly if requested and sector is within user sectors (not negative or overflow)
197 if(ctx->calculating_spamsum && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
198 aaruf_spamsum_update(ctx->spamsum_context, data, length);
199 // Calculate BLAKE3 on-the-fly if requested and sector is within user sectors (not negative or overflow)
200 if(ctx->calculating_blake3 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
201 blake3_hasher_update(ctx->blake3_context, data, length);
202
203 // Mark checksum block as dirty if any checksums are being calculated
205 ctx->calculating_blake3) &&
206 !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
207 ctx->dirty_checksum_block = true;
208
209 // Close current block first
210 if(ctx->writing_buffer != NULL &&
211 // When sector size changes or block reaches maximum size
212 (ctx->current_block_header.sectorSize != length ||
214 {
215 TRACE("Closing current block before writing new data");
216 int error = aaruf_close_current_block(ctx);
217
218 if(error != AARUF_STATUS_OK)
219 {
220 FATAL("Error closing current block: %d", error);
221
222 TRACE("Exiting aaruf_write_sector() = %d", error);
223 return error;
224 }
225 }
226
227 uint64_t ddt_entry = 0;
228 bool ddt_ok;
229
230 if(ctx->deduplicate)
231 {
232 // Calculate 64-bit XXH3 hash of the sector
233 TRACE("Hashing sector data for deduplication");
234 uint64_t hash = XXH3_64bits(data, length);
235
236 // Check if the hash is already in the map
237 bool existing = lookup_map(ctx->sector_hash_map, hash, &ddt_entry);
238 TRACE("Block does %s exist in deduplication map", existing ? "already" : "not yet");
239
240 ddt_ok = set_ddt_entry_v2(ctx, sector_address, negative, ctx->current_block_offset, ctx->next_block_position,
241 sector_status, &ddt_entry);
242 if(!ddt_ok)
243 {
244 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_CANNOT_SET_DDT_ENTRY");
246 }
247
248 if(existing)
249 {
250 TRACE("Sector exists, so not writing to image");
251 TRACE("Exiting aaruf_write_sector() = AARUF_STATUS_OK");
252 return AARUF_STATUS_OK;
253 }
254
255 TRACE("Inserting sector hash into deduplication map, proceeding to write into image as normal");
256 insert_map(ctx->sector_hash_map, hash, ddt_entry);
257 }
258 else
259 ddt_ok = set_ddt_entry_v2(ctx, sector_address, negative, ctx->current_block_offset, ctx->next_block_position,
260 sector_status, &ddt_entry);
261
262 if(!ddt_ok)
263 {
264 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_CANNOT_SET_DDT_ENTRY");
266 }
267
268 // No block set
269 if(ctx->writing_buffer_position == 0)
270 {
271 TRACE("Creating new writing block");
274 ctx->current_block_header.sectorSize = length;
275
276 // We need to save the track type for later compression
277 if(ctx->image_info.MetadataMediaType == OpticalDisc && ctx->track_entries != NULL)
278 {
279 const TrackEntry *track = NULL;
280 for(int i = 0; i < ctx->tracks_header.entries; i++)
281 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
282 {
283 track = &ctx->track_entries[i];
284 break;
285 }
286
287 if(track != NULL)
288 {
289 ctx->current_track_type = track->type;
290
291 if(track->sequence == 0 && track->start == 0 && track->end == 0) ctx->current_track_type = Data;
292 }
293 else
295
296 if(ctx->current_track_type == Audio &&
297 // JaguarCD stores data in audio tracks. FLAC is too inefficient, we need to use LZMA as data.
298 (ctx->image_info.MediaType == JaguarCD && track->session > 1 ||
299 // VideoNow stores video in audio tracks, and LZMA works better too.
303
304 if(ctx->compression_enabled)
305 {
306 if(ctx->current_track_type == Audio)
308 else
310 }
311 else
313 }
314 else
315 {
317 if(ctx->compression_enabled)
319 else
321 }
322
323 uint32_t max_buffer_size =
325 TRACE("Setting max buffer size to %u bytes", max_buffer_size);
326
327 TRACE("Allocating memory for writing buffer");
328 ctx->writing_buffer = (uint8_t *)calloc(1, max_buffer_size);
329 if(ctx->writing_buffer == NULL)
330 {
331 FATAL("Could not allocate memory");
332
333 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
335 }
336 }
337
338 TRACE("Copying data to writing buffer at position %zu", ctx->writing_buffer_position);
339 memcpy(ctx->writing_buffer + ctx->writing_buffer_position, data, length);
340 TRACE("Advancing writing buffer position to %zu", ctx->writing_buffer_position + length);
341 ctx->writing_buffer_position += length;
342 TRACE("Advancing current block offset to %zu", ctx->current_block_offset + 1);
344
345 TRACE("Exiting aaruf_write_sector() = AARUF_STATUS_OK");
346 return AARUF_STATUS_OK;
347}
348
555AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_long(void *context, uint64_t sector_address, bool negative,
556 const uint8_t *data, uint8_t sector_status, uint32_t length)
557{
558 TRACE("Entering aaruf_write_sector_long(%p, %" PRIu64 ", %d, %p, %u, %u)", context, sector_address, negative, data,
559 sector_status, length);
560
561 // Check context is correct AaruFormat context
562 if(context == NULL)
563 {
564 FATAL("Invalid context");
565
566 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
568 }
569
570 aaruformat_context *ctx = context;
571
572 // Not a libaaruformat context
573 if(ctx->magic != AARU_MAGIC)
574 {
575 FATAL("Invalid context");
576
577 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
579 }
580
581 // Check we are writing
582 if(!ctx->is_writing)
583 {
584 FATAL("Trying to write a read-only image");
585
586 TRACE("Exiting aaruf_write_sector() = AARUF_READ_ONLY");
587 return AARUF_READ_ONLY;
588 }
589
590 if(negative && sector_address > ctx->user_data_ddt_header.negative)
591 {
592 FATAL("Sector address out of bounds");
593
594 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
596 }
597
598 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
599 {
600 FATAL("Sector address out of bounds");
601
602 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
604 }
605
606 switch(ctx->image_info.MetadataMediaType)
607 {
608 case OpticalDisc:
609 {
610 TrackEntry track = {0};
611
612 for(int i = 0; i < ctx->tracks_header.entries; i++)
613 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
614 {
615 track = ctx->track_entries[i];
616 break;
617 }
618
619 if(track.sequence == 0 && track.start == 0 && track.end == 0) track.type = Data;
620
621 uint64_t corrected_sector_address = sector_address;
622
623 // Calculate positive or negative sector
624 if(negative)
625 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
626 else
627 corrected_sector_address += ctx->user_data_ddt_header.negative;
628
629 uint64_t total_sectors =
631
632 // DVD long sector
633 if(length == 2064 && (ctx->image_info.MediaType == DVDROM || ctx->image_info.MediaType == PS2DVD ||
634 ctx->image_info.MediaType == SACD || ctx->image_info.MediaType == PS3DVD ||
635 ctx->image_info.MediaType == DVDR || ctx->image_info.MediaType == DVDRW ||
640 ctx->image_info.MediaType == Nuon))
641 {
642 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
643 if(ctx->sector_ied == NULL) ctx->sector_ied = calloc(1, 2 * total_sectors);
644 if(ctx->sector_cpr_mai == NULL) ctx->sector_cpr_mai = calloc(1, 6 * total_sectors);
645 if(ctx->sector_edc == NULL) ctx->sector_edc = calloc(1, 4 * total_sectors);
646
647 memcpy(ctx->sector_id + corrected_sector_address * 4, data, 4);
648 memcpy(ctx->sector_ied + corrected_sector_address * 2, data + 4, 2);
649 memcpy(ctx->sector_cpr_mai + corrected_sector_address * 6, data + 6, 6);
650 memcpy(ctx->sector_edc + corrected_sector_address * 4, data + 2060, 4);
651
652 return aaruf_write_sector(context, sector_address, negative, data + 12, sector_status, 2048);
653 }
654
655 if(length != 2352)
656 {
657 FATAL("Incorrect sector size");
658 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
660 }
661
662 ctx->writing_long = true;
663
664 if(!ctx->rewinded)
665 {
666 if(sector_address <= ctx->last_written_block)
667 {
668 if(sector_address == 0 && !ctx->block_zero_written)
669 ctx->block_zero_written = true;
670 else
671 {
672 TRACE("Rewinded");
673 ctx->rewinded = true;
674
675 // Disable MD5 calculation
676 if(ctx->calculating_md5) ctx->calculating_md5 = false;
677 // Disable SHA1 calculation
678 if(ctx->calculating_sha1) ctx->calculating_sha1 = false;
679 // Disable SHA256 calculation
680 if(ctx->calculating_sha256) ctx->calculating_sha256 = false;
681 // Disable SpamSum calculation
682 if(ctx->calculating_spamsum) ctx->calculating_spamsum = false;
683 // Disable BLAKE3 calculation
684 if(ctx->calculating_blake3) ctx->calculating_blake3 = false;
685 }
686 }
687 else
688 ctx->last_written_block = sector_address;
689 }
690
691 // Calculate MD5 on-the-fly if requested and sector is within user sectors (not negative or overflow)
692 if(ctx->calculating_md5 && !negative && sector_address <= ctx->image_info.Sectors)
693 aaruf_md5_update(&ctx->md5_context, data, length);
694 // Calculate SHA1 on-the-fly if requested and sector is within user sectors (not negative or overflow)
695 if(ctx->calculating_sha1 && !negative && sector_address <= ctx->image_info.Sectors)
696 aaruf_sha1_update(&ctx->sha1_context, data, length);
697 // Calculate SHA256 on-the-fly if requested and sector is within user sectors (not negative or overflow)
698 if(ctx->calculating_sha256 && !negative && sector_address <= ctx->image_info.Sectors)
699 aaruf_sha256_update(&ctx->sha256_context, data, length);
700 // Calculate SpamSum on-the-fly if requested and sector is within user sectors (not negative or overflow)
701 if(ctx->calculating_spamsum && !negative && sector_address <= ctx->image_info.Sectors)
702 aaruf_spamsum_update(ctx->spamsum_context, data, length);
703 // Calculate BLAKE3 on-the-fly if requested and sector is within user sectors (not negative or overflow)
704 if(ctx->calculating_blake3 && !negative && sector_address <= ctx->image_info.Sectors)
705 blake3_hasher_update(ctx->blake3_context, data, length);
706
707 bool prefix_correct;
708
709 // Split raw cd sector data in prefix (sync, header), user data and suffix (edc, ecc p, ecc q)
710 switch(track.type)
711 {
712 case Audio:
713 case Data:
714 return aaruf_write_sector(context, sector_address, negative, data, sector_status, length);
715 case CdMode1:
716
717 // If we do not have a DDT V2 for sector prefix, create one
718 if(ctx->sector_prefix_ddt2 == NULL)
719 {
720 ctx->sector_prefix_ddt2 =
721 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
723
724 if(ctx->sector_prefix_ddt2 == NULL)
725 {
726 FATAL("Could not allocate memory for CD sector prefix DDT");
727
728 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
730 }
731 }
732
733 // If we do not have a DDT V2 for sector suffix, create one
734 if(ctx->sector_suffix_ddt2 == NULL)
735 {
736 ctx->sector_suffix_ddt2 =
737 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
739
740 if(ctx->sector_suffix_ddt2 == NULL)
741 {
742 FATAL("Could not allocate memory for CD sector prefix DDT");
743
744 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
746 }
747 }
748
749 if(ctx->sector_prefix == NULL)
750 {
753 ctx->sector_prefix = malloc(ctx->sector_prefix_length);
754
755 if(ctx->sector_prefix == NULL)
756 {
757 FATAL("Could not allocate memory for CD sector prefix buffer");
758
759 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
761 }
762 }
763
764 if(ctx->sector_suffix == NULL)
765 {
769 ctx->sector_suffix = malloc(ctx->sector_suffix_length);
770
771 if(ctx->sector_suffix == NULL)
772 {
773 FATAL("Could not allocate memory for CD sector suffix buffer");
774
775 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
777 }
778 }
779
780 bool empty = true;
781
782 for(int i = 0; i < length; i++)
783 if(data[i] != 0)
784 {
785 empty = false;
786 break;
787 }
788
789 if(empty)
790 {
791 ctx->sector_prefix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
792 ctx->sector_suffix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
793 ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty
794 ctx->dirty_sector_suffix_ddt = true; // Mark suffix DDT as dirty
795 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
796 2048);
797 }
798
799 prefix_correct = true;
800
801 if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
802 data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
803 data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
804 data[0x0F] != 0x01)
805 prefix_correct = false;
806
807 if(prefix_correct)
808 {
809 const int minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
810 const int second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
811 const int frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
812 const int stored_lba = minute * 60 * 75 + second * 75 + frame - 150;
813 prefix_correct = stored_lba == sector_address;
814 }
815
816 if(prefix_correct)
817 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode1Correct << 60;
818 else
819 {
820 // Copy CD prefix from data buffer to prefix buffer
821 memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
822 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_prefix_offset / 16);
823 ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
824 ctx->sector_prefix_offset += 16;
825 ctx->dirty_sector_prefix_block = true; // Mark prefix block as dirty
826
827 // Grow prefix buffer if needed
829 {
830 ctx->sector_prefix_length *= 2;
831 ctx->sector_prefix = realloc(ctx->sector_prefix, ctx->sector_prefix_length);
832
833 if(ctx->sector_prefix == NULL)
834 {
835 FATAL("Could not allocate memory for CD sector prefix buffer");
836
837 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
839 }
840 }
841 }
842 ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty
843
844 const bool suffix_correct = aaruf_ecc_cd_is_suffix_correct(ctx->ecc_cd_context, data);
845
846 if(suffix_correct)
847 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode1Correct << 60;
848 else
849 {
850 // Copy CD suffix from data buffer to suffix buffer
851 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2064, 288);
852 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288);
853 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
854 ctx->sector_suffix_offset += 288;
855 ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty
856
857 // Grow suffix buffer if needed
859 {
860 ctx->sector_suffix_length *= 2;
861 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
862
863 if(ctx->sector_suffix == NULL)
864 {
865 FATAL("Could not allocate memory for CD sector suffix buffer");
866
867 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
869 }
870 }
871 }
872 ctx->dirty_sector_suffix_ddt = true; // Mark suffix DDT as dirty
873
874 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusMode1Correct,
875 2048);
876 case CdMode2Form1:
877 case CdMode2Form2:
878 case CdMode2Formless:
879 // If we do not have a DDT V2 for sector prefix, create one
880 if(ctx->sector_prefix_ddt2 == NULL)
881 {
882 ctx->sector_prefix_ddt2 =
883 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
885
886 if(ctx->sector_prefix_ddt2 == NULL)
887 {
888 FATAL("Could not allocate memory for CD sector prefix DDT");
889
890 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
892 }
893 }
894
895 // If we do not have a DDT V2 for sector suffix, create one
896 if(ctx->sector_suffix_ddt2 == NULL)
897 {
898 ctx->sector_suffix_ddt2 =
899 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
901
902 if(ctx->sector_suffix_ddt2 == NULL)
903 {
904 FATAL("Could not allocate memory for CD sector prefix DDT");
905
906 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
908 }
909 }
910
911 if(ctx->sector_prefix == NULL)
912 {
915 ctx->sector_prefix = malloc(ctx->sector_prefix_length);
916
917 if(ctx->sector_prefix == NULL)
918 {
919 FATAL("Could not allocate memory for CD sector prefix buffer");
920
921 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
923 }
924 }
925
926 if(ctx->sector_suffix == NULL)
927 {
931 ctx->sector_suffix = malloc(ctx->sector_suffix_length);
932
933 if(ctx->sector_suffix == NULL)
934 {
935 FATAL("Could not allocate memory for CD sector suffix buffer");
936
937 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
939 }
940 }
941
942 empty = true;
943
944 for(int i = 0; i < length; i++)
945 if(data[i] != 0)
946 {
947 empty = false;
948 break;
949 }
950
951 if(empty)
952 {
953 ctx->sector_prefix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
954 ctx->sector_suffix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
955 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
956 2328);
957 }
958
959 const bool form2 = (data[18] & 0x20) == 0x20 || (data[22] & 0x20) == 0x20;
960
961 prefix_correct = true;
962
963 if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
964 data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
965 data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
966 data[0x0F] != 0x02)
967 prefix_correct = false;
968
969 if(prefix_correct)
970 {
971 const int minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
972 const int second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
973 const int frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
974 const int stored_lba = minute * 60 * 75 + second * 75 + frame - 150;
975 prefix_correct = stored_lba == sector_address;
976 }
977
978 if(prefix_correct)
979 ctx->sector_prefix_ddt2[corrected_sector_address] =
980 (uint64_t)(form2 ? SectorStatusMode2Form2Ok : SectorStatusMode2Form1Ok) << 60;
981 else
982 {
983 // Copy CD prefix from data buffer to prefix buffer
984 memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
985 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint32_t)(ctx->sector_prefix_offset / 16);
986 ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
987 ctx->sector_prefix_offset += 16;
988 ctx->dirty_sector_prefix_block = true; // Mark prefix block as dirty
989
990 // Grow prefix buffer if needed
992 {
993 ctx->sector_prefix_length *= 2;
994 ctx->sector_prefix = realloc(ctx->sector_prefix, ctx->sector_prefix_length);
995
996 if(ctx->sector_prefix == NULL)
997 {
998 FATAL("Could not allocate memory for CD sector prefix buffer");
999
1000 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1002 }
1003 }
1004 }
1005 ctx->dirty_sector_prefix_ddt = true; // Mark prefix DDT as dirty
1006
1007 if(ctx->mode2_subheaders == NULL)
1008 {
1009 ctx->mode2_subheaders =
1010 calloc(1, 8 * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
1012
1013 if(ctx->mode2_subheaders == NULL)
1014 {
1015 FATAL("Could not allocate memory for CD mode 2 subheader buffer");
1016
1017 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1019 }
1020 }
1021
1022 if(form2)
1023 {
1024 const uint32_t computed_edc = aaruf_edc_cd_compute(ctx->ecc_cd_context, 0, data, 0x91C, 0x10);
1025 uint32_t edc = 0;
1026 memcpy(&edc, data + 0x92C, sizeof(edc));
1027 const bool correct_edc = computed_edc == edc;
1028
1029 if(correct_edc)
1030 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form2Ok
1031 << 60;
1032 else if(edc == 0)
1033 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form2NoCrc
1034 << 60;
1035 else
1036 {
1037 // Copy CD suffix from data buffer to suffix buffer
1038 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2348, 4);
1039 ctx->sector_suffix_ddt2[corrected_sector_address] =
1040 (uint64_t)(ctx->sector_suffix_offset / 288);
1041 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
1042 ctx->sector_suffix_offset += 288;
1043 ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty
1044
1045 // Grow suffix buffer if needed
1047 {
1048 ctx->sector_suffix_length *= 2;
1049 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
1050
1051 if(ctx->sector_suffix == NULL)
1052 {
1053 FATAL("Could not allocate memory for CD sector suffix buffer");
1054
1055 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1057 }
1058 }
1059 }
1060
1061 // Copy subheader from data buffer to subheader buffer
1062 memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8);
1063 ctx->dirty_sector_prefix_ddt = true;
1064 ctx->dirty_sector_suffix_ddt = true;
1065 ctx->dirty_mode2_subheaders_block = true;
1066 return aaruf_write_sector(context, sector_address, negative, data + 24,
1068 : correct_edc ? SectorStatusMode2Form2Ok
1070 2324);
1071 }
1072
1073 const bool correct_ecc = aaruf_ecc_cd_is_suffix_correct_mode2(ctx->ecc_cd_context, data);
1074 const uint32_t computed_edc = aaruf_edc_cd_compute(ctx->ecc_cd_context, 0, data, 0x808, 0x10);
1075 uint32_t edc = 0;
1076 memcpy(&edc, data + 0x818, sizeof(edc));
1077 const bool correct_edc = computed_edc == edc;
1078
1079 if(correct_ecc && correct_edc)
1080 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form1Ok << 60;
1081 else
1082 {
1083 // Copy CD suffix from data buffer to suffix buffer
1084 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2072, 280);
1085 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288);
1086 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
1087 ctx->sector_suffix_offset += 288;
1088 ctx->dirty_sector_suffix_block = true; // Mark suffix block as dirty
1089
1090 // Grow suffix buffer if needed
1092 {
1093 ctx->sector_suffix_length *= 2;
1094 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
1095
1096 if(ctx->sector_suffix == NULL)
1097 {
1098 FATAL("Could not allocate memory for CD sector suffix buffer");
1099
1100 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1102 }
1103 }
1104 }
1105
1106 // Copy subheader from data buffer to subheader buffer
1107 memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8);
1108 ctx->dirty_sector_prefix_ddt = true;
1109 ctx->dirty_sector_suffix_ddt = true;
1110 ctx->dirty_mode2_subheaders_block = true;
1111 return aaruf_write_sector(
1112 context, sector_address, negative, data + 24,
1113 correct_edc && correct_ecc ? SectorStatusMode2Form1Ok : SectorStatusErrored, 2048);
1114 }
1115
1116 break;
1117 }
1118 case BlockMedia:
1119 switch(ctx->image_info.MediaType)
1120 {
1121 case AppleFileWare:
1122 case AppleProfile:
1123 case AppleSonyDS:
1124 case AppleSonySS:
1125 case AppleWidget:
1126 case PriamDataTower:
1127 {
1128 uint8_t *newTag;
1129 int newTagSize = 0;
1130
1131 switch(length - 512)
1132 {
1133 // Sony tag
1134 case 12:
1135 {
1136 const sony_tag decoded_sony_tag = bytes_to_sony_tag(data + 512);
1137
1139 {
1140 const profile_tag decoded_profile_tag = sony_tag_to_profile(decoded_sony_tag);
1141 newTag = profile_tag_to_bytes(decoded_profile_tag);
1142 newTagSize = 20;
1143 }
1144 else if(ctx->image_info.MediaType == PriamDataTower)
1145 {
1146 const priam_tag decoded_priam_tag = sony_tag_to_priam(decoded_sony_tag);
1147 newTag = priam_tag_to_bytes(decoded_priam_tag);
1148 newTagSize = 24;
1149 }
1150 else if(ctx->image_info.MediaType == AppleSonyDS ||
1152 {
1153 newTag = malloc(12);
1154 memcpy(newTag, data + 512, 12);
1155 newTagSize = 12;
1156 }
1157 break;
1158 }
1159 // Profile tag
1160 case 20:
1161 {
1162 const profile_tag decoded_profile_tag = bytes_to_profile_tag(data + 512);
1163
1165 {
1166 newTag = malloc(20);
1167 memcpy(newTag, data + 512, 20);
1168 newTagSize = 20;
1169 }
1170 else if(ctx->image_info.MediaType == PriamDataTower)
1171 {
1172 const priam_tag decoded_priam_tag = profile_tag_to_priam(decoded_profile_tag);
1173 newTag = priam_tag_to_bytes(decoded_priam_tag);
1174 newTagSize = 24;
1175 }
1176 else if(ctx->image_info.MediaType == AppleSonyDS ||
1178 {
1179 const sony_tag decoded_sony_tag = profile_tag_to_sony(decoded_profile_tag);
1180 newTag = sony_tag_to_bytes(decoded_sony_tag);
1181 newTagSize = 12;
1182 }
1183 break;
1184 }
1185 // Priam tag
1186 case 24:
1187 {
1188 const priam_tag decoded_priam_tag = bytes_to_priam_tag(data + 512);
1190 {
1191 const profile_tag decoded_profile_tag = priam_tag_to_profile(decoded_priam_tag);
1192 newTag = profile_tag_to_bytes(decoded_profile_tag);
1193 newTagSize = 20;
1194 }
1195 else if(ctx->image_info.MediaType == PriamDataTower)
1196 {
1197 newTag = malloc(24);
1198 memcpy(newTag, data + 512, 24);
1199 newTagSize = 24;
1200 }
1201 else if(ctx->image_info.MediaType == AppleSonyDS ||
1203 {
1204 const sony_tag decoded_sony_tag = priam_tag_to_sony(decoded_priam_tag);
1205 newTag = sony_tag_to_bytes(decoded_sony_tag);
1206 newTagSize = 12;
1207 }
1208 break;
1209 }
1210 case 0:
1211 newTagSize = 0;
1212 break;
1213 default:
1214 FATAL("Incorrect sector size");
1215 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1217 }
1218
1219 if(newTagSize == 0)
1220 return aaruf_write_sector(context, sector_address, negative, data, sector_status, 512);
1221
1222 if(ctx->sector_subchannel == NULL)
1223 {
1224 ctx->sector_subchannel =
1225 calloc(1, newTagSize * (ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow));
1226
1227 if(ctx->sector_subchannel == NULL)
1228 {
1229 FATAL("Could not allocate memory for sector subchannel DDT");
1230
1231 free(newTag);
1232
1233 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1235 }
1236 }
1237
1238 memcpy(ctx->sector_subchannel + sector_address * newTagSize, newTag, newTagSize);
1239 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
1240 free(newTag);
1241
1242 return aaruf_write_sector(context, sector_address, negative, data, sector_status, 512);
1243 }
1244 default:
1246 }
1247 default:
1248 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
1250 }
1251
1252 // Fallback return when media type branch does not produce a value (satisfy non-void contract)
1254}
1255
1439{
1440 // Not a libaaruformat context
1441 if(ctx->magic != AARU_MAGIC) return AARUF_ERROR_NOT_AARUFORMAT;
1442
1443 // Check we are writing
1444 if(!ctx->is_writing) return AARUF_READ_ONLY;
1445
1447
1448 TRACE("Initializing CRC64 context");
1450 TRACE("Updating CRC64");
1453
1454 uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH] = {0};
1455 uint8_t *cmp_buffer = NULL;
1456
1458 {
1459 case None:
1460 break;
1461 case Flac:
1462 cmp_buffer = malloc(ctx->current_block_header.length * 2);
1463 if(cmp_buffer == NULL)
1464 {
1465 FATAL("Could not allocate buffer for compressed data");
1467 }
1468 const uint32_t current_samples = ctx->current_block_offset * SAMPLES_PER_SECTOR;
1469 uint32_t flac_block_size = ctx->current_block_offset * SAMPLES_PER_SECTOR;
1470
1471 if(flac_block_size > MAX_FLAKE_BLOCK) flac_block_size = MAX_FLAKE_BLOCK;
1472 if(flac_block_size < MIN_FLAKE_BLOCK) flac_block_size = MIN_FLAKE_BLOCK;
1473
1474 const long remaining = current_samples % flac_block_size;
1475
1476 // Fill FLAC block
1477 if(remaining != 0)
1478 for(int r = 0; r < remaining * 4; r++) ctx->writing_buffer[ctx->writing_buffer_position + r] = 0;
1479
1481 cmp_buffer, ctx->current_block_header.length * 2, ctx->writing_buffer, ctx->current_block_header.length,
1482 flac_block_size, true, false, "hamming", 12, 15, true, false, 0, 8, "Aaru", 4);
1483
1485 {
1487 free(cmp_buffer);
1488 }
1489
1490 break;
1491 case Lzma:
1492 cmp_buffer = malloc(ctx->current_block_header.length * 2);
1493 if(cmp_buffer == NULL)
1494 {
1495 FATAL("Could not allocate buffer for compressed data");
1497 }
1498
1499 size_t dst_size = ctx->current_block_header.length * 2;
1500 size_t props_size = LZMA_PROPERTIES_LENGTH;
1501 aaruf_lzma_encode_buffer(cmp_buffer, &dst_size, ctx->writing_buffer, ctx->current_block_header.length,
1502 lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
1503
1504 ctx->current_block_header.cmpLength = (uint32_t)dst_size;
1505
1507 {
1509 free(cmp_buffer);
1510 }
1511
1512 break;
1513 default:
1514 FATAL("Invalid compression type");
1516 }
1517
1519 {
1522 }
1523 else
1525
1527
1528 // Add to index
1529 TRACE("Adding block to index");
1530 IndexEntry index_entry;
1531 index_entry.blockType = DataBlock;
1532 index_entry.dataType = UserData;
1533 index_entry.offset = ctx->next_block_position;
1534
1535 utarray_push_back(ctx->index_entries, &index_entry);
1536 ctx->dirty_index_block = true; // Mark index block as dirty
1537 TRACE("Block added to index at offset %" PRIu64, index_entry.offset);
1538
1539 // Write block header to file
1540
1541 // Move to expected block position
1542 fseek(ctx->imageStream, ctx->next_block_position, SEEK_SET);
1543
1544 // Write block header
1545 if(fwrite(&ctx->current_block_header, sizeof(BlockHeader), 1, ctx->imageStream) != 1)
1547
1548 // Write block data
1550 fwrite(lzma_properties, LZMA_PROPERTIES_LENGTH, 1, ctx->imageStream) != 1)
1551 {
1552 free(cmp_buffer);
1554 }
1555
1557 {
1558 if(fwrite(ctx->writing_buffer, ctx->current_block_header.length, 1, ctx->imageStream) != 1)
1560 }
1561 else
1562 {
1563 if(fwrite(cmp_buffer, ctx->current_block_header.cmpLength, 1, ctx->imageStream) != 1)
1564 {
1565 free(cmp_buffer);
1567 }
1568
1569 free(cmp_buffer);
1570 }
1571
1572 // Update nextBlockPosition to point to the next available aligned position
1573 const uint64_t block_total_size = sizeof(BlockHeader) + ctx->current_block_header.cmpLength;
1574 const uint64_t alignment_mask = (1ULL << ctx->user_data_ddt_header.blockAlignmentShift) - 1;
1575 ctx->next_block_position = ctx->next_block_position + block_total_size + alignment_mask & ~alignment_mask;
1576 TRACE("Updated nextBlockPosition to %" PRIu64, ctx->next_block_position);
1577
1578 // Clear values
1579 free(ctx->writing_buffer);
1580 ctx->writing_buffer = NULL;
1581 ctx->current_block_offset = 0;
1582 memset(&ctx->current_block_header, 0, sizeof(BlockHeader));
1584 ctx->writing_buffer_position = 0;
1585
1586 return AARUF_STATUS_OK;
1587}
1588
1836AARU_EXPORT int32_t AARU_CALL aaruf_write_media_tag(void *context, const uint8_t *data, const int32_t type,
1837 const uint32_t length)
1838{
1839 TRACE("Entering aaruf_write_media_tag(%p, %p, %d, %d)", context, data, type, length);
1840
1841 // Check context is correct AaruFormat context
1842 if(context == NULL)
1843 {
1844 FATAL("Invalid context");
1845
1846 TRACE("Exiting aaruf_write_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
1848 }
1849
1850 aaruformat_context *ctx = context;
1851
1852 // Not a libaaruformat context
1853 if(ctx->magic != AARU_MAGIC)
1854 {
1855 FATAL("Invalid context");
1856
1857 TRACE("Exiting aaruf_write_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
1859 }
1860
1861 // Check we are writing
1862 if(!ctx->is_writing)
1863 {
1864 FATAL("Trying to write a read-only image");
1865
1866 TRACE("Exiting aaruf_write_media_tag() = AARUF_READ_ONLY");
1867 return AARUF_READ_ONLY;
1868 }
1869
1870 if(data == NULL || length == 0)
1871 {
1872 FATAL("Invalid data or length");
1874 }
1875
1876 uint8_t *new_data = malloc(length);
1877
1878 if(new_data == NULL)
1879 {
1880 FATAL("Could not allocate memory for media tag");
1882 }
1883 memcpy(new_data, data, length);
1884
1885 mediaTagEntry *media_tag = malloc(sizeof(mediaTagEntry));
1886 mediaTagEntry *old_media_tag = NULL;
1887
1888 if(media_tag == NULL)
1889 {
1890 TRACE("Cannot allocate memory for media tag entry.");
1891 free(new_data);
1893 }
1894
1895 memset(media_tag, 0, sizeof(mediaTagEntry));
1896
1897 media_tag->type = type;
1898 media_tag->data = new_data;
1899 media_tag->length = length;
1900
1901 HASH_REPLACE_INT(ctx->mediaTags, type, media_tag, old_media_tag);
1902
1903 if(old_media_tag != NULL)
1904 {
1905 TRACE("Replaced media tag with type %d", old_media_tag->type);
1906 free(old_media_tag->data);
1907 free(old_media_tag);
1908 old_media_tag = NULL;
1909 }
1910
1911 ctx->dirty_media_tags = true; // Mark media tags as dirty
1912 TRACE("Exiting aaruf_write_media_tag() = AARUF_STATUS_OK");
1913 return AARUF_STATUS_OK;
1914}
1915
2106AARU_EXPORT int32_t AARU_CALL aaruf_write_sector_tag(void *context, const uint64_t sector_address, const bool negative,
2107 const uint8_t *data, const size_t length, const int32_t tag)
2108{
2109 TRACE("Entering aaruf_write_sector_tag(%p, %" PRIu64 ", %d, %p, %zu, %d)", context, sector_address, negative, data,
2110 length, tag);
2111
2112 // Check context is correct AaruFormat context
2113 if(context == NULL)
2114 {
2115 FATAL("Invalid context");
2116
2117 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2119 }
2120
2121 aaruformat_context *ctx = context;
2122
2123 // Not a libaaruformat context
2124 if(ctx->magic != AARU_MAGIC)
2125 {
2126 FATAL("Invalid context");
2127
2128 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2130 }
2131
2132 // Check we are writing
2133 if(!ctx->is_writing)
2134 {
2135 FATAL("Trying to write a read-only image");
2136
2137 TRACE("Exiting aaruf_write_sector_tag() = AARUF_READ_ONLY");
2138 return AARUF_READ_ONLY;
2139 }
2140
2141 if(negative && sector_address > ctx->user_data_ddt_header.negative)
2142 {
2143 FATAL("Sector address out of bounds");
2144
2145 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2147 }
2148
2149 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
2150 {
2151 FATAL("Sector address out of bounds");
2152
2153 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2155 }
2156
2157 if(data == NULL || length == 0)
2158 {
2159 FATAL("Invalid data or length");
2161 }
2162
2163 uint64_t corrected_sector_address = sector_address;
2164
2165 // Calculate positive or negative sector
2166 if(negative)
2167 corrected_sector_address = ctx->user_data_ddt_header.negative - sector_address;
2168 else
2169 corrected_sector_address += ctx->user_data_ddt_header.negative;
2170
2171 const uint64_t total_sectors =
2173
2174 switch(tag)
2175 {
2176 case CdTrackFlags:
2178 {
2179 FATAL("Invalid media type for tag");
2180 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2182 }
2183
2184 if(length != 1)
2185 {
2186 FATAL("Incorrect tag size");
2187 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2189 }
2190
2191 for(int i = 0; i < ctx->tracks_header.entries; i++)
2192 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2193 {
2194 ctx->track_entries[i].flags = data[0];
2195 ctx->dirty_tracks_block = true; // Mark tracks block as dirty
2196 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2197 return AARUF_STATUS_OK;
2198 }
2199
2200 FATAL("Track not found");
2202 case CdTrackIsrc:
2204 {
2205 FATAL("Invalid media type for tag");
2206 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2208 }
2209
2210 if(length != 12)
2211 {
2212 FATAL("Incorrect tag size");
2213 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2215 }
2216
2217 for(int i = 0; i < ctx->tracks_header.entries; i++)
2218 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2219 {
2220 memcpy(ctx->track_entries[i].isrc, data, 12);
2221 ctx->dirty_tracks_block = true; // Mark tracks block as dirty
2222 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2223 return AARUF_STATUS_OK;
2224 }
2225
2226 FATAL("Track not found");
2230 {
2231 FATAL("Invalid media type for tag");
2232 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2234 }
2235
2236 if(length != 96)
2237 {
2238 FATAL("Incorrect tag size");
2239 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2241 }
2242
2243 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 96 * total_sectors);
2244
2245 if(ctx->sector_subchannel == NULL)
2246 {
2247 FATAL("Could not allocate memory for sector subchannel");
2248
2249 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2251 }
2252
2253 memcpy(ctx->sector_subchannel + corrected_sector_address * 96, data, 96);
2254 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2255 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2256 return AARUF_STATUS_OK;
2257 case DvdCmi:
2259 {
2260 FATAL("Invalid media type for tag");
2261 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2263 }
2264
2265 if(length != 1)
2266 {
2267 FATAL("Incorrect tag size");
2268 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2270 }
2271
2272 if(ctx->sector_cpr_mai == NULL) ctx->sector_cpr_mai = calloc(1, 6 * total_sectors);
2273
2274 if(ctx->sector_cpr_mai == NULL)
2275 {
2276 FATAL("Could not allocate memory for sector CPR/MAI");
2277
2278 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2280 }
2281
2282 memcpy(ctx->sector_cpr_mai + corrected_sector_address * 6, data, 1);
2283 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2284 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2285 return AARUF_STATUS_OK;
2288 {
2289 FATAL("Invalid media type for tag");
2290 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2292 }
2293
2294 if(length != 1)
2295 {
2296 FATAL("Incorrect tag size");
2297 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2299 }
2300
2301 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
2302
2303 if(ctx->sector_id == NULL)
2304 {
2305 FATAL("Could not allocate memory for sector ID");
2306
2307 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2309 }
2310
2311 memcpy(ctx->sector_id + corrected_sector_address * 4, data, 1);
2312 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2313 return AARUF_STATUS_OK;
2314 case DvdSectorNumber:
2316 {
2317 FATAL("Invalid media type for tag");
2318 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2320 }
2321
2322 if(length != 3)
2323 {
2324 FATAL("Incorrect tag size");
2325 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2327 }
2328
2329 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
2330
2331 if(ctx->sector_id == NULL)
2332 {
2333 FATAL("Could not allocate memory for sector ID");
2334
2335 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2337 }
2338
2339 memcpy(ctx->sector_id + corrected_sector_address * 4 + 1, data, 3);
2340 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2341 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2342 return AARUF_STATUS_OK;
2343 case DvdSectorIedAaru:
2345 {
2346 FATAL("Invalid media type for tag");
2347 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2349 }
2350
2351 if(length != 2)
2352 {
2353 FATAL("Incorrect tag size");
2354 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2356 }
2357
2358 if(ctx->sector_ied == NULL) ctx->sector_ied = calloc(1, 2 * total_sectors);
2359
2360 if(ctx->sector_ied == NULL)
2361 {
2362 FATAL("Could not allocate memory for sector IED");
2363
2364 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2366 }
2367
2368 memcpy(ctx->sector_ied + corrected_sector_address * 2, data, 2);
2369 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2370 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2371 return AARUF_STATUS_OK;
2372 case DvdSectorEdcAaru:
2374 {
2375 FATAL("Invalid media type for tag");
2376 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2378 }
2379
2380 if(length != 4)
2381 {
2382 FATAL("Incorrect tag size");
2383 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2385 }
2386
2387 if(ctx->sector_edc == NULL) ctx->sector_edc = calloc(1, 4 * total_sectors);
2388
2389 if(ctx->sector_edc == NULL)
2390 {
2391 FATAL("Could not allocate memory for sector EDC");
2392
2393 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2395 }
2396
2397 memcpy(ctx->sector_edc + corrected_sector_address * 4, data, 4);
2398 ctx->dirty_dvd_long_sector_blocks = true; // Mark DVD long sector blocks as dirty
2399 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2400 return AARUF_STATUS_OK;
2403 {
2404 FATAL("Invalid media type for tag");
2405 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2407 }
2408
2409 if(length != 5)
2410 {
2411 FATAL("Incorrect tag size");
2412 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2414 }
2415
2416 if(ctx->sector_decrypted_title_key == NULL) ctx->sector_decrypted_title_key = calloc(1, 5 * total_sectors);
2417
2418 if(ctx->sector_decrypted_title_key == NULL)
2419 {
2420 FATAL("Could not allocate memory for sector decrypted title key");
2421
2422 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2424 }
2425
2426 memcpy(ctx->sector_decrypted_title_key + corrected_sector_address * 5, data, 5);
2427 ctx->dirty_dvd_title_key_decrypted_block = true; // Mark title key block as dirty
2428 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2429 return AARUF_STATUS_OK;
2430 case AppleSonyTagAaru:
2432 {
2433 FATAL("Invalid media type for tag");
2434 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2436 }
2437
2438 if(length != 12)
2439 {
2440 FATAL("Incorrect tag size");
2441 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2443 }
2444
2445 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 12 * total_sectors);
2446
2447 if(ctx->sector_subchannel == NULL)
2448 {
2449 FATAL("Could not allocate memory for Apple Sony tag");
2450
2451 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2453 }
2454
2455 memcpy(ctx->sector_subchannel + corrected_sector_address * 12, data, 12);
2456 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2457 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2458 return AARUF_STATUS_OK;
2461 {
2462 FATAL("Invalid media type for tag");
2463 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2465 }
2466
2467 if(length != 20)
2468 {
2469 FATAL("Incorrect tag size");
2470 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2472 }
2473
2474 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 20 * total_sectors);
2475
2476 if(ctx->sector_subchannel == NULL)
2477 {
2478 FATAL("Could not allocate memory for Apple Profile tag");
2479
2480 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2482 }
2483
2484 memcpy(ctx->sector_subchannel + corrected_sector_address * 20, data, 20);
2485 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2486 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2487 return AARUF_STATUS_OK;
2490 {
2491 FATAL("Invalid media type for tag");
2492 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2494 }
2495
2496 if(length != 24)
2497 {
2498 FATAL("Incorrect tag size");
2499 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2501 }
2502
2503 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 24 * total_sectors);
2504
2505 if(ctx->sector_subchannel == NULL)
2506 {
2507 FATAL("Could not allocate memory for Priam Data Tower tag");
2508
2509 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2511 }
2512
2513 memcpy(ctx->sector_subchannel + corrected_sector_address * 24, data, 24);
2514 ctx->dirty_sector_subchannel_block = true; // Mark subchannel block as dirty
2515 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2516 return AARUF_STATUS_OK;
2517 default:
2518 TRACE("Do not know how to write sector tag %d", tag);
2520 }
2521}
#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:46
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:564
void aaruf_md5_update(md5_ctx *ctx, const void *data, unsigned long size)
Definition md5.c:447
#define AARU_EXPORT
Definition decls.h:55
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:182
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:118
@ DataBlock
Block containing data.
Definition enums.h:144
@ SectorStatusNotDumped
Sector(s) not yet acquired during image dumping.
Definition enums.h:236
@ SectorStatusMode2Form2NoCrc
Suffix matches MODE 2 Form 2 but CRC empty/missing.
Definition enums.h:242
@ SectorStatusMode1Correct
Valid MODE 1 data with regenerable suffix/prefix.
Definition enums.h:239
@ SectorStatusMode2Form2Ok
Suffix matches MODE 2 Form 2 with valid CRC.
Definition enums.h:241
@ SectorStatusErrored
Error during dumping; data may be incomplete or corrupt.
Definition enums.h:238
@ SectorStatusMode2Form1Ok
Suffix verified/regenerable for MODE 2 Form 1.
Definition enums.h:240
@ OpticalDisc
Purely optical discs.
Definition enums.h:224
@ BlockMedia
Media that is physically block-based or abstracted like that.
Definition enums.h:225
@ CdMode1
Compact Disc Mode 1 data track.
Definition enums.h:203
@ Data
Generic data track (not further specified).
Definition enums.h:202
@ CdMode2Form2
Compact Disc Mode 2 Form 2 data track.
Definition enums.h:206
@ Audio
Audio track.
Definition enums.h:201
@ CdMode2Form1
Compact Disc Mode 2 Form 1 data track.
Definition enums.h:205
@ CdMode2Formless
Compact Disc Mode 2 (formless) data track.
Definition enums.h:204
@ 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:77
#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_INVALID_SECTOR_LENGTH
Sector length is too big.
Definition errors.h:70
#define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER
Failure writing block header.
Definition errors.h:62
@ AppleProfile
Definition aaru.h:708
@ VideoNowColor
Hasbro VideoNow Color disc.
Definition aaru.h:782
@ AppleSonySS
3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR
Definition aaru.h:250
@ 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:209
@ JaguarCD
Atari Jaguar CD.
Definition aaru.h:235
@ PS2DVD
Sony PlayStation 2 game DVD.
Definition aaru.h:208
@ VideoNow
Hasbro VideoNow 85 mm proprietary video disc.
Definition aaru.h:781
@ VideoNowXp
Hasbro VideoNow XP higher capacity disc.
Definition aaru.h:783
@ PriamDataTower
Definition aaru.h:711
@ AppleFileWare
5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy
Definition aaru.h:252
@ DVDPR
DVD+R.
Definition aaru.h:139
@ AppleWidget
Definition aaru.h:709
@ DVDPRW
DVD+RW.
Definition aaru.h:140
@ Nuon
Nuon (DVD based videogame console).
Definition aaru.h:241
@ 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:251
@ 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:976
@ CdTrackFlags
Track flags (audio/data, copy permitted, pre-emphasis).
Definition aaru.h:969
@ DvdSectorEdcAaru
DVD sector EDC, 4 bytes.
Definition aaru.h:977
@ DvdCmi
DVD Copyright Management Information (CSS).
Definition aaru.h:970
@ CdSectorSubchannelAaru
96 raw subchannel bytes (P-W)
Definition aaru.h:966
@ DvdSectorNumber
DVD sector number, 3 bytes.
Definition aaru.h:975
@ CdTrackIsrc
Track ISRC (12 ASCII chars, no terminator).
Definition aaru.h:967
@ PriamDataTowerTagAaru
Priam DataTower sector tags, 24 bytes.
Definition aaru.h:979
@ AppleProfileTagAaru
Apple's Profile sector tags, 20 bytes.
Definition aaru.h:978
@ DvdSectorInformation
DVD sector information, 1 bytes.
Definition aaru.h:974
@ DvdTitleKeyDecrypted
Decrypted DVD sector title key, 5 bytes.
Definition aaru.h:973
@ AppleSonyTagAaru
Apple's Sony sector tags, 12 bytes (address prolog + checksum).
Definition aaru.h:958
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:228
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:185
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:1002
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
uint16_t biggestSectorSize
size of biggest sector in the image (in bytes).
Definition header.h:120
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
uint8_t blockAlignmentShift
2^blockAlignmentShift = block alignment boundary in bytes.
Definition ddt.h:154
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
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:943
uint8_t MetadataMediaType
Media type for sidecar generation (internal archival use).
Definition aaru.h:944
uint64_t Sectors
Total count of addressable logical sectors/blocks.
Definition aaru.h:936
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:175
DdtHeader2 user_data_ddt_header
Active user data DDT v2 header (primary table meta).
Definition context.h:192
bool dirty_checksum_block
True if checksum block should be written during close.
Definition context.h:320
bool deduplicate
Storage deduplication active (duplicates coalesce).
Definition context.h:302
size_t sector_suffix_length
Length of sector_suffix.
Definition context.h:288
bool compression_enabled
True if block compression enabled (writing path).
Definition context.h:303
uint64_t last_written_block
Last written block number (write path).
Definition context.h:286
uint8_t * sector_cpr_mai
DVD sector CPR_MAI (6 bytes) if present.
Definition context.h:210
bool dirty_media_tags
True if media tags should be written during close.
Definition context.h:330
hash_map_t * sector_hash_map
Deduplication hash map (fingerprint->entry mapping).
Definition context.h:256
sha256_ctx sha256_context
Opaque SHA-256 context for streaming updates.
Definition context.h:275
bool calculating_sha256
True if whole-image SHA-256 being calculated on-the-fly.
Definition context.h:278
uint8_t * sector_ied
DVD sector IED (2 bytes) if present.
Definition context.h:209
md5_ctx md5_context
Opaque MD5 context for streaming updates.
Definition context.h:273
bool dirty_sector_suffix_block
True if sector suffix block should be written during close.
Definition context.h:325
uint8_t * sector_prefix
Raw per-sector prefix (e.g., sync+header) uncorrected.
Definition context.h:202
bool dirty_dvd_title_key_decrypted_block
True if decrypted title key block should be written during close.
Definition context.h:329
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
Definition context.h:189
bool dirty_mode2_subheaders_block
True if MODE2 subheader block should be written during close.
Definition context.h:322
uint8_t * sector_edc
DVD sector EDC (4 bytes) if present.
Definition context.h:211
bool calculating_sha1
True if whole-image SHA-1 being calculated on-the-fly.
Definition context.h:277
bool dirty_tracks_block
True if tracks block should be written during close.
Definition context.h:321
CdEccContext * ecc_cd_context
CD ECC/EDC helper tables (allocated on demand).
Definition context.h:251
bool rewinded
True if stream has been rewound after open (write path).
Definition context.h:296
bool dirty_sector_prefix_block
True if sector prefix block should be written during close.
Definition context.h:323
bool dirty_index_block
True if index block should be written during close.
Definition context.h:340
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 current_block_offset
Logical offset inside block (units: bytes or sectors depending on path).
Definition context.h:291
bool is_writing
True if context opened/created for writing.
Definition context.h:295
spamsum_ctx * spamsum_context
Opaque SpamSum context for streaming updates.
Definition context.h:270
size_t sector_prefix_offset
Current position in sector_prefix.
Definition context.h:289
BlockHeader current_block_header
Header for block currently being assembled (write path).
Definition context.h:284
uint64_t magic
File magic (AARU_MAGIC) post-open.
Definition context.h:177
uint8_t * writing_buffer
Accumulation buffer for current block data.
Definition context.h:283
uint64_t * sector_prefix_ddt2
CD sector prefix DDT V2.
Definition context.h:188
bool calculating_spamsum
True if whole-image SpamSum being calculated on-the-fly.
Definition context.h:279
size_t sector_prefix_length
Length of sector_prefix.
Definition context.h:287
mediaTagEntry * mediaTags
Hash table of extra media tags (uthash root).
Definition context.h:267
blake3_hasher * blake3_context
Opaque BLAKE3 context for streaming updates.
Definition context.h:271
bool calculating_blake3
True if whole-image BLAKE3 being calculated on-the-fly.
Definition context.h:280
uint64_t next_block_position
Absolute file offset where next block will be written.
Definition context.h:285
bool calculating_md5
True if whole-image MD5 being calculated on-the-fly.
Definition context.h:276
bool dirty_sector_suffix_ddt
True if sector suffix DDT should be written during close.
Definition context.h:326
size_t sector_suffix_offset
Current position in sector_suffix.
Definition context.h:290
uint8_t * sector_decrypted_title_key
DVD decrypted title key (5 bytes) if present.
Definition context.h:212
int writing_buffer_position
Current size / position within writingBuffer.
Definition context.h:292
bool block_zero_written
True if block zero has been written (writing path).
Definition context.h:298
crc64_ctx * crc64_context
Opaque CRC64 context for streaming updates.
Definition context.h:252
uint8_t * sector_subchannel
Raw 96-byte subchannel (if captured).
Definition context.h:206
bool dirty_sector_subchannel_block
True if subchannel block should be written during close.
Definition context.h:327
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:179
bool dirty_dvd_long_sector_blocks
True if DVD long sector blocks should be written during close.
Definition context.h:328
bool dirty_sector_prefix_ddt
True if sector prefix DDT should be written during close.
Definition context.h:324
UT_array * index_entries
Flattened index entries (UT_array of IndexEntry).
Definition context.h:255
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
uint8_t * sector_id
DVD sector ID (4 bytes) if present.
Definition context.h:208
sha1_ctx sha1_context
Opaque SHA-1 context for streaming updates.
Definition context.h:274
uint32_t lzma_dict_size
LZMA dictionary size (writing path).
Definition context.h:301
TrackEntry * track_entries
Full track list (tracksHeader.entries elements).
Definition context.h:245
uint8_t current_track_type
Current track type (when writing optical images with tracks, needed for block compression type).
Definition context.h:293
bool writing_long
True if writing long sectors.
Definition context.h:297
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
int32_t type
Numeric type identifier.
Definition context.h:124
uint32_t length
Length in bytes of data.
Definition context.h:125
int32_t aaruf_close_current_block(aaruformat_context *ctx)
Finalizes and writes the current data block to the AaruFormat image file.
Definition write.c:1438
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:2106
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:1836
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:99
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:555