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
98int32_t aaruf_write_sector(void *context, uint64_t sector_address, bool negative, const uint8_t *data,
99 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 - 1)
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 TRACE("Rewinded");
154 ctx->rewinded = true;
155
156 // Disable MD5 calculation
157 if(ctx->calculating_md5) ctx->calculating_md5 = false;
158 // Disable SHA1 calculation
159 if(ctx->calculating_sha1) ctx->calculating_sha1 = false;
160 // Disable SHA256 calculation
161 if(ctx->calculating_sha256) ctx->calculating_sha256 = false;
162 // Disable SpamSum calculation
163 if(ctx->calculating_spamsum) ctx->calculating_spamsum = false;
164 // Disable BLAKE3 calculation
165 if(ctx->calculating_blake3) ctx->calculating_blake3 = false;
166 }
167 else
168 ctx->last_written_block = sector_address;
169 }
170
171 // Calculate MD5 on-the-fly if requested and sector is within user sectors (not negative or overflow)
172 if(ctx->calculating_md5 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
173 aaruf_md5_update(&ctx->md5_context, data, length);
174 // Calculate SHA1 on-the-fly if requested and sector is within user sectors (not negative or overflow)
175 if(ctx->calculating_sha1 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
176 aaruf_sha1_update(&ctx->sha1_context, data, length);
177 // Calculate SHA256 on-the-fly if requested and sector is within user sectors (not negative or overflow)
178 if(ctx->calculating_sha256 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
179 aaruf_sha256_update(&ctx->sha256_context, data, length);
180 // Calculate SpamSum on-the-fly if requested and sector is within user sectors (not negative or overflow)
181 if(ctx->calculating_spamsum && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
182 aaruf_spamsum_update(ctx->spamsum_context, data, length);
183 // Calculate BLAKE3 on-the-fly if requested and sector is within user sectors (not negative or overflow)
184 if(ctx->calculating_blake3 && !negative && sector_address <= ctx->image_info.Sectors && !ctx->writing_long)
185 blake3_hasher_update(ctx->blake3_context, data, length);
186
187 // Close current block first
188 if(ctx->writing_buffer != NULL &&
189 // When sector size changes or block reaches maximum size
190 (ctx->current_block_header.sectorSize != length ||
192 {
193 TRACE("Closing current block before writing new data");
194 int error = aaruf_close_current_block(ctx);
195
196 if(error != AARUF_STATUS_OK)
197 {
198 FATAL("Error closing current block: %d", error);
199
200 TRACE("Exiting aaruf_write_sector() = %d", error);
201 return error;
202 }
203 }
204
205 uint64_t ddt_entry = 0;
206 bool ddt_ok;
207
208 if(ctx->deduplicate)
209 {
210 // Calculate 64-bit XXH3 hash of the sector
211 TRACE("Hashing sector data for deduplication");
212 uint64_t hash = XXH3_64bits(data, length);
213
214 // Check if the hash is already in the map
215 bool existing = lookup_map(ctx->sector_hash_map, hash, &ddt_entry);
216 TRACE("Block does %s exist in deduplication map", existing ? "already" : "not yet");
217
218 ddt_ok = set_ddt_entry_v2(ctx, sector_address, negative, ctx->current_block_offset, ctx->next_block_position,
219 sector_status, &ddt_entry);
220 if(!ddt_ok)
221 {
222 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_CANNOT_SET_DDT_ENTRY");
224 }
225
226 if(existing)
227 {
228 TRACE("Sector exists, so not writing to image");
229 TRACE("Exiting aaruf_write_sector() = AARUF_STATUS_OK");
230 return AARUF_STATUS_OK;
231 }
232
233 TRACE("Inserting sector hash into deduplication map, proceeding to write into image as normal");
234 insert_map(ctx->sector_hash_map, hash, ddt_entry);
235 }
236 else
237 ddt_ok = set_ddt_entry_v2(ctx, sector_address, negative, ctx->current_block_offset, ctx->next_block_position,
238 sector_status, &ddt_entry);
239
240 if(!ddt_ok)
241 {
242 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_CANNOT_SET_DDT_ENTRY");
244 }
245
246 // No block set
247 if(ctx->writing_buffer_position == 0)
248 {
249 TRACE("Creating new writing block");
252 ctx->current_block_header.sectorSize = length;
253
254 // We need to save the track type for later compression
255 if(ctx->image_info.MetadataMediaType == OpticalDisc && ctx->track_entries != NULL)
256 {
257 const TrackEntry *track = NULL;
258 for(int i = 0; i < ctx->tracks_header.entries; i++)
259 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
260 {
261 track = &ctx->track_entries[i];
262 break;
263 }
264
265 if(track != NULL)
266 {
267 ctx->current_track_type = track->type;
268
269 if(track->sequence == 0 && track->start == 0 && track->end == 0) ctx->current_track_type = Data;
270 }
271 else
273
274 if(ctx->current_track_type == Audio &&
275 // JaguarCD stores data in audio tracks. FLAC is too inefficient, we need to use LZMA as data.
276 (ctx->image_info.MediaType == JaguarCD && track->session > 1 ||
277 // VideoNow stores video in audio tracks, and LZMA works better too.
281
282 if(ctx->compression_enabled)
283 {
284 if(ctx->current_track_type == Audio)
286 else
288 }
289 else
291 }
292 else
293 {
295 if(ctx->compression_enabled)
297 else
299 }
300
301 uint32_t max_buffer_size = (1 << ctx->user_data_ddt_header.dataShift) * ctx->current_block_header.sectorSize;
302 TRACE("Setting max buffer size to %u bytes", max_buffer_size);
303
304 TRACE("Allocating memory for writing buffer");
305 ctx->writing_buffer = (uint8_t *)calloc(1, max_buffer_size);
306 if(ctx->writing_buffer == NULL)
307 {
308 FATAL("Could not allocate memory");
309
310 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
312 }
313 }
314
315 TRACE("Copying data to writing buffer at position %zu", ctx->writing_buffer_position);
316 memcpy(ctx->writing_buffer + ctx->writing_buffer_position, data, length);
317 TRACE("Advancing writing buffer position to %zu", ctx->writing_buffer_position + length);
318 ctx->writing_buffer_position += length;
319 TRACE("Advancing current block offset to %zu", ctx->current_block_offset + 1);
321
322 TRACE("Exiting aaruf_write_sector() = AARUF_STATUS_OK");
323 return AARUF_STATUS_OK;
324}
325
532int32_t aaruf_write_sector_long(void *context, uint64_t sector_address, bool negative, const uint8_t *data,
533 uint8_t sector_status, uint32_t length)
534{
535 TRACE("Entering aaruf_write_sector_long(%p, %" PRIu64 ", %d, %p, %u, %u)", context, sector_address, negative, data,
536 sector_status, length);
537
538 // Check context is correct AaruFormat context
539 if(context == NULL)
540 {
541 FATAL("Invalid context");
542
543 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
545 }
546
547 aaruformat_context *ctx = context;
548
549 // Not a libaaruformat context
550 if(ctx->magic != AARU_MAGIC)
551 {
552 FATAL("Invalid context");
553
554 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_AARUFORMAT");
556 }
557
558 // Check we are writing
559 if(!ctx->is_writing)
560 {
561 FATAL("Trying to write a read-only image");
562
563 TRACE("Exiting aaruf_write_sector() = AARUF_READ_ONLY");
564 return AARUF_READ_ONLY;
565 }
566
567 if(negative && sector_address > ctx->user_data_ddt_header.negative - 1)
568 {
569 FATAL("Sector address out of bounds");
570
571 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
573 }
574
575 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
576 {
577 FATAL("Sector address out of bounds");
578
579 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
581 }
582
583 switch(ctx->image_info.MetadataMediaType)
584 {
585 case OpticalDisc:
586 TrackEntry track = {0};
587
588 for(int i = 0; i < ctx->tracks_header.entries; i++)
589 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
590 {
591 track = ctx->track_entries[i];
592 break;
593 }
594
595 if(track.sequence == 0 && track.start == 0 && track.end == 0) track.type = Data;
596
597 uint64_t corrected_sector_address = sector_address;
598
599 // Calculate positive or negative sector
600 if(negative)
601 corrected_sector_address -= ctx->user_data_ddt_header.negative;
602 else
603 corrected_sector_address += ctx->user_data_ddt_header.negative;
604
605 uint64_t total_sectors =
607
608 // DVD long sector
609 if(length == 2064 && (ctx->image_info.MediaType == DVDROM || ctx->image_info.MediaType == PS2DVD ||
610 ctx->image_info.MediaType == SACD || ctx->image_info.MediaType == PS3DVD ||
611 ctx->image_info.MediaType == DVDR || ctx->image_info.MediaType == DVDRW ||
616 ctx->image_info.MediaType == Nuon))
617 {
618 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
619 if(ctx->sector_ied == NULL) ctx->sector_ied = calloc(1, 2 * total_sectors);
620 if(ctx->sector_cpr_mai == NULL) ctx->sector_cpr_mai = calloc(1, 6 * total_sectors);
621 if(ctx->sector_edc == NULL) ctx->sector_edc = calloc(1, 4 * total_sectors);
622
623 memcpy(ctx->sector_id + corrected_sector_address * 4, data, 4);
624 memcpy(ctx->sector_ied + corrected_sector_address * 2, data + 4, 2);
625 memcpy(ctx->sector_cpr_mai + corrected_sector_address * 6, data + 6, 6);
626 memcpy(ctx->sector_edc + corrected_sector_address * 4, data + 2060, 4);
627
628 return aaruf_write_sector(context, sector_address, negative, data + 12, sector_status, 2048);
629 }
630
631 if(length != 2352)
632 {
633 FATAL("Incorrect sector size");
634 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
636 }
637
638 ctx->writing_long = true;
639
640 if(!ctx->rewinded)
641 {
642 if(sector_address <= ctx->last_written_block)
643 {
644 TRACE("Rewinded");
645 ctx->rewinded = true;
646
647 // Disable MD5 calculation
648 if(ctx->calculating_md5) ctx->calculating_md5 = false;
649 // Disable SHA1 calculation
650 if(ctx->calculating_sha1) ctx->calculating_sha1 = false;
651 // Disable SHA256 calculation
652 if(ctx->calculating_sha256) ctx->calculating_sha256 = false;
653 // Disable SpamSum calculation
654 if(ctx->calculating_spamsum) ctx->calculating_spamsum = false;
655 // Disable BLAKE3 calculation
656 if(ctx->calculating_blake3) ctx->calculating_blake3 = false;
657 }
658 else
659 ctx->last_written_block = sector_address;
660 }
661
662 // Calculate MD5 on-the-fly if requested and sector is within user sectors (not negative or overflow)
663 if(ctx->calculating_md5 && !negative && sector_address <= ctx->image_info.Sectors)
664 aaruf_md5_update(&ctx->md5_context, data, length);
665 // Calculate SHA1 on-the-fly if requested and sector is within user sectors (not negative or overflow)
666 if(ctx->calculating_sha1 && !negative && sector_address <= ctx->image_info.Sectors)
667 aaruf_sha1_update(&ctx->sha1_context, data, length);
668 // Calculate SHA256 on-the-fly if requested and sector is within user sectors (not negative or overflow)
669 if(ctx->calculating_sha256 && !negative && sector_address <= ctx->image_info.Sectors)
670 aaruf_sha256_update(&ctx->sha256_context, data, length);
671 // Calculate SpamSum on-the-fly if requested and sector is within user sectors (not negative or overflow)
672 if(ctx->calculating_spamsum && !negative && sector_address <= ctx->image_info.Sectors)
673 aaruf_spamsum_update(ctx->spamsum_context, data, length);
674 // Calculate BLAKE3 on-the-fly if requested and sector is within user sectors (not negative or overflow)
675 if(ctx->calculating_blake3 && !negative && sector_address <= ctx->image_info.Sectors)
676 blake3_hasher_update(ctx->blake3_context, data, length);
677
678 bool prefix_correct;
679
680 // Split raw cd sector data in prefix (sync, header), user data and suffix (edc, ecc p, ecc q)
681 switch(track.type)
682 {
683 case Audio:
684 case Data:
685 return aaruf_write_sector(context, sector_address, negative, data, sector_status, length);
686 case CdMode1:
687
688 // If we do not have a DDT V2 for sector prefix, create one
689 if(ctx->sector_prefix_ddt2 == NULL)
690 {
691 ctx->sector_prefix_ddt2 =
692 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
694
695 if(ctx->sector_prefix_ddt2 == NULL)
696 {
697 FATAL("Could not allocate memory for CD sector prefix DDT");
698
699 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
701 }
702 }
703
704 // If we do not have a DDT V2 for sector suffix, create one
705 if(ctx->sector_suffix_ddt2 == NULL)
706 {
707 ctx->sector_suffix_ddt2 =
708 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
710
711 if(ctx->sector_suffix_ddt2 == NULL)
712 {
713 FATAL("Could not allocate memory for CD sector prefix DDT");
714
715 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
717 }
718 }
719
720 if(ctx->sector_prefix == NULL)
721 {
724 ctx->sector_prefix = malloc(ctx->sector_prefix_length);
725
726 if(ctx->sector_prefix == NULL)
727 {
728 FATAL("Could not allocate memory for CD sector prefix buffer");
729
730 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
732 }
733 }
734
735 if(ctx->sector_suffix == NULL)
736 {
740 ctx->sector_suffix = malloc(ctx->sector_suffix_length);
741
742 if(ctx->sector_suffix == NULL)
743 {
744 FATAL("Could not allocate memory for CD sector suffix buffer");
745
746 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
748 }
749 }
750
751 bool empty = true;
752
753 for(int i = 0; i < length; i++)
754 if(data[i] != 0)
755 {
756 empty = false;
757 break;
758 }
759
760 if(empty)
761 {
762 ctx->sector_prefix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
763 ctx->sector_suffix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
764 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
765 2048);
766 }
767
768 prefix_correct = true;
769
770 if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
771 data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
772 data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
773 data[0x0F] != 0x01)
774 prefix_correct = false;
775
776 if(prefix_correct)
777 {
778 const int minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
779 const int second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
780 const int frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
781 const int stored_lba = minute * 60 * 75 + second * 75 + frame - 150;
782 prefix_correct = stored_lba == sector_address;
783 }
784
785 if(prefix_correct)
786 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode1Correct << 60;
787 else
788 {
789 // Copy CD prefix from data buffer to prefix buffer
790 memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
791 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_prefix_offset / 16);
792 ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
793 ctx->sector_prefix_offset += 16;
794
795 // Grow prefix buffer if needed
797 {
798 ctx->sector_prefix_length *= 2;
799 ctx->sector_prefix = realloc(ctx->sector_prefix, ctx->sector_prefix_length);
800
801 if(ctx->sector_prefix == NULL)
802 {
803 FATAL("Could not allocate memory for CD sector prefix buffer");
804
805 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
807 }
808 }
809 }
810
811 const bool suffix_correct = aaruf_ecc_cd_is_suffix_correct(ctx->ecc_cd_context, data);
812
813 if(suffix_correct)
814 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode1Correct << 60;
815 else
816 {
817 // Copy CD suffix from data buffer to suffix buffer
818 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2064, 288);
819 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288);
820 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
821 ctx->sector_suffix_offset += 288;
822
823 // Grow suffix buffer if needed
825 {
826 ctx->sector_suffix_length *= 2;
827 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
828
829 if(ctx->sector_suffix == NULL)
830 {
831 FATAL("Could not allocate memory for CD sector suffix buffer");
832
833 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
835 }
836 }
837 }
838
839 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusMode1Correct,
840 2048);
841 case CdMode2Form1:
842 case CdMode2Form2:
843 case CdMode2Formless:
844 // If we do not have a DDT V2 for sector prefix, create one
845 if(ctx->sector_prefix_ddt2 == NULL)
846 {
847 ctx->sector_prefix_ddt2 =
848 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
850
851 if(ctx->sector_prefix_ddt2 == NULL)
852 {
853 FATAL("Could not allocate memory for CD sector prefix DDT");
854
855 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
857 }
858 }
859
860 // If we do not have a DDT V2 for sector suffix, create one
861 if(ctx->sector_suffix_ddt2 == NULL)
862 {
863 ctx->sector_suffix_ddt2 =
864 calloc(1, sizeof(uint64_t) * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
866
867 if(ctx->sector_suffix_ddt2 == NULL)
868 {
869 FATAL("Could not allocate memory for CD sector prefix DDT");
870
871 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
873 }
874 }
875
876 if(ctx->sector_prefix == NULL)
877 {
880 ctx->sector_prefix = malloc(ctx->sector_prefix_length);
881
882 if(ctx->sector_prefix == NULL)
883 {
884 FATAL("Could not allocate memory for CD sector prefix buffer");
885
886 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
888 }
889 }
890
891 if(ctx->sector_suffix == NULL)
892 {
896 ctx->sector_suffix = malloc(ctx->sector_suffix_length);
897
898 if(ctx->sector_suffix == NULL)
899 {
900 FATAL("Could not allocate memory for CD sector suffix buffer");
901
902 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
904 }
905 }
906
907 empty = true;
908
909 for(int i = 0; i < length; i++)
910 if(data[i] != 0)
911 {
912 empty = false;
913 break;
914 }
915
916 if(empty)
917 {
918 ctx->sector_prefix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
919 ctx->sector_suffix_ddt2[corrected_sector_address] = SectorStatusNotDumped;
920 return aaruf_write_sector(context, sector_address, negative, data + 16, SectorStatusNotDumped,
921 2328);
922 }
923
924 const bool form2 = (data[18] & 0x20) == 0x20 || (data[22] & 0x20) == 0x20;
925
926 prefix_correct = true;
927
928 if(data[0x00] != 0x00 || data[0x01] != 0xFF || data[0x02] != 0xFF || data[0x03] != 0xFF ||
929 data[0x04] != 0xFF || data[0x05] != 0xFF || data[0x06] != 0xFF || data[0x07] != 0xFF ||
930 data[0x08] != 0xFF || data[0x09] != 0xFF || data[0x0A] != 0xFF || data[0x0B] != 0x00 ||
931 data[0x0F] != 0x02)
932 prefix_correct = false;
933
934 if(prefix_correct)
935 {
936 const int minute = (data[0x0C] >> 4) * 10 + (data[0x0C] & 0x0F);
937 const int second = (data[0x0D] >> 4) * 10 + (data[0x0D] & 0x0F);
938 const int frame = (data[0x0E] >> 4) * 10 + (data[0x0E] & 0x0F);
939 const int stored_lba = minute * 60 * 75 + second * 75 + frame - 150;
940 prefix_correct = stored_lba == sector_address;
941 }
942
943 if(prefix_correct)
944 ctx->sector_prefix_ddt2[corrected_sector_address] =
945 (uint64_t)(form2 ? SectorStatusMode2Form2Ok : SectorStatusMode2Form1Ok) << 60;
946 else
947 {
948 // Copy CD prefix from data buffer to prefix buffer
949 memcpy(ctx->sector_prefix + ctx->sector_prefix_offset, data, 16);
950 ctx->sector_prefix_ddt2[corrected_sector_address] = (uint32_t)(ctx->sector_prefix_offset / 16);
951 ctx->sector_prefix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
952 ctx->sector_prefix_offset += 16;
953
954 // Grow prefix buffer if needed
956 {
957 ctx->sector_prefix_length *= 2;
958 ctx->sector_prefix = realloc(ctx->sector_prefix, ctx->sector_prefix_length);
959
960 if(ctx->sector_prefix == NULL)
961 {
962 FATAL("Could not allocate memory for CD sector prefix buffer");
963
964 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
966 }
967 }
968 }
969
970 if(ctx->mode2_subheaders == NULL)
971 {
972 ctx->mode2_subheaders =
973 calloc(1, 8 * (ctx->user_data_ddt_header.negative + ctx->image_info.Sectors +
975
976 if(ctx->mode2_subheaders == NULL)
977 {
978 FATAL("Could not allocate memory for CD mode 2 subheader buffer");
979
980 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
982 }
983 }
984
985 if(form2)
986 {
987 const uint32_t computed_edc = aaruf_edc_cd_compute(ctx->ecc_cd_context, 0, data, 0x91C, 0x10);
988 uint32_t edc = 0;
989 memcpy(&edc, data + 0x92C, sizeof(edc));
990 const bool correct_edc = computed_edc == edc;
991
992 if(correct_edc)
993 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form2Ok
994 << 60;
995 else if(edc == 0)
996 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form2NoCrc
997 << 60;
998 else
999 {
1000 // Copy CD suffix from data buffer to suffix buffer
1001 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2348, 4);
1002 ctx->sector_suffix_ddt2[corrected_sector_address] =
1003 (uint64_t)(ctx->sector_suffix_offset / 288);
1004 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
1005 ctx->sector_suffix_offset += 288;
1006
1007 // Grow suffix buffer if needed
1009 {
1010 ctx->sector_suffix_length *= 2;
1011 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
1012
1013 if(ctx->sector_suffix == NULL)
1014 {
1015 FATAL("Could not allocate memory for CD sector suffix buffer");
1016
1017 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1019 }
1020 }
1021 }
1022
1023 // Copy subheader from data buffer to subheader buffer
1024 memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8);
1025 return aaruf_write_sector(context, sector_address, negative, data + 24,
1027 : correct_edc ? SectorStatusMode2Form2Ok
1029 2324);
1030 }
1031
1032 const bool correct_ecc = aaruf_ecc_cd_is_suffix_correct_mode2(ctx->ecc_cd_context, data);
1033 const uint32_t computed_edc = aaruf_edc_cd_compute(ctx->ecc_cd_context, 0, data, 0x808, 0x10);
1034 uint32_t edc = 0;
1035 memcpy(&edc, data + 0x818, sizeof(edc));
1036 const bool correct_edc = computed_edc == edc;
1037
1038 if(correct_ecc && correct_edc)
1039 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)SectorStatusMode2Form1Ok << 60;
1040 else
1041 {
1042 // Copy CD suffix from data buffer to suffix buffer
1043 memcpy(ctx->sector_suffix + ctx->sector_suffix_offset, data + 2072, 280);
1044 ctx->sector_suffix_ddt2[corrected_sector_address] = (uint64_t)(ctx->sector_suffix_offset / 288);
1045 ctx->sector_suffix_ddt2[corrected_sector_address] |= (uint64_t)SectorStatusErrored << 60;
1046 ctx->sector_suffix_offset += 288;
1047
1048 // Grow suffix buffer if needed
1050 {
1051 ctx->sector_suffix_length *= 2;
1052 ctx->sector_suffix = realloc(ctx->sector_suffix, ctx->sector_suffix_length);
1053
1054 if(ctx->sector_suffix == NULL)
1055 {
1056 FATAL("Could not allocate memory for CD sector suffix buffer");
1057
1058 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1060 }
1061 }
1062 }
1063
1064 // Copy subheader from data buffer to subheader buffer
1065 memcpy(ctx->mode2_subheaders + corrected_sector_address * 8, data + 0x10, 8);
1066 return aaruf_write_sector(
1067 context, sector_address, negative, data + 24,
1068 correct_edc && correct_ecc ? SectorStatusMode2Form1Ok : SectorStatusErrored, 2048);
1069 }
1070
1071 break;
1072 case BlockMedia:
1073 switch(ctx->image_info.MediaType)
1074 {
1075 case AppleFileWare:
1076 case AppleProfile:
1077 case AppleSonyDS:
1078 case AppleSonySS:
1079 case AppleWidget:
1080 case PriamDataTower:
1081 uint8_t *newTag;
1082 int newTagSize = 0;
1083
1084 switch(length - 512)
1085 {
1086 // Sony tag
1087 case 12:
1088 const sony_tag decoded_sony_tag = bytes_to_sony_tag(data + 512);
1089
1091 {
1092 const profile_tag decoded_profile_tag = sony_tag_to_profile(decoded_sony_tag);
1093 newTag = profile_tag_to_bytes(decoded_profile_tag);
1094 newTagSize = 20;
1095 }
1096 else if(ctx->image_info.MediaType == PriamDataTower)
1097 {
1098 const priam_tag decoded_priam_tag = sony_tag_to_priam(decoded_sony_tag);
1099 newTag = priam_tag_to_bytes(decoded_priam_tag);
1100 newTagSize = 24;
1101 }
1102 else if(ctx->image_info.MediaType == AppleSonyDS ||
1104 {
1105 newTag = malloc(12);
1106 memcpy(newTag, data + 512, 12);
1107 newTagSize = 12;
1108 }
1109 break;
1110 // Profile tag
1111 case 20:
1112 const profile_tag decoded_profile_tag = bytes_to_profile_tag(data + 512);
1113
1115 {
1116 newTag = malloc(20);
1117 memcpy(newTag, data + 512, 20);
1118 newTagSize = 20;
1119 }
1120 else if(ctx->image_info.MediaType == PriamDataTower)
1121 {
1122 const priam_tag decoded_priam_tag = profile_tag_to_priam(decoded_profile_tag);
1123 newTag = priam_tag_to_bytes(decoded_priam_tag);
1124 newTagSize = 24;
1125 }
1126 else if(ctx->image_info.MediaType == AppleSonyDS ||
1128 {
1129 const sony_tag decoded_sony_tag = profile_tag_to_sony(decoded_profile_tag);
1130 newTag = sony_tag_to_bytes(decoded_sony_tag);
1131 newTagSize = 12;
1132 }
1133 break;
1134 // Priam tag
1135 case 24:
1136 const priam_tag decoded_priam_tag = bytes_to_priam_tag(data + 512);
1138 {
1139 const profile_tag decoded_profile_tag = priam_tag_to_profile(decoded_priam_tag);
1140 newTag = profile_tag_to_bytes(decoded_profile_tag);
1141 newTagSize = 20;
1142 }
1143 else if(ctx->image_info.MediaType == PriamDataTower)
1144 {
1145 newTag = malloc(24);
1146 memcpy(newTag, data + 512, 24);
1147 newTagSize = 24;
1148 }
1149 else if(ctx->image_info.MediaType == AppleSonyDS ||
1151 {
1152 const sony_tag decoded_sony_tag = priam_tag_to_sony(decoded_priam_tag);
1153 newTag = sony_tag_to_bytes(decoded_sony_tag);
1154 newTagSize = 12;
1155 }
1156 break;
1157 case 0:
1158 newTagSize = 0;
1159 break;
1160 default:
1161 FATAL("Incorrect sector size");
1162 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_DATA_SIZE");
1164 }
1165
1166 if(newTagSize == 0)
1167 return aaruf_write_sector(context, sector_address, negative, data, sector_status, 512);
1168
1169 if(ctx->sector_subchannel == NULL)
1170 {
1171 ctx->sector_subchannel =
1172 calloc(1, newTagSize * (ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow));
1173
1174 if(ctx->sector_subchannel == NULL)
1175 {
1176 FATAL("Could not allocate memory for sector subchannel DDT");
1177
1178 free(newTag);
1179
1180 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
1182 }
1183 }
1184
1185 memcpy(ctx->sector_subchannel + sector_address * newTagSize, newTag, newTagSize);
1186 free(newTag);
1187
1188 return aaruf_write_sector(context, sector_address, negative, data, sector_status, 512);
1189 default:
1191 }
1192 default:
1193 TRACE("Exiting aaruf_write_sector() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
1195 }
1196
1197 // Fallback return when media type branch does not produce a value (satisfy non-void contract)
1199}
1200
1384{
1385 // Not a libaaruformat context
1386 if(ctx->magic != AARU_MAGIC) return AARUF_ERROR_NOT_AARUFORMAT;
1387
1388 // Check we are writing
1389 if(!ctx->is_writing) return AARUF_READ_ONLY;
1390
1392
1393 TRACE("Initializing CRC64 context");
1395 TRACE("Updating CRC64");
1398
1399 uint8_t lzma_properties[LZMA_PROPERTIES_LENGTH] = {0};
1400 uint8_t *cmp_buffer = NULL;
1401
1403 {
1404 case None:
1405 break;
1406 case Flac:
1407 cmp_buffer = malloc(ctx->current_block_header.length * 2);
1408 if(cmp_buffer == NULL)
1409 {
1410 FATAL("Could not allocate buffer for compressed data");
1412 }
1413 const uint32_t current_samples = ctx->current_block_offset * SAMPLES_PER_SECTOR;
1414 uint32_t flac_block_size = ctx->current_block_offset * SAMPLES_PER_SECTOR;
1415
1416 if(flac_block_size > MAX_FLAKE_BLOCK) flac_block_size = MAX_FLAKE_BLOCK;
1417 if(flac_block_size < MIN_FLAKE_BLOCK) flac_block_size = MIN_FLAKE_BLOCK;
1418
1419 const long remaining = current_samples % flac_block_size;
1420
1421 // Fill FLAC block
1422 if(remaining != 0)
1423 for(int r = 0; r < remaining * 4; r++) ctx->writing_buffer[ctx->writing_buffer_position + r] = 0;
1424
1426 cmp_buffer, ctx->current_block_header.length * 2, ctx->writing_buffer, ctx->current_block_header.length,
1427 flac_block_size, true, false, "hamming", 12, 15, true, false, 0, 8, "Aaru", 4);
1428
1430 {
1432 free(cmp_buffer);
1433 }
1434
1435 break;
1436 case Lzma:
1437 cmp_buffer = malloc(ctx->current_block_header.length * 2);
1438 if(cmp_buffer == NULL)
1439 {
1440 FATAL("Could not allocate buffer for compressed data");
1442 }
1443
1444 size_t dst_size = ctx->current_block_header.length * 2;
1445 size_t props_size = LZMA_PROPERTIES_LENGTH;
1446 aaruf_lzma_encode_buffer(cmp_buffer, &dst_size, ctx->writing_buffer, ctx->current_block_header.length,
1447 lzma_properties, &props_size, 9, ctx->lzma_dict_size, 4, 0, 2, 273, 8);
1448
1449 ctx->current_block_header.cmpLength = (uint32_t)dst_size;
1450
1452 {
1454 free(cmp_buffer);
1455 }
1456
1457 break;
1458 default:
1459 FATAL("Invalid compression type");
1461 }
1462
1464 {
1467 }
1468 else
1470
1472
1473 // Add to index
1474 TRACE("Adding block to index");
1475 IndexEntry index_entry;
1476 index_entry.blockType = DataBlock;
1477 index_entry.dataType = UserData;
1478 index_entry.offset = ctx->next_block_position;
1479
1480 utarray_push_back(ctx->index_entries, &index_entry);
1481 TRACE("Block added to index at offset %" PRIu64, index_entry.offset);
1482
1483 // Write block header to file
1484
1485 // Move to expected block position
1486 fseek(ctx->imageStream, ctx->next_block_position, SEEK_SET);
1487
1488 // Write block header
1489 if(fwrite(&ctx->current_block_header, sizeof(BlockHeader), 1, ctx->imageStream) != 1)
1491
1492 // Write block data
1494 fwrite(lzma_properties, LZMA_PROPERTIES_LENGTH, 1, ctx->imageStream) != 1)
1495 {
1496 free(cmp_buffer);
1498 }
1499
1501 {
1502 if(fwrite(ctx->writing_buffer, ctx->current_block_header.length, 1, ctx->imageStream) != 1)
1504 }
1505 else
1506 {
1507 if(fwrite(cmp_buffer, ctx->current_block_header.cmpLength, 1, ctx->imageStream) != 1)
1508 {
1509 free(cmp_buffer);
1511 }
1512
1513 free(cmp_buffer);
1514 }
1515
1516 // Update nextBlockPosition to point to the next available aligned position
1517 const uint64_t block_total_size = sizeof(BlockHeader) + ctx->current_block_header.cmpLength;
1518 const uint64_t alignment_mask = (1ULL << ctx->user_data_ddt_header.blockAlignmentShift) - 1;
1519 ctx->next_block_position = ctx->next_block_position + block_total_size + alignment_mask & ~alignment_mask;
1520 TRACE("Updated nextBlockPosition to %" PRIu64, ctx->next_block_position);
1521
1522 // Clear values
1523 free(ctx->writing_buffer);
1524 ctx->writing_buffer = NULL;
1525 ctx->current_block_offset = 0;
1526 memset(&ctx->current_block_header, 0, sizeof(BlockHeader));
1528 ctx->writing_buffer_position = 0;
1529
1530 return AARUF_STATUS_OK;
1531}
1532
1780int32_t aaruf_write_media_tag(void *context, const uint8_t *data, const int32_t type, const uint32_t length)
1781{
1782 TRACE("Entering aaruf_write_media_tag(%p, %p, %d, %d)", context, data, type, length);
1783
1784 // Check context is correct AaruFormat context
1785 if(context == NULL)
1786 {
1787 FATAL("Invalid context");
1788
1789 TRACE("Exiting aaruf_write_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
1791 }
1792
1793 aaruformat_context *ctx = context;
1794
1795 // Not a libaaruformat context
1796 if(ctx->magic != AARU_MAGIC)
1797 {
1798 FATAL("Invalid context");
1799
1800 TRACE("Exiting aaruf_write_media_tag() = AARUF_ERROR_NOT_AARUFORMAT");
1802 }
1803
1804 // Check we are writing
1805 if(!ctx->is_writing)
1806 {
1807 FATAL("Trying to write a read-only image");
1808
1809 TRACE("Exiting aaruf_write_media_tag() = AARUF_READ_ONLY");
1810 return AARUF_READ_ONLY;
1811 }
1812
1813 if(data == NULL || length == 0)
1814 {
1815 FATAL("Invalid data or length");
1817 }
1818
1819 uint8_t *new_data = malloc(length);
1820
1821 if(new_data == NULL)
1822 {
1823 FATAL("Could not allocate memory for media tag");
1825 }
1826 memcpy(new_data, data, length);
1827
1828 mediaTagEntry *media_tag = malloc(sizeof(mediaTagEntry));
1829 mediaTagEntry *old_media_tag = NULL;
1830
1831 if(media_tag == NULL)
1832 {
1833 TRACE("Cannot allocate memory for media tag entry.");
1834 free(new_data);
1836 }
1837
1838 memset(media_tag, 0, sizeof(mediaTagEntry));
1839
1840 media_tag->type = type;
1841 media_tag->data = new_data;
1842 media_tag->length = length;
1843
1844 HASH_REPLACE_INT(ctx->mediaTags, type, media_tag, old_media_tag);
1845
1846 if(old_media_tag != NULL)
1847 {
1848 TRACE("Replaced media tag with type %d", old_media_tag->type);
1849 free(old_media_tag->data);
1850 free(old_media_tag);
1851 old_media_tag = NULL;
1852 }
1853
1854 TRACE("Exiting aaruf_write_media_tag() = AARUF_STATUS_OK");
1855 return AARUF_STATUS_OK;
1856}
1857
2048int32_t aaruf_write_sector_tag(void *context, const uint64_t sector_address, const bool negative, const uint8_t *data,
2049 const size_t length, const int32_t tag)
2050{
2051 TRACE("Entering aaruf_write_sector_tag(%p, %" PRIu64 ", %d, %p, %zu, %d)", context, sector_address, negative, data,
2052 length, tag);
2053
2054 // Check context is correct AaruFormat context
2055 if(context == NULL)
2056 {
2057 FATAL("Invalid context");
2058
2059 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2061 }
2062
2063 aaruformat_context *ctx = context;
2064
2065 // Not a libaaruformat context
2066 if(ctx->magic != AARU_MAGIC)
2067 {
2068 FATAL("Invalid context");
2069
2070 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_AARUFORMAT");
2072 }
2073
2074 // Check we are writing
2075 if(!ctx->is_writing)
2076 {
2077 FATAL("Trying to write a read-only image");
2078
2079 TRACE("Exiting aaruf_write_sector_tag() = AARUF_READ_ONLY");
2080 return AARUF_READ_ONLY;
2081 }
2082
2083 if(negative && sector_address > ctx->user_data_ddt_header.negative - 1)
2084 {
2085 FATAL("Sector address out of bounds");
2086
2087 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2089 }
2090
2091 if(!negative && sector_address > ctx->image_info.Sectors + ctx->user_data_ddt_header.overflow - 1)
2092 {
2093 FATAL("Sector address out of bounds");
2094
2095 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_SECTOR_OUT_OF_BOUNDS");
2097 }
2098
2099 if(data == NULL || length == 0)
2100 {
2101 FATAL("Invalid data or length");
2103 }
2104
2105 uint64_t corrected_sector_address = sector_address;
2106
2107 // Calculate positive or negative sector
2108 if(negative)
2109 corrected_sector_address -= ctx->user_data_ddt_header.negative;
2110 else
2111 corrected_sector_address += ctx->user_data_ddt_header.negative;
2112
2113 const uint64_t total_sectors =
2115
2116 switch(tag)
2117 {
2118 case CdTrackFlags:
2120 {
2121 FATAL("Invalid media type for tag");
2122 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2124 }
2125
2126 if(length != 1)
2127 {
2128 FATAL("Incorrect tag size");
2129 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2131 }
2132
2133 for(int i = 0; i < ctx->tracks_header.entries; i++)
2134 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2135 {
2136 ctx->track_entries[i].flags = data[0];
2137 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2138 return AARUF_STATUS_OK;
2139 }
2140
2141 FATAL("Track not found");
2143 case CdTrackIsrc:
2145 {
2146 FATAL("Invalid media type for tag");
2147 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2149 }
2150
2151 if(length != 12)
2152 {
2153 FATAL("Incorrect tag size");
2154 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2156 }
2157
2158 for(int i = 0; i < ctx->tracks_header.entries; i++)
2159 if(sector_address >= ctx->track_entries[i].start && sector_address <= ctx->track_entries[i].end)
2160 {
2161 memcpy(ctx->track_entries[i].isrc, data, 12);
2162 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2163 return AARUF_STATUS_OK;
2164 }
2165
2166 FATAL("Track not found");
2168 case CdSectorSubchannel:
2170 {
2171 FATAL("Invalid media type for tag");
2172 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2174 }
2175
2176 if(length != 96)
2177 {
2178 FATAL("Incorrect tag size");
2179 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2181 }
2182
2183 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 96 * total_sectors);
2184
2185 if(ctx->sector_subchannel == NULL)
2186 {
2187 FATAL("Could not allocate memory for sector subchannel");
2188
2189 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2191 }
2192
2193 memcpy(ctx->sector_subchannel + corrected_sector_address * 96, data, 96);
2194 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2195 return AARUF_STATUS_OK;
2196 case DvdCmi:
2198 {
2199 FATAL("Invalid media type for tag");
2200 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2202 }
2203
2204 if(length != 1)
2205 {
2206 FATAL("Incorrect tag size");
2207 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2209 }
2210
2211 if(ctx->sector_cpr_mai == NULL) ctx->sector_cpr_mai = calloc(1, 6 * total_sectors);
2212
2213 if(ctx->sector_cpr_mai == NULL)
2214 {
2215 FATAL("Could not allocate memory for sector CPR/MAI");
2216
2217 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2219 }
2220
2221 memcpy(ctx->sector_cpr_mai + corrected_sector_address * 6, data, 1);
2222 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2223 return AARUF_STATUS_OK;
2226 {
2227 FATAL("Invalid media type for tag");
2228 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2230 }
2231
2232 if(length != 1)
2233 {
2234 FATAL("Incorrect tag size");
2235 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2237 }
2238
2239 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
2240
2241 if(ctx->sector_id == NULL)
2242 {
2243 FATAL("Could not allocate memory for sector ID");
2244
2245 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2247 }
2248
2249 memcpy(ctx->sector_id + corrected_sector_address * 4, data, 1);
2250 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2251 return AARUF_STATUS_OK;
2252 case DvdSectorNumber:
2254 {
2255 FATAL("Invalid media type for tag");
2256 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2258 }
2259
2260 if(length != 3)
2261 {
2262 FATAL("Incorrect tag size");
2263 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2265 }
2266
2267 if(ctx->sector_id == NULL) ctx->sector_id = calloc(1, 4 * total_sectors);
2268
2269 if(ctx->sector_id == NULL)
2270 {
2271 FATAL("Could not allocate memory for sector ID");
2272
2273 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2275 }
2276
2277 memcpy(ctx->sector_id + corrected_sector_address * 4 + 1, data, 3);
2278 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2279 return AARUF_STATUS_OK;
2280 case DvdSectorIed:
2282 {
2283 FATAL("Invalid media type for tag");
2284 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2286 }
2287
2288 if(length != 2)
2289 {
2290 FATAL("Incorrect tag size");
2291 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2293 }
2294
2295 if(ctx->sector_ied == NULL) ctx->sector_ied = calloc(1, 2 * total_sectors);
2296
2297 if(ctx->sector_ied == NULL)
2298 {
2299 FATAL("Could not allocate memory for sector IED");
2300
2301 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2303 }
2304
2305 memcpy(ctx->sector_ied + corrected_sector_address * 2, data, 2);
2306 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2307 return AARUF_STATUS_OK;
2308 case DvdSectorEdc:
2310 {
2311 FATAL("Invalid media type for tag");
2312 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2314 }
2315
2316 if(length != 4)
2317 {
2318 FATAL("Incorrect tag size");
2319 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2321 }
2322
2323 if(ctx->sector_edc == NULL) ctx->sector_edc = calloc(1, 4 * total_sectors);
2324
2325 if(ctx->sector_edc == NULL)
2326 {
2327 FATAL("Could not allocate memory for sector EDC");
2328
2329 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2331 }
2332
2333 memcpy(ctx->sector_edc + corrected_sector_address * 4, data, 4);
2334 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2335 return AARUF_STATUS_OK;
2338 {
2339 FATAL("Invalid media type for tag");
2340 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2342 }
2343
2344 if(length != 5)
2345 {
2346 FATAL("Incorrect tag size");
2347 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2349 }
2350
2351 if(ctx->sector_decrypted_title_key == NULL) ctx->sector_decrypted_title_key = calloc(1, 5 * total_sectors);
2352
2353 if(ctx->sector_decrypted_title_key == NULL)
2354 {
2355 FATAL("Could not allocate memory for sector decrypted title key");
2356
2357 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2359 }
2360
2361 memcpy(ctx->sector_decrypted_title_key + corrected_sector_address * 5, data, 5);
2362 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2363 return AARUF_STATUS_OK;
2364 case AppleSonyTag:
2366 {
2367 FATAL("Invalid media type for tag");
2368 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2370 }
2371
2372 if(length != 12)
2373 {
2374 FATAL("Incorrect tag size");
2375 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2377 }
2378
2379 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 12 * total_sectors);
2380
2381 if(ctx->sector_subchannel == NULL)
2382 {
2383 FATAL("Could not allocate memory for Apple Sony tag");
2384
2385 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2387 }
2388
2389 memcpy(ctx->sector_subchannel + corrected_sector_address * 12, data, 12);
2390 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2391 return AARUF_STATUS_OK;
2392 case AppleProfileTag:
2394 {
2395 FATAL("Invalid media type for tag");
2396 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2398 }
2399
2400 if(length != 20)
2401 {
2402 FATAL("Incorrect tag size");
2403 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2405 }
2406
2407 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 20 * total_sectors);
2408
2409 if(ctx->sector_subchannel == NULL)
2410 {
2411 FATAL("Could not allocate memory for Apple Profile tag");
2412
2413 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2415 }
2416
2417 memcpy(ctx->sector_subchannel + corrected_sector_address * 20, data, 20);
2418 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2419 return AARUF_STATUS_OK;
2420 case PriamDataTowerTag:
2422 {
2423 FATAL("Invalid media type for tag");
2424 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_MEDIA_TYPE");
2426 }
2427
2428 if(length != 24)
2429 {
2430 FATAL("Incorrect tag size");
2431 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_INCORRECT_DATA_SIZE");
2433 }
2434
2435 if(ctx->sector_subchannel == NULL) ctx->sector_subchannel = calloc(1, 24 * total_sectors);
2436
2437 if(ctx->sector_subchannel == NULL)
2438 {
2439 FATAL("Could not allocate memory for Priam Data Tower tag");
2440
2441 TRACE("Exiting aaruf_write_sector_tag() = AARUF_ERROR_NOT_ENOUGH_MEMORY");
2443 }
2444
2445 memcpy(ctx->sector_subchannel + corrected_sector_address * 24, data, 24);
2446 TRACE("Exiting aaruf_write_sector_tag() = AARUF_STATUS_OK");
2447 return AARUF_STATUS_OK;
2448 default:
2449 TRACE("Do not know how to write sector tag %d", tag);
2451 }
2452}
#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
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:543
void aaruf_md5_update(md5_ctx *ctx, const void *data, unsigned long size)
Definition md5.c:436
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:141
@ SectorStatusNotDumped
Sector(s) not yet acquired during image dumping.
Definition enums.h:230
@ SectorStatusMode2Form2NoCrc
Suffix matches MODE 2 Form 2 but CRC empty/missing.
Definition enums.h:236
@ SectorStatusMode1Correct
Valid MODE 1 data with regenerable suffix/prefix.
Definition enums.h:233
@ SectorStatusMode2Form2Ok
Suffix matches MODE 2 Form 2 with valid CRC.
Definition enums.h:235
@ SectorStatusErrored
Error during dumping; data may be incomplete or corrupt.
Definition enums.h:232
@ SectorStatusMode2Form1Ok
Suffix verified/regenerable for MODE 2 Form 1.
Definition enums.h:234
@ OpticalDisc
Purely optical discs.
Definition enums.h:218
@ BlockMedia
Media that is physically block-based or abstracted like that.
Definition enums.h:219
@ CdMode1
Compact Disc Mode 1 data track.
Definition enums.h:197
@ Data
Generic data track (not further specified).
Definition enums.h:196
@ CdMode2Form2
Compact Disc Mode 2 Form 2 data track.
Definition enums.h:200
@ Audio
Audio track.
Definition enums.h:195
@ CdMode2Form1
Compact Disc Mode 2 Form 1 data track.
Definition enums.h:199
@ CdMode2Formless
Compact Disc Mode 2 (formless) data track.
Definition enums.h:198
@ CdSectorSubchannel
Compact Disc subchannel data.
Definition enums.h:116
@ AppleProfileTag
Apple Profile (20‑byte) tag.
Definition enums.h:117
@ DvdSectorIed
DVD ID Error Detection Code (IED)
Definition enums.h:129
@ AppleSonyTag
Apple Sony (12‑byte) tag.
Definition enums.h:118
@ PriamDataTowerTag
Priam Data Tower (24‑byte) tag.
Definition enums.h:119
@ UserData
User (main) data.
Definition enums.h:46
@ DvdSectorEdc
DVD Error Detection Code (EDC)
Definition enums.h:130
@ 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
@ CdTrackFlags
Track flags (audio/data, copy permitted, pre-emphasis)
Definition aaru.h:907
@ DvdCmi
DVD Copyright Management Information (CSS)
Definition aaru.h:908
@ DvdSectorNumber
DVD sector number, 3 bytes.
Definition aaru.h:913
@ CdTrackIsrc
Track ISRC (12 ASCII chars, no terminator)
Definition aaru.h:905
@ DvdSectorInformation
DVD sector information, 1 bytes.
Definition aaru.h:912
@ DvdTitleKeyDecrypted
Decrypted DVD sector title key, 5 bytes.
Definition aaru.h:911
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:881
uint8_t MetadataMediaType
Media type for sidecar generation (internal archival use)
Definition aaru.h:882
uint64_t Sectors
Total count of addressable logical sectors/blocks.
Definition aaru.h:874
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 deduplicate
Storage deduplication active (duplicates coalesce).
Definition context.h:298
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:299
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
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
uint8_t * sector_prefix
Raw per-sector prefix (e.g., sync+header) uncorrected.
Definition context.h:199
uint64_t * sector_suffix_ddt2
CD sector suffix DDT V2.
Definition context.h:186
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
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
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
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
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
FILE * imageStream
Underlying FILE* stream (binary mode).
Definition context.h:176
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:297
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:1383
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:2048
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:1780
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:532