diff --git a/include/aaru.h b/include/aaru.h index 074c97c..7ca0336 100644 --- a/include/aaru.h +++ b/include/aaru.h @@ -26,484 +26,350 @@ #include -// TODO: Generate automatically from C# +/** \file aaru.h + * \brief Public high-level API types: media classifications, per-sector / per-media tag enums and image summary. + * + * This header provides: + * - \ref MediaType : exhaustive enumeration of recognized physical / logical media formats + * (disks, tapes, cards, optics). + * - \ref ImageInfo : summary metadata extracted from an opened image (sizes, creator, geometry, + * drive/media identity). + * - \ref SectorTagType : bit-addressable per-sector auxiliary data kinds (prefix/suffix/ECC/subchannel, etc.). + * - \ref MediaTagType : higher-level per-media metadata structures (TOCs, format information, IDs, + * inquiry pages, etc.). + * + * Value range conventions (MediaType): groups of contiguous numeric IDs are reserved for technology families; + * comments in the enum mark the ranges. This stable numeric mapping forms part of the external on-disk and + * API contract—do not renumber existing entries. New media types must be appended in an unused range or in an + * explicitly extended tail section to preserve backward compatibility. + * + * Thread safety: All types here are PODs / enumerations and are safe for concurrent read-only access. + * Encoding: All UTF-8 textual pointers inside \ref ImageInfo refer to NUL-terminated dynamically allocated + * buffers owned by the context that produced them (caller copies if persistence is required beyond context lifetime). + * + * See also: aaruformat/context.h for runtime context internals and metadata/dump structures. + */ -/** - * Contains an enumeration of all known types of media. +/** \addtogroup MediaTypes Media type classification + * Comprehensive list of supported physical / logical media. Grouped by numeric ranges in the enum. + * @{ */ +/** \enum MediaType + * \brief Enumerates every recognized media / cartridge / optical / tape / card / disk format. + * + * The numeric values are ABI- and file-format-stable. They are stored verbatim in serialized Aaru images + * and MUST NOT be changed. Only append new identifiers. When adding new values document them clearly. + * + * Typical usage patterns: + * - Switch over a MediaType to choose decoding / geometry heuristics. + * - Persist the numeric value in sidecar metadata (never stringify and parse unless necessary). + * - Provide user-facing localization by mapping the enum to translated labels externally. + * + * Ranges (do not reorder existing values): + * - 0–9: Generic / unknown basic categories. + * - 10–39: Compact Disc (CD) family (Red/Yellow/Green/Orange Books & variants). + * - 40–50: DVD family. + * - 51–59: HD-DVD family. + * - 60–69: Blu-ray family. + * - 70–79: Rare / niche optical formats. + * - 80–89: LaserDisc and derivatives. + * - 90–99: MiniDisc related. + * - 100–109: Plasmon UDO. + * - 110–169: Console / game optical & cartridge media (Sony / Sega / others). + * - 170–229: Additional console & early optical / cartridge variants. + * - 180–289: Floppy standards (Apple / IBM / NEC / ECMA / vendor-specific). + * - 290–309: Non-standard / extended PC floppy formats. + * - 310–359: Tape & removable disk (OnStream, AIT, Iomega, etc.). + * - 360–399: Audio/video and DEC / Exabyte families. + * - 400–699: Removable cards (PCMCIA, MemoryStick, SD, MMC), additional tape/storage families. + * - 700–739: DEC hard disks & Imation removable media. + * - 740–749: Niche video disc formats (VideoNow, etc.). + * - 750+: Extended / rare or future additions. + * + * Invariants / recommendations: + * - Treat Unknown (0) as a safe default; do not assume geometry. + * - Where possible, prefer feature probing (e.g. presence of TOC) instead of relying solely on the enum. + * - New client code should always have a default clause in switch statements to remain forward compatible. */ // NOLINTBEGIN(readability-identifier-naming) typedef enum { // Generics, types 0 to 9 - /** Unknown disk type */ - Unknown = 0, - /** Unknown magneto-optical */ - UnknownMO = 1, - /** Generic hard disk */ - GENERIC_HDD = 2, - /** Microdrive type hard disk */ - Microdrive = 3, - /** Zoned hard disk */ - Zone_HDD = 4, - /** USB flash drives */ - FlashDrive = 5, + Unknown = 0, ///< Unknown disk type + UnknownMO = 1, ///< Unknown magneto-optical + GENERIC_HDD = 2, ///< Generic hard disk + Microdrive = 3, ///< Microdrive type hard disk + Zone_HDD = 4, ///< Zoned hard disk + FlashDrive = 5, ///< USB flash drives // Generics, types 0 to 9 // Somewhat standard Compact Disc formats, types 10 to 39 - /** Any unknown or standard violating CD */ - CD = 10, - /** CD Digital Audio (Red Book) */ - CDDA = 11, - /** CD+G (Red Book) */ - CDG = 12, - /** CD+EG (Red Book) */ - CDEG = 13, - /** CD-i (Green Book) */ - CDI = 14, - /** CD-ROM (Yellow Book) */ - CDROM = 15, - /** CD-ROM XA (Yellow Book) */ - CDROMXA = 16, - /** CD+ (Blue Book) */ - CDPLUS = 17, - /** CD-MO (Orange Book) */ - CDMO = 18, - /** CD-Recordable (Orange Book) */ - CDR = 19, - /** CD-ReWritable (Orange Book) */ - CDRW = 20, - /** Mount-Rainier CD-RW */ - CDMRW = 21, - /** Video CD (White Book) */ - VCD = 22, - /** Super Video CD (White Book) */ - SVCD = 23, - /** Photo CD (Beige Book) */ - PCD = 24, - /** Super Audio CD (Scarlet Book) */ - SACD = 25, - /** Double-Density CD-ROM (Purple Book) */ - DDCD = 26, - /** DD CD-R (Purple Book) */ - DDCDR = 27, - /** DD CD-RW (Purple Book) */ - DDCDRW = 28, - /** DTS audio CD (non-standard) */ - DTSCD = 29, - /** CD-MIDI (Red Book) */ - CDMIDI = 30, - /** CD-Video (ISO/IEC 61104) */ - CDV = 31, - /** 120mm, Phase-Change, 1298496 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 */ - PD650 = 32, - /** 120mm, Write-Once, 1281856 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 */ - PD650_WORM = 33, /** - * CD-i Ready, contains a track before the first TOC track, in mode 2, and all TOC tracks are - * Audio. Subchannel marks track as audio pause. - */ - CDIREADY = 34, - FMTOWNS = 35, + CD = 10, ///< Any unknown or standard violating CD + CDDA = 11, ///< CD Digital Audio (Red Book) + CDG = 12, ///< CD+G (Red Book) + CDEG = 13, ///< CD+EG (Red Book) + CDI = 14, ///< CD-i (Green Book) + CDROM = 15, ///< CD-ROM (Yellow Book) + CDROMXA = 16, ///< CD-ROM XA (Yellow Book) + CDPLUS = 17, ///< CD+ (Blue Book) + CDMO = 18, ///< CD-MO (Orange Book) + CDR = 19, ///< CD-Recordable (Orange Book) + CDRW = 20, ///< CD-ReWritable (Orange Book) + CDMRW = 21, ///< Mount-Rainier CD-RW + VCD = 22, ///< Video CD (White Book) + SVCD = 23, ///< Super Video CD (White Book) + PCD = 24, ///< Photo CD (Beige Book) + SACD = 25, ///< Super Audio CD (Scarlet Book) + DDCD = 26, ///< Double-Density CD-ROM (Purple Book) + DDCDR = 27, ///< DD CD-R (Purple Book) + DDCDRW = 28, ///< DD CD-RW (Purple Book) + DTSCD = 29, ///< DTS audio CD (non-standard) + CDMIDI = 30, ///< CD-MIDI (Red Book) + CDV = 31, ///< CD-Video (ISO/IEC 61104) + PD650 = 32, ///< 120mm, Phase-Change, 1298496 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 + PD650_WORM = 33, ///< 120mm, Write-Once, 1281856 sectors, 512 bytes/sector, PD650, ECMA-240, ISO 15485 + CDIREADY = 34, ///< CD-i Ready, contains a track before the first TOC track, in mode 2, and all TOC tracks are + ///< Audio. Subchannel marks track as audio pause. + FMTOWNS = 35, ///< Fujitsu FM Towns bootable CD (mixed-mode proprietary extensions) // Somewhat standard Compact Disc formats, types 10 to 39 // Standard DVD formats, types 40 to 50 - /** DVD-ROM (applies to DVD Video and DVD Audio) */ - DVDROM = 40, - /** DVD-R */ - DVDR = 41, - /** DVD-RW */ - DVDRW = 42, - /** DVD+R */ - DVDPR = 43, - /** DVD+RW */ - DVDPRW = 44, - /** DVD+RW DL */ - DVDPRWDL = 45, - /** DVD-R DL */ - DVDRDL = 46, - /** DVD+R DL */ - DVDPRDL = 47, - /** DVD-RAM */ - DVDRAM = 48, - /** DVD-RW DL */ - DVDRWDL = 49, - /** DVD-Download */ - DVDDownload = 50, + DVDROM = 40, ///< DVD-ROM (applies to DVD Video and DVD Audio) + DVDR = 41, ///< DVD-R + DVDRW = 42, ///< DVD-RW + DVDPR = 43, ///< DVD+R + DVDPRW = 44, ///< DVD+RW + DVDPRWDL = 45, ///< DVD+RW DL + DVDRDL = 46, ///< DVD-R DL + DVDPRDL = 47, ///< DVD+R DL + DVDRAM = 48, ///< DVD-RAM + DVDRWDL = 49, ///< DVD-RW DL + DVDDownload = 50, ///< DVD-Download // Standard DVD formats, types 40 to 50 // Standard HD-DVD formats, types 51 to 59 - /** HD DVD-ROM (applies to HD DVD Video) */ - HDDVDROM = 51, - /** HD DVD-RAM */ - HDDVDRAM = 52, - /** HD DVD-R */ - HDDVDR = 53, - /** HD DVD-RW */ - HDDVDRW = 54, - /** HD DVD-R DL */ - HDDVDRDL = 55, - /** HD DVD-RW DL */ - HDDVDRWDL = 56, + HDDVDROM = 51, ///< HD DVD-ROM (applies to HD DVD Video) + HDDVDRAM = 52, ///< HD DVD-RAM + HDDVDR = 53, ///< HD DVD-R + HDDVDRW = 54, ///< HD DVD-RW + HDDVDRDL = 55, ///< HD DVD-R DL + HDDVDRWDL = 56, ///< HD DVD-RW DL // Standard HD-DVD formats, types 51 to 59 // Standard Blu-ray formats, types 60 to 69 - /** BD-ROM (and BD Video) */ - BDROM = 60, - /** BD-R */ - BDR = 61, - /** BD-RE */ - BDRE = 62, - /** BD-R XL */ - BDRXL = 63, - /** BD-RE XL */ - BDREXL = 64, + BDROM = 60, ///< BD-ROM (and BD Video) + BDR = 61, ///< BD-R + BDRE = 62, ///< BD-RE + BDRXL = 63, ///< BD-R XL + BDREXL = 64, ///< BD-RE XL // Standard Blu-ray formats, types 60 to 69 // Rare or uncommon optical standards, types 70 to 79 - /** Enhanced Versatile Disc */ - EVD = 70, - /** Forward Versatile Disc */ - FVD = 71, - /** Holographic Versatile Disc */ - HVD = 72, - /** China Blue High Definition */ - CBHD = 73, - /** High Definition Versatile Multilayer Disc */ - HDVMD = 74, - /** Versatile Compact Disc High Density */ - VCDHD = 75, - /** Stacked Volumetric Optical Disc */ - SVOD = 76, - /** Five Dimensional disc */ - FDDVD = 77, + EVD = 70, ///< Enhanced Versatile Disc + FVD = 71, ///< Forward Versatile Disc + HVD = 72, ///< Holographic Versatile Disc + CBHD = 73, ///< China Blue High Definition + HDVMD = 74, ///< High Definition Versatile Multilayer Disc + VCDHD = 75, ///< Versatile Compact Disc High Density + SVOD = 76, ///< Stacked Volumetric Optical Disc + FDDVD = 77, ///< Five Dimensional disc // Rare or uncommon optical standards, types 70 to 79 // LaserDisc based, types 80 to 89 - /** Pioneer LaserDisc */ - LD = 80, - /** Pioneer LaserDisc data */ - LDROM = 81, + LD = 80, ///< Pioneer LaserDisc + LDROM = 81, ///< Pioneer LaserDisc data LDROM2 = 82, LVROM = 83, MegaLD = 84, // LaserDisc based, types 80 to 89 // MiniDisc based, types 90 to 99 - /** Sony Hi-MD */ - HiMD = 90, - /** Sony MiniDisc */ - MD = 91, - MDData = 92, - MDData2 = 93, + HiMD = 90, ///< Sony Hi-MD + MD = 91, ///< Sony MiniDisc + MDData = 92, ///< MiniDisc DATA (HiFD style data-only variant) + MDData2 = 93, ///< High-capacity MiniDisc DATA 2 // MiniDisc based, types 90 to 99 // Plasmon UDO, types 100 to 109 - /** 5.25", Phase-Change, 1834348 sectors, 8192 bytes/sector, Ultra Density Optical, ECMA-350, ISO 17345 */ - UDO = 100, - /** 5.25", Phase-Change, 3669724 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 */ - UDO2 = 101, - /** 5.25", Write-Once, 3668759 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 */ - UDO2_WORM = 102, + UDO = 100, ///< 5.25", Phase-Change, 1834348 sectors, 8192 bytes/sector, Ultra Density Optical, ECMA-350, ISO 17345 + UDO2 = + 101, ///< 5.25", Phase-Change, 3669724 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 + UDO2_WORM = + 102, ///< 5.25", Write-Once, 3668759 sectors, 8192 bytes/sector, Ultra Density Optical 2, ECMA-380, ISO 11976 // Plasmon UDO, types 100 to 109 // Sony game media, types 110 to 129 - PlayStationMemoryCard = 110, - PlayStationMemoryCard2 = 111, - /** Sony PlayStation game CD */ - PS1CD = 112, - /** Sony PlayStation 2 game CD */ - PS2CD = 113, - /** Sony PlayStation 2 game DVD */ - PS2DVD = 114, - /** Sony PlayStation 3 game DVD */ - PS3DVD = 115, - /** Sony PlayStation 3 game Blu-ray */ - PS3BD = 116, - /** Sony PlayStation 4 game Blu-ray */ - PS4BD = 117, - /** Sony PlayStation Portable Universal Media Disc (ECMA-365) */ - UMD = 118, - PlayStationVitaGameCard = 119, + PlayStationMemoryCard = 110, ///< Sony PlayStation (PS1) memory card (128 KiB, 8 KB blocks) + PlayStationMemoryCard2 = 111, ///< Sony PlayStation 2 memory card (MagicGate, 8 MiB) + PS1CD = 112, ///< Sony PlayStation game CD + PS2CD = 113, ///< Sony PlayStation 2 game CD + PS2DVD = 114, ///< Sony PlayStation 2 game DVD + PS3DVD = 115, ///< Sony PlayStation 3 game DVD + PS3BD = 116, ///< Sony PlayStation 3 game Blu-ray + PS4BD = 117, ///< Sony PlayStation 4 game Blu-ray + UMD = 118, ///< Sony PlayStation Portable Universal Media Disc (ECMA-365) + PlayStationVitaGameCard = 119, ///< PS Vita NV memory card (proprietary flash) // Sony game media, types 110 to 129 // Microsoft game media, types 130 to 149 - /** Microsoft X-box Game Disc */ - XGD = 130, - /** Microsoft X-box 360 Game Disc */ - XGD2 = 131, - /** Microsoft X-box 360 Game Disc */ - XGD3 = 132, - /** Microsoft X-box One Game Disc */ - XGD4 = 133, + XGD = 130, ///< Microsoft X-box Game Disc + XGD2 = 131, ///< Microsoft X-box 360 Game Disc + XGD3 = 132, ///< Microsoft X-box 360 Game Disc + XGD4 = 133, ///< Microsoft X-box One Game Disc // Microsoft game media, types 130 to 149 // Sega game media, types 150 to 169 - /** Sega MegaCD */ - MEGACD = 150, - /** Sega Saturn disc */ - SATURNCD = 151, - /** Sega/Yamaha Gigabyte Disc */ - GDROM = 152, - /** Sega/Yamaha recordable Gigabyte Disc */ - GDR = 153, - SegaCard = 154, - MilCD = 155, + MEGACD = 150, ///< Sega MegaCD + SATURNCD = 151, ///< Sega Saturn disc + GDROM = 152, ///< Sega/Yamaha Gigabyte Disc + GDR = 153, ///< Sega/Yamaha recordable Gigabyte Disc + SegaCard = 154, ///< Sega My Card / Sega Card (SG-1000 / Mark III) + MilCD = 155, ///< Sega Dreamcast MIL-CD enhanced multimedia disc // Sega game media, types 150 to 169 // Other game media, types 170 to 179 - /** PC-Engine / TurboGrafx cartridge */ - HuCard = 170, - /** PC-Engine / TurboGrafx CD */ - SuperCDROM2 = 171, - /** Atari Jaguar CD */ - JaguarCD = 172, - /** 3DO CD */ - ThreeDO = 173, - /** NEC PC-FX */ - PCFX = 174, - /** NEO-GEO CD */ - NeoGeoCD = 175, - /** Commodore CDTV */ - CDTV = 176, - /** Amiga CD32 */ - CD32 = 177, - /** Nuon (DVD based videogame console) */ - Nuon = 178, - /** Bandai Playdia */ - Playdia = 179, + HuCard = 170, ///< PC-Engine / TurboGrafx cartridge + SuperCDROM2 = 171, ///< PC-Engine / TurboGrafx CD + JaguarCD = 172, ///< Atari Jaguar CD + ThreeDO = 173, ///< 3DO CD + PCFX = 174, ///< NEC PC-FX + NeoGeoCD = 175, ///< NEO-GEO CD + CDTV = 176, ///< Commodore CDTV + CD32 = 177, ///< Amiga CD32 + Nuon = 178, ///< Nuon (DVD based videogame console) + Playdia = 179, ///< Bandai Playdia // Other game media, types 170 to 179 // Apple standard floppy format, types 180 to 189 - /** 5.25", SS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR */ - Apple32SS = 180, - /** 5.25", DS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR */ - Apple32DS = 181, - /** 5.25", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR */ - Apple33SS = 182, - /** 5.25", DS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR */ - Apple33DS = 183, - /** 3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR */ - AppleSonySS = 184, - /** 3.5", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR */ - AppleSonyDS = 185, - /** 5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy */ - AppleFileWare = 186, + Apple32SS = 180, ///< 5.25", SS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR + Apple32DS = 181, ///< 5.25", DS, DD, 35 tracks, 13 spt, 256 bytes/sector, GCR + Apple33SS = 182, ///< 5.25", SS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR + Apple33DS = 183, ///< 5.25", DS, DD, 35 tracks, 16 spt, 256 bytes/sector, GCR + AppleSonySS = 184, ///< 3.5", SS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR + AppleSonyDS = 185, ///< 3.5", DS, DD, 80 tracks, 8 to 12 spt, 512 bytes/sector, GCR + AppleFileWare = 186, ///< 5.25", DS, ?D, ?? tracks, ?? spt, 512 bytes/sector, GCR, opposite side heads, aka Twiggy // Apple standard floppy format // IBM/Microsoft PC floppy formats, types 190 to 209 - /** 5.25", SS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM */ - DOS_525_SS_DD_8 = 190, - /** 5.25", SS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM */ - DOS_525_SS_DD_9 = 191, - /** 5.25", DS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM */ - DOS_525_DS_DD_8 = 192, - /** 5.25", DS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM */ - DOS_525_DS_DD_9 = 193, - /** 5.25", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM */ - DOS_525_HD = 194, - /** 3.5", SS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM */ - DOS_35_SS_DD_8 = 195, - /** 3.5", SS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM */ - DOS_35_SS_DD_9 = 196, - /** 3.5", DS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM */ - DOS_35_DS_DD_8 = 197, - /** 3.5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM */ - DOS_35_DS_DD_9 = 198, - /** 3.5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM */ - DOS_35_HD = 199, - /** 3.5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM */ - DOS_35_ED = 200, - /** 3.5", DS, HD, 80 tracks, 21 spt, 512 bytes/sector, MFM */ - DMF = 201, - /** 3.5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM */ - DMF_82 = 202, /** - * 5.25", DS, HD, 80 tracks, ? spt, ??? + ??? + ??? bytes/sector, MFM track 0 = ??15 sectors, 512 - * bytes/sector, falsified to DOS as 19 spt, 512 bps - */ - XDF_525 = 203, /** - * 3.5", DS, HD, 80 tracks, 4 spt, 8192 + 2048 + 1024 + 512 bytes/sector, MFM track 0 = 19 - * sectors, 512 bytes/sector, falsified to DOS as 23 spt, 512 bps - */ - XDF_35 = 204, + DOS_525_SS_DD_8 = 190, ///< 5.25", SS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM + DOS_525_SS_DD_9 = 191, ///< 5.25", SS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM + DOS_525_DS_DD_8 = 192, ///< 5.25", DS, DD, 40 tracks, 8 spt, 512 bytes/sector, MFM + DOS_525_DS_DD_9 = 193, ///< 5.25", DS, DD, 40 tracks, 9 spt, 512 bytes/sector, MFM + DOS_525_HD = 194, ///< 5.25", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM + DOS_35_SS_DD_8 = 195, ///< 3.5", SS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM + DOS_35_SS_DD_9 = 196, ///< 3.5", SS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + DOS_35_DS_DD_8 = 197, ///< 3.5", DS, DD, 80 tracks, 8 spt, 512 bytes/sector, MFM + DOS_35_DS_DD_9 = 198, ///< 3.5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + DOS_35_HD = 199, ///< 3.5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM + DOS_35_ED = 200, ///< 3.5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM + DMF = 201, ///< 3.5", DS, HD, 80 tracks, 21 spt, 512 bytes/sector, MFM + DMF_82 = 202, ///< 3.5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM + XDF_525 = 203, ///< 5.25", DS, HD, 80 tracks, ? spt, ??? + ??? + ??? bytes/sector, MFM track 0 = ??15 sectors, 512 + ///< bytes/sector, falsified to DOS as 19 spt, 512 bps + XDF_35 = 204, ///< 3.5", DS, HD, 80 tracks, 4 spt, 8192 + 2048 + 1024 + 512 bytes/sector, MFM track 0 = 19 sectors, + ///< 512 bytes/sector, falsified to DOS as 23 spt, 512 bps // IBM/Microsoft PC standard floppy formats, types 190 to 209 // IBM standard floppy formats, types 210 to 219 - /** 8", SS, SD, 32 tracks, 8 spt, 319 bytes/sector, FM */ - IBM23FD = 210, - /** 8", SS, SD, 73 tracks, 26 spt, 128 bytes/sector, FM */ - IBM33FD_128 = 211, - /** 8", SS, SD, 74 tracks, 15 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector */ - IBM33FD_256 = 212, - /** 8", SS, SD, 74 tracks, 8 spt, 512 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector */ - IBM33FD_512 = 213, - /** 8", DS, SD, 74 tracks, 26 spt, 128 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector */ - IBM43FD_128 = 214, - /** 8", DS, SD, 74 tracks, 26 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector */ - IBM43FD_256 = 215, /** - * 8", DS, DD, 74 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - IBM53FD_256 = 216, /** - * 8", DS, DD, 74 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - IBM53FD_512 = 217, /** - * 8", DS, DD, 74 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - IBM53FD_1024 = 218, + IBM23FD = 210, ///< 8", SS, SD, 32 tracks, 8 spt, 319 bytes/sector, FM + IBM33FD_128 = 211, ///< 8", SS, SD, 73 tracks, 26 spt, 128 bytes/sector, FM + IBM33FD_256 = 212, ///< 8", SS, SD, 74 tracks, 15 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM33FD_512 = 213, ///< 8", SS, SD, 74 tracks, 8 spt, 512 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM43FD_128 = 214, ///< 8", DS, SD, 74 tracks, 26 spt, 128 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM43FD_256 = 215, ///< 8", DS, SD, 74 tracks, 26 spt, 256 bytes/sector, FM, track 0 = 26 sectors, 128 bytes/sector + IBM53FD_256 = 216, ///< 8", DS, DD, 74 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + IBM53FD_512 = 217, ///< 8", DS, DD, 74 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + IBM53FD_1024 = 218, ///< 8", DS, DD, 74 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector // IBM standard floppy formats, types 210 to 219 // DEC standard floppy formats, types 220 to 229 - /** 8", SS, DD, 77 tracks, 26 spt, 128 bytes/sector, FM */ - RX01 = 220, - /** 8", SS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM */ - RX02 = 221, - /** 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM */ - RX03 = 222, - /** 5.25", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM */ - RX50 = 223, + RX01 = 220, ///< 8", SS, DD, 77 tracks, 26 spt, 128 bytes/sector, FM + RX02 = 221, ///< 8", SS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM + RX03 = 222, ///< 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM/MFM + RX50 = 223, ///< 5.25", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM // DEC standard floppy formats, types 220 to 229 // Acorn standard floppy formats, types 230 to 239 - /** 5,25", SS, SD, 40 tracks, 10 spt, 256 bytes/sector, FM */ - ACORN_525_SS_SD_40 = 230, - /** 5,25", SS, SD, 80 tracks, 10 spt, 256 bytes/sector, FM */ - ACORN_525_SS_SD_80 = 231, - /** 5,25", SS, DD, 40 tracks, 16 spt, 256 bytes/sector, MFM */ - ACORN_525_SS_DD_40 = 232, - /** 5,25", SS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM */ - ACORN_525_SS_DD_80 = 233, - /** 5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM */ - ACORN_525_DS_DD = 234, - /** 3,5", DS, DD, 80 tracks, 5 spt, 1024 bytes/sector, MFM */ - ACORN_35_DS_DD = 235, - /** 3,5", DS, HD, 80 tracks, 10 spt, 1024 bytes/sector, MFM */ - ACORN_35_DS_HD = 236, + ACORN_525_SS_SD_40 = 230, ///< 5,25", SS, SD, 40 tracks, 10 spt, 256 bytes/sector, FM + ACORN_525_SS_SD_80 = 231, ///< 5,25", SS, SD, 80 tracks, 10 spt, 256 bytes/sector, FM + ACORN_525_SS_DD_40 = 232, ///< 5,25", SS, DD, 40 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_SS_DD_80 = 233, ///< 5,25", SS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_525_DS_DD = 234, ///< 5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, MFM + ACORN_35_DS_DD = 235, ///< 3,5", DS, DD, 80 tracks, 5 spt, 1024 bytes/sector, MFM + ACORN_35_DS_HD = 236, ///< 3,5", DS, HD, 80 tracks, 10 spt, 1024 bytes/sector, MFM // Acorn standard floppy formats, types 230 to 239 // Atari standard floppy formats, types 240 to 249 - /** 5,25", SS, SD, 40 tracks, 18 spt, 128 bytes/sector, FM */ - ATARI_525_SD = 240, - /** 5,25", SS, ED, 40 tracks, 26 spt, 128 bytes/sector, MFM */ - ATARI_525_ED = 241, - /** 5,25", SS, DD, 40 tracks, 18 spt, 256 bytes/sector, MFM */ - ATARI_525_DD = 242, - /** 3,5", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM */ - ATARI_35_SS_DD = 243, - /** 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM */ - ATARI_35_DS_DD = 244, - /** 3,5", SS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM */ - ATARI_35_SS_DD_11 = 245, - /** 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM */ - ATARI_35_DS_DD_11 = 246, + ATARI_525_SD = 240, ///< 5,25", SS, SD, 40 tracks, 18 spt, 128 bytes/sector, FM + ATARI_525_ED = 241, ///< 5,25", SS, ED, 40 tracks, 26 spt, 128 bytes/sector, MFM + ATARI_525_DD = 242, ///< 5,25", SS, DD, 40 tracks, 18 spt, 256 bytes/sector, MFM + ATARI_35_SS_DD = 243, ///< 3,5", SS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + ATARI_35_DS_DD = 244, ///< 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM + ATARI_35_SS_DD_11 = 245, ///< 3,5", SS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM + ATARI_35_DS_DD_11 = 246, ///< 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM // Atari standard floppy formats, types 240 to 249 // Commodore standard floppy formats, types 250 to 259 - /** 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM (1581) */ - CBM_35_DD = 250, - /** 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM (Amiga) */ - CBM_AMIGA_35_DD = 251, - /** 3,5", DS, HD, 80 tracks, 22 spt, 512 bytes/sector, MFM (Amiga) */ - CBM_AMIGA_35_HD = 252, - /** 5,25", SS, DD, 35 tracks, GCR */ - CBM_1540 = 253, - /** 5,25", SS, DD, 40 tracks, GCR */ - CBM_1540_Ext = 254, - /** 5,25", DS, DD, 35 tracks, GCR */ - CBM_1571 = 255, + CBM_35_DD = 250, ///< 3,5", DS, DD, 80 tracks, 10 spt, 512 bytes/sector, MFM (1581) + CBM_AMIGA_35_DD = 251, ///< 3,5", DS, DD, 80 tracks, 11 spt, 512 bytes/sector, MFM (Amiga) + CBM_AMIGA_35_HD = 252, ///< 3,5", DS, HD, 80 tracks, 22 spt, 512 bytes/sector, MFM (Amiga) + CBM_1540 = 253, ///< 5,25", SS, DD, 35 tracks, GCR + CBM_1540_Ext = 254, ///< 5,25", SS, DD, 40 tracks, GCR + CBM_1571 = 255, ///< 5,25", DS, DD, 35 tracks, GCR // Commodore standard floppy formats, types 250 to 259 // NEC/SHARP standard floppy formats, types 260 to 269 - /** 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM */ - NEC_8_SD = 260, - /** 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM */ - NEC_8_DD = 261, - /** 5.25", SS, SD, 80 tracks, 16 spt, 256 bytes/sector, FM */ - NEC_525_SS = 262, - /** 5.25", DS, SD, 80 tracks, 16 spt, 256 bytes/sector, MFM */ - NEC_525_DS = 263, - /** 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM */ - NEC_525_HD = 264, - /** 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM, aka mode 3 */ - NEC_35_HD_8 = 265, - /** 3,5", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM */ - NEC_35_HD_15 = 266, - /** 3,5", DS, TD, 240 tracks, 38 spt, 512 bytes/sector, MFM */ - NEC_35_TD = 267, - /** 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM */ - SHARP_525 = NEC_525_HD, - /** 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM */ - SHARP_525_9 = 268, - /** 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM */ - SHARP_35 = NEC_35_HD_8, - /** 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM */ - SHARP_35_9 = 269, + NEC_8_SD = 260, ///< 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + NEC_8_DD = 261, ///< 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM + NEC_525_SS = 262, ///< 5.25", SS, SD, 80 tracks, 16 spt, 256 bytes/sector, FM + NEC_525_DS = 263, ///< 5.25", DS, SD, 80 tracks, 16 spt, 256 bytes/sector, MFM + NEC_525_HD = 264, ///< 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + NEC_35_HD_8 = 265, ///< 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM, aka mode 3 + NEC_35_HD_15 = 266, ///< 3,5", DS, HD, 80 tracks, 15 spt, 512 bytes/sector, MFM + NEC_35_TD = 267, ///< 3,5", DS, TD, 240 tracks, 38 spt, 512 bytes/sector, MFM + SHARP_525 = NEC_525_HD, ///< 5,25", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM + SHARP_525_9 = 268, ///< 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM + SHARP_35 = NEC_35_HD_8, ///< 3,5", DS, HD, 77 tracks, 8 spt, 1024 bytes/sector, MFM, aka mode 3 + SHARP_35_9 = 269, ///< 3,5", DS, HD, 80 tracks, 9 spt, 1024 bytes/sector, MFM // NEC/SHARP standard floppy formats, types 260 to 269 // ECMA floppy standards, types 270 to 289 - /** - * 5,25", DS, DD, 80 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 bytes/sector, track - * 0 side 1 = 26 sectors, 256 bytes/sector - */ - ECMA_99_8 = 270, /** - * 5,25", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - ECMA_99_15 = 271, /** - * 5,25", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - ECMA_99_26 = 272, - /** 3,5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM */ - ECMA_100 = DOS_35_DS_DD_9, - /** 3,5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM */ - ECMA_125 = DOS_35_HD, - /** 3,5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM */ - ECMA_147 = DOS_35_ED, - /** 8", SS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM */ - ECMA_54 = 273, - /** 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM */ - ECMA_59 = 274, - /** 5,25", SS, DD, 35 tracks, 9 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector */ - ECMA_66 = 275, /** - * 8", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - ECMA_69_8 = 276, /** - * 8", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - ECMA_69_15 = 277, /** - * 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 - * bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector - */ - ECMA_69_26 = 278, /** - * 5,25", DS, DD, 40 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 - * bytes/sector, track 0 side 1 = 16 sectors, 256 bytes/sector - */ - ECMA_70 = 279, /** - * 5,25", DS, DD, 80 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 - * bytes/sector, track 0 side 1 = 16 sectors, 256 bytes/sector - */ + ECMA_99_8 = 270, ///< 5,25", DS, DD, 80 tracks, 8 spt, 1024 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + ECMA_99_15 = 271, ///< 5,25", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + ECMA_99_26 = 272, ///< 5,25", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, MFM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + ECMA_100 = DOS_35_DS_DD_9, ///< 3,5", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, MFM + ECMA_125 = DOS_35_HD, ///< 3,5", DS, HD, 80 tracks, 18 spt, 512 bytes/sector, MFM + ECMA_147 = DOS_35_ED, ///< 3,5", DS, ED, 80 tracks, 36 spt, 512 bytes/sector, MFM + ECMA_54 = 273, ///< 8", SS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + ECMA_59 = 274, ///< 8", DS, SD, 77 tracks, 26 spt, 128 bytes/sector, FM + ECMA_66 = + 275, ///< 5,25", SS, DD, 35 tracks, 9 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 bytes/sector + ECMA_69_8 = 276, ///< 8", DS, DD, 77 tracks, 8 spt, 1024 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + ECMA_69_15 = 277, ///< 8", DS, DD, 77 tracks, 15 spt, 512 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + ECMA_69_26 = 278, ///< 8", DS, DD, 77 tracks, 26 spt, 256 bytes/sector, FM, track 0 side 0 = 26 sectors, 128 + ///< bytes/sector, track 0 side 1 = 26 sectors, 256 bytes/sector + ECMA_70 = 279, ///< 5,25", DS, DD, 40 tracks, 16 spt, 256 bytes/sector, FM, track 0 side 0 = 16 sectors, 128 + ///< bytes/sector, track 0 side 1 = 16 sectors, 256 bytes/sector ECMA_78 = 280, - /** 5,25", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, FM */ - ECMA_78_2 = 281, + ECMA_78_2 = 281, ///< 5,25", DS, DD, 80 tracks, 9 spt, 512 bytes/sector, FM // ECMA floppy standards, types 270 to 289 // Non-standard PC formats (FDFORMAT, 2M, etc), types 290 to 308 - /** 5,25", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM */ - FDFORMAT_525_DD = 290, - /** 5,25", DS, HD, 82 tracks, 17 spt, 512 bytes/sector, MFM */ - FDFORMAT_525_HD = 291, - /** 3,5", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM */ - FDFORMAT_35_DD = 292, - /** 3,5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM */ - FDFORMAT_35_HD = 293, + FDFORMAT_525_DD = 290, ///< 5,25", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM + FDFORMAT_525_HD = 291, ///< 5,25", DS, HD, 82 tracks, 17 spt, 512 bytes/sector, MFM + FDFORMAT_35_DD = 292, ///< 3,5", DS, DD, 82 tracks, 10 spt, 512 bytes/sector, MFM + FDFORMAT_35_HD = 293, ///< 3,5", DS, HD, 82 tracks, 21 spt, 512 bytes/sector, MFM // Non-standard PC formats (FDFORMAT, 2M, etc), types 290 to 308 // Apricot ACT standard floppy formats, type 309 - /** 3.5", DS, DD, 70 tracks, 9 spt, 512 bytes/sector, MFM */ - Apricot_35 = 309, + Apricot_35 = 309, ///< 3.5", DS, DD, 70 tracks, 9 spt, 512 bytes/sector, MFM // Apricot ACT standard floppy formats, type 309 // OnStream ADR, types 310 to 319 @@ -548,12 +414,9 @@ typedef enum CompactCassette = 360, Data8 = 361, MiniDV = 362, - /** D/CAS-25: Digital data on Compact Cassette form factor, special magnetic media, 9-track */ - Dcas25 = 363, - /** D/CAS-85: Digital data on Compact Cassette form factor, special magnetic media, 17-track */ - Dcas85 = 364, - /** D/CAS-103: Digital data on Compact Cassette form factor, special magnetic media, 21-track */ - Dcas103 = 365, + Dcas25 = 363, ///< D/CAS-25: Digital data on Compact Cassette form factor, special magnetic media, 9-track + Dcas85 = 364, ///< D/CAS-85: Digital data on Compact Cassette form factor, special magnetic media, 17-track + Dcas103 = 365, ///< D/CAS-103: Digital data on Compact Cassette form factor, special magnetic media, 21-track // Audio media, types 360 to 369 // CompactFlash Association, types 370 to 379 @@ -633,25 +496,22 @@ typedef enum // SyQuest, types 430 to 449 // Nintendo, types 450 to 469 - FamicomGamePak = 450, - GameBoyAdvanceGamePak = 451, - GameBoyGamePak = 452, - /** Nintendo GameCube Optical Disc */ - GOD = 453, + FamicomGamePak = 450, ///< Nintendo Famicom cartridge + GameBoyAdvanceGamePak = 451, ///< Nintendo Game Boy Advance cartridge + GameBoyGamePak = 452, ///< Nintendo Game Boy / Color cartridge + GOD = 453, ///< Nintendo GameCube Optical Disc N64DD = 454, - N64GamePak = 455, - NESGamePak = 456, - Nintendo3DSGameCard = 457, - NintendoDiskCard = 458, - NintendoDSGameCard = 459, - NintendoDSiGameCard = 460, - SNESGamePak = 461, - SNESGamePakUS = 462, - /** Nintendo Wii Optical Disc */ - WOD = 463, - /** Nintendo Wii U Optical Disc */ - WUOD = 464, - SwitchGameCard = 465, + N64GamePak = 455, ///< Nintendo 64 cartridge + NESGamePak = 456, ///< Nintendo NES cartridge + Nintendo3DSGameCard = 457, ///< Nintendo 3DS ROM card + NintendoDiskCard = 458, ///< Famicom Disk System disk + NintendoDSGameCard = 459, ///< Nintendo DS ROM card + NintendoDSiGameCard = 460, ///< Nintendo DSi enhanced ROM card + SNESGamePak = 461, ///< Nintendo SNES (PAL/JPN) cartridge + SNESGamePakUS = 462, ///< Nintendo SNES (US) cartridge (different shell) + WOD = 463, ///< Nintendo Wii Optical Disc + WUOD = 464, ///< Nintendo Wii U Optical Disc + SwitchGameCard = 465, ///< Nintendo Switch Game Card (NV flash) // Nintendo, types 450 to 469 // IBM Tapes, types 470 to 479 @@ -686,17 +546,17 @@ typedef enum // MemoryStick, types 510 to 519 // SecureDigital, types 520 to 529 - microSD = 520, - miniSD = 521, - SecureDigital = 522, + microSD = 520, ///< microSD / microSDHC / microSDXC card + miniSD = 521, ///< miniSD card + SecureDigital = 522, ///< Full-size SD / SDHC / SDXC card // SecureDigital, types 520 to 529 // MultiMediaCard, types 530 to 539 - MMC = 530, - MMCmicro = 531, - RSMMC = 532, - MMCplus = 533, - MMCmobile = 534, + MMC = 530, ///< MultiMediaCard (legacy) + MMCmicro = 531, ///< MMCmicro (RS-MMC form) + RSMMC = 532, ///< Reduced Size MMC + MMCplus = 533, ///< MMCplus (high speed) + MMCmobile = 534, ///< MMCmobile (dual voltage) // MultiMediaCard, types 530 to 539 // SLR, types 540 to 569 @@ -773,63 +633,37 @@ typedef enum // VXA, types 620 to 629 // Magneto-optical, types 630 to 659 - /** 5,25", M.O., ??? sectors, 1024 bytes/sector, ECMA-153, ISO 11560 */ - ECMA_153 = 630, - /** 5,25", M.O., ??? sectors, 512 bytes/sector, ECMA-153, ISO 11560 */ - ECMA_153_512 = 631, - /** 3,5", M.O., 249850 sectors, 512 bytes/sector, ECMA-154, ISO 10090 */ - ECMA_154 = 632, - /** 5,25", M.O., 904995 sectors, 512 bytes/sector, ECMA-183, ISO 13481 */ - ECMA_183_512 = 633, - /** 5,25", M.O., 498526 sectors, 1024 bytes/sector, ECMA-183, ISO 13481 */ - ECMA_183 = 634, - /** 5,25", M.O., 1128772 or 1163337 sectors, 512 bytes/sector, ECMA-183, ISO 13549 */ - ECMA_184_512 = 635, - /** 5,25", M.O., 603466 or 637041 sectors, 1024 bytes/sector, ECMA-183, ISO 13549 */ - ECMA_184 = 636, - /** 300mm, M.O., ??? sectors, 1024 bytes/sector, ECMA-189, ISO 13614 */ - ECMA_189 = 637, - /** 300mm, M.O., ??? sectors, 1024 bytes/sector, ECMA-190, ISO 13403 */ - ECMA_190 = 638, - /** 5,25", M.O., 936921 or 948770 sectors, 1024 bytes/sector, ECMA-195, ISO 13842 */ - ECMA_195 = 639, - /** 5,25", M.O., 1644581 or 1647371 sectors, 512 bytes/sector, ECMA-195, ISO 13842 */ - ECMA_195_512 = 640, - /** 3,5", M.O., 446325 sectors, 512 bytes/sector, ECMA-201, ISO 13963 */ - ECMA_201 = 641, - /** 3,5", M.O., 429975 sectors, 512 bytes/sector, embossed, ISO 13963 */ - ECMA_201_ROM = 642, - /** 3,5", M.O., 371371 sectors, 1024 bytes/sector, ECMA-223 */ - ECMA_223 = 643, - /** 3,5", M.O., 694929 sectors, 512 bytes/sector, ECMA-223 */ - ECMA_223_512 = 644, - /** 5,25", M.O., 1244621 sectors, 1024 bytes/sector, ECMA-238, ISO 15486 */ - ECMA_238 = 645, - /** 3,5", M.O., 318988, 320332 or 321100 sectors, 2048 bytes/sector, ECMA-239, ISO 15498 */ - ECMA_239 = 646, - /** 356mm, M.O., 14476734 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 */ - ECMA_260 = 647, - /** 356mm, M.O., 24445990 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 */ - ECMA_260_Double = 648, - /** 5,25", M.O., 1128134 sectors, 2048 bytes/sector, ECMA-280, ISO 18093 */ - ECMA_280 = 649, - /** 300mm, M.O., 7355716 sectors, 2048 bytes/sector, ECMA-317, ISO 20162 */ - ECMA_317 = 650, - /** 5,25", M.O., 1095840 sectors, 4096 bytes/sector, ECMA-322, ISO 22092 */ - ECMA_322 = 651, - /** 5,25", M.O., 2043664 sectors, 2048 bytes/sector, ECMA-322, ISO 22092 */ - ECMA_322_2k = 652, - /** 3,5", M.O., 605846 sectors, 2048 bytes/sector, Cherry Book, GigaMo, ECMA-351, ISO 17346 */ - GigaMo = 653, - /** 3,5", M.O., 1063146 sectors, 2048 bytes/sector, Cherry Book 2, GigaMo 2, ECMA-353, ISO 22533 */ - GigaMo2 = 654, + ECMA_153 = 630, ///< 5,25", M.O., ??? sectors, 1024 bytes/sector, ECMA-153, ISO 11560 + ECMA_153_512 = 631, ///< 5,25", M.O., ??? sectors, 512 bytes/sector, ECMA-153, ISO 11560 + ECMA_154 = 632, ///< 3,5", M.O., 249850 sectors, 512 bytes/sector, ECMA-154, ISO 10090 + ECMA_183_512 = 633, ///< 5,25", M.O., 904995 sectors, 512 bytes/sector, ECMA-183, ISO 13481 + ECMA_183 = 634, ///< 5,25", M.O., 498526 sectors, 1024 bytes/sector, ECMA-183, ISO 13481 + ECMA_184_512 = 635, ///< 5,25", M.O., 1128772 or 1163337 sectors, 512 bytes/sector, ECMA-183, ISO 13549 + ECMA_184 = 636, ///< 5,25", M.O., 603466 or 637041 sectors, 1024 bytes/sector, ECMA-183, ISO 13549 + ECMA_189 = 637, ///< 300mm, M.O., ??? sectors, 1024 bytes/sector, ECMA-189, ISO 13614 + ECMA_190 = 638, ///< 300mm, M.O., ??? sectors, 1024 bytes/sector, ECMA-190, ISO 13403 + ECMA_195 = 639, ///< 5,25", M.O., 936921 or 948770 sectors, 1024 bytes/sector, ECMA-195, ISO 13842 + ECMA_195_512 = 640, ///< 5,25", M.O., 1644581 or 1647371 sectors, 512 bytes/sector, ECMA-195, ISO 13842 + ECMA_201 = 641, ///< 3,5", M.O., 446325 sectors, 512 bytes/sector, ECMA-201, ISO 13963 + ECMA_201_ROM = 642, ///< 3,5", M.O., 429975 sectors, 512 bytes/sector, embossed, ISO 13963 + ECMA_223 = 643, ///< 3,5", M.O., 371371 sectors, 1024 bytes/sector, ECMA-223 + ECMA_223_512 = 644, ///< 3,5", M.O., 694929 sectors, 512 bytes/sector, ECMA-223 + ECMA_238 = 645, ///< 5,25", M.O., 1244621 sectors, 1024 bytes/sector, ECMA-238, ISO 15486 + ECMA_239 = 646, ///< 3,5", M.O., 318988, 320332 or 321100 sectors, 2048 bytes/sector, ECMA-239, ISO 15498 + ECMA_260 = 647, ///< 356mm, M.O., 14476734 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 + ECMA_260_Double = 648, ///< 356mm, M.O., 24445990 sectors, 1024 bytes/sector, ECMA-260, ISO 15898 + ECMA_280 = 649, ///< 5,25", M.O., 1128134 sectors, 2048 bytes/sector, ECMA-280, ISO 18093 + ECMA_317 = 650, ///< 300mm, M.O., 7355716 sectors, 2048 bytes/sector, ECMA-317, ISO 20162 + ECMA_322 = 651, ///< 5,25", M.O., 1095840 sectors, 4096 bytes/sector, ECMA-322, ISO 22092 + ECMA_322_2k = 652, ///< 5,25", M.O., 2043664 sectors, 2048 bytes/sector, ECMA-322, ISO 22092 + GigaMo = 653, ///< 3,5", M.O., 605846 sectors, 2048 bytes/sector, Cherry Book, GigaMo, ECMA-351, ISO 17346 + GigaMo2 = 654, ///< 3,5", M.O., 1063146 sectors, 2048 bytes/sector, Cherry Book 2, GigaMo 2, ECMA-353, ISO 22533 // Magneto-optical, types 630 to 659 // Other floppy standards, types 660 to 689 CompactFloppy = 660, DemiDiskette = 661, - /** 3.5", 652 tracks, 2 sides, 512 bytes/sector, Floptical, ECMA-207, ISO 14169 */ - Floptical = 662, + Floptical = 662, ///< 3.5", 652 tracks, 2 sides, 512 bytes/sector, Floptical, ECMA-207, ISO 14169 HiFD = 663, QuickDisk = 664, UHD144 = 665, @@ -869,312 +703,264 @@ typedef enum // Apple specific media, types 690 to 699 // DEC hard disks, types 700 to 729 - /** - * 2382 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 bytes/sector, - * 204890112 bytes - */ - RA60 = 700, /** - * 546 cylinders, 14 tracks/cylinder, 31 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 121325568 bytes - */ - RA80 = 701, /** - * 1248 cylinders, 14 tracks/cylinder, 51 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 456228864 bytes - */ - RA81 = 702, /** - * 302 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 25976832 bytes - */ - RC25 = 703, /** - * 615 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 21411840 bytes - */ - RD31 = 704, /** - * 820 cylinders, 6 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 42823680 bytes - */ - RD32 = 705, /** - * 306 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 10653696 bytes - */ - RD51 = 706, /** - * 480 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 30965760 bytes - */ - RD52 = 707, /** - * 1024 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 75497472 bytes - */ - RD53 = 708, /** - * 1225 cylinders, 8 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 159936000 bytes - */ - RD54 = 709, /** - * 411 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 - * bytes/sector, 13888512 bytes - */ - RK06 = 710, /** - * 411 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 - * bytes/sector, 14204160 bytes - */ - RK06_18 = 711, /** - * 815 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 - * bytes/sector, 27540480 bytes - */ - RK07 = 712, /** - * 815 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 - * bytes/sector, 28166400 bytes - */ - RK07_18 = 713, /** - * 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 67420160 bytes - */ - RM02 = 714, /** - * 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 67420160 bytes - */ - RM03 = 715, /** - * 823 cylinders, 19 tracks/cylinder, 32 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 256196608 bytes - */ - RM05 = 716, /** - * 203 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 22865920 bytes - */ - RP02 = 717, /** - * 203 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 - * bytes/sector, 23385600 bytes - */ - RP02_18 = 718, /** - * 400 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 45056000 bytes - */ - RP03 = 719, /** - * 400 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 - * bytes/sector, 46080000 bytes - */ - RP03_18 = 720, /** - * 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 87960576 bytes - */ - RP04 = 721, /** - * 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 - * bytes/sector, 89959680 bytes - */ - RP04_18 = 722, /** - * 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 87960576 bytes - */ - RP05 = 723, /** - * 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 - * bytes/sector, 89959680 bytes - */ - RP05_18 = 724, /** - * 815 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 - * bytes/sector, 174423040 bytes - */ - RP06 = 725, /** - * 815 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 - * bytes/sector, 178387200 bytes - */ - RP06_18 = 726, + RA60 = 700, ///< 2382 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 204890112 bytes + RA80 = 701, ///< 546 cylinders, 14 tracks/cylinder, 31 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 121325568 bytes + RA81 = 702, ///< 1248 cylinders, 14 tracks/cylinder, 51 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 456228864 bytes + RC25 = 703, ///< 302 cylinders, 4 tracks/cylinder, 42 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 25976832 bytes + RD31 = 704, ///< 615 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 21411840 bytes + RD32 = 705, ///< 820 cylinders, 6 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 42823680 bytes + RD51 = 706, ///< 306 cylinders, 4 tracks/cylinder, 17 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 10653696 bytes + RD52 = 707, ///< 480 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 30965760 bytes + RD53 = 708, ///< 1024 cylinders, 7 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 75497472 bytes + RD54 = 709, ///< 1225 cylinders, 8 tracks/cylinder, 18 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 159936000 bytes + RK06 = 710, ///< 411 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 + ///< bytes/sector, 13888512 bytes + RK06_18 = 711, ///< 411 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 + ///< bytes/sector, 14204160 bytes + RK07 = 712, ///< 815 cylinders, 3 tracks/cylinder, 22 sectors/track, 256 words/sector, 16 bits/word, 512 + ///< bytes/sector, 27540480 bytes + RK07_18 = 713, ///< 815 cylinders, 3 tracks/cylinder, 20 sectors/track, 256 words/sector, 18 bits/word, 576 + ///< bytes/sector, 28166400 bytes + RM02 = 714, ///< 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 256 words/sector, 16 bits/word, 512 + ///< bytes/sector, 67420160 bytes + RM03 = 715, ///< 823 cylinders, 5 tracks/cylinder, 32 sectors/track, 256 words/sector, 16 bits/word, 512 + ///< bytes/sector, 67420160 bytes + RM05 = 716, ///< 823 cylinders, 19 tracks/cylinder, 32 sectors/track, 256 words/sector, 16 bits/word, 512 + ///< bytes/sector, 256196608 bytes + RP02 = 717, ///< 203 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 22865920 bytes + RP02_18 = 718, ///< 203 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 + ///< bytes/sector, 23385600 bytes + RP03 = 719, ///< 400 cylinders, 10 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 45056000 bytes + RP03_18 = 720, ///< 400 cylinders, 10 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 + ///< bytes/sector, 46080000 bytes + RP04 = 721, ///< 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 87960576 bytes + RP04_18 = 722, ///< 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 + ///< bytes/sector, 89959680 bytes + RP05 = 723, ///< 411 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 87960576 bytes + RP05_18 = 724, ///< 411 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 + ///< bytes/sector, 89959680 bytes + RP06 = 725, ///< 815 cylinders, 19 tracks/cylinder, 22 sectors/track, 128 words/sector, 32 bits/word, 512 + ///< bytes/sector, 174423040 bytes + RP06_18 = 726, ///< 815 cylinders, 19 tracks/cylinder, 20 sectors/track, 128 words/sector, 36 bits/word, 576 + ///< bytes/sector, 178387200 bytes // DEC hard disks, types 700 to 729 // Imation, types 730 to 739 - LS120 = 730, - LS240 = 731, - FD32MB = 732, - RDX = 733, - /** Imation 320Gb RDX */ - RDX320 = 734, + LS120 = 730, ///< Imation LS-120 SuperDisk + LS240 = 731, ///< Imation LS-240 SuperDisk + FD32MB = 732, ///< MF2HD formatted as 32MiB disk in Imation LS-240 drive + RDX = 733, ///< Tandberg / Imation RDX removable disk cartridge + RDX320 = 734, ///< Imation 320Gb RDX // Imation, types 730 to 739 // VideoNow, types 740 to 749 - VideoNow = 740, - VideoNowColor = 741, - VideoNowXp = 742 + VideoNow = 740, ///< Hasbro VideoNow 85 mm proprietary video disc + VideoNowColor = 741, ///< Hasbro VideoNow Color disc + VideoNowXp = 742 ///< Hasbro VideoNow XP higher capacity disc // } MediaType; +/** @} */ /* end of MediaTypes group */ + // NOLINTEND(readability-identifier-naming) -/** - * Contains information about a dump image and its contents +/** \struct ImageInfo + * \ingroup MediaTypes + * \brief High-level summary of an opened Aaru image. + * + * Field semantics: + * - HasPartitions: Non-zero if partition (or track, for optical) metadata structures were discovered. + * - HasSessions: Non-zero if multiple sessions (optical) are described. + * - ImageSize: Total number of addressable user-data bytes (excluding container / format headers). + * - Sectors / SectorSize: Logical block count and size. Note: (Sectors * SectorSize) may be <= ImageSize when + * variable-sized tracks exist or gap/padding bytes are preserved separately. + * - *_Time: Signed UNIX epoch seconds; negative denotes unknown / unset. + * - MediaType: Numeric value from \ref MediaType (cast-safe). 0 (Unknown) when detection failed or media is exotic. + * - XmlMediaType: Legacy compact identifier used in historical XML sidecars; retained for backward compatibility. + * - CHS geometry fields: Provided for legacy tooling; may be zero if not derivable. For variable track layouts the + * minimum SectorsPerTrack is reported (use per-track descriptors for exact geometry when available). + * + * Pointer members: + * - All uint8_t* strings are UTF-8, NUL-terminated, and owned by the library. They may be NULL if absent. + * - Copy any needed strings before destroying/closing the image context to avoid dangling pointers. + * + * Initialization contract: + * - A zeroed ImageInfo is a valid input to any population routine. + * - Callers must NOT free individual pointer members—use the designated image/context destroy API instead. + * + * Design note: This struct intentionally contains many fields for completeness / binary compatibility. + * Refactoring into sub-structures would break the public ABI, so a linter warning about field count is suppressed. */ -typedef struct ImageInfo +typedef struct ImageInfo // NOLINT { - /** Image contains partitions (or tracks for optical media) */ - uint8_t HasPartitions; - /** Image contains sessions (optical media only) */ - uint8_t HasSessions; - /** Size of the image without headers */ - uint64_t ImageSize; - /** Sectors contained in the image */ - uint64_t Sectors; - /** Size of sectors contained in the image */ - uint32_t SectorSize; - /** Media tags contained by the image */ - // List ReadableMediaTags; - /** Sector tags contained by the image */ - // List ReadableSectorTags; - /** Image version */ - uint8_t *Version; - /** Application that created the image */ - uint8_t *Application; - /** Version of the application that created the image */ - uint8_t *ApplicationVersion; - /** Who (person) created the image? */ - uint8_t *Creator; - /** Image creation time */ - int64_t CreationTime; - /** Image last modification time */ - int64_t LastModificationTime; - /** Title of the media represented by the image */ - uint8_t *MediaTitle; - /** Image comments */ - uint8_t *Comments; - /** Manufacturer of the media represented by the image */ - uint8_t *MediaManufacturer; - /** Model of the media represented by the image */ - uint8_t *MediaModel; - /** Serial number of the media represented by the image */ - uint8_t *MediaSerialNumber; - /** Barcode of the media represented by the image */ - uint8_t *MediaBarcode; - /** Part number of the media represented by the image */ - uint8_t *MediaPartNumber; - /** Media type represented by the image */ - uint32_t MediaType; - /** Number in sequence for the media represented by the image */ - int32_t MediaSequence; - /** Last media of the sequence the media represented by the image corresponds to */ - int32_t LastMediaSequence; - /** Manufacturer of the drive used to read the media represented by the image */ - uint8_t *DriveManufacturer; - /** Model of the drive used to read the media represented by the image */ - uint8_t *DriveModel; - /** Serial number of the drive used to read the media represented by the image */ - uint8_t *DriveSerialNumber; - /** Firmware revision of the drive used to read the media represented by the image */ - uint8_t *DriveFirmwareRevision; - /** Type of the media represented by the image to use in XML sidecars */ - uint8_t XmlMediaType; + uint8_t HasPartitions; ///< Image contains partitions (or tracks for optical media) + uint8_t HasSessions; ///< Image contains sessions (optical media only) + uint64_t ImageSize; ///< Size of the image without headers + uint64_t Sectors; ///< Sectors contained in the image + uint32_t SectorSize; ///< Size of sectors contained in the image + uint8_t *Version; ///< Image version + uint8_t *Application; ///< Application that created the image + uint8_t *ApplicationVersion; ///< Version of the application that created the image + uint8_t *Creator; ///< Who (person) created the image? + int64_t CreationTime; ///< Image creation time + int64_t LastModificationTime; ///< Image last modification time + uint8_t *MediaTitle; ///< Title of the media represented by the image + uint8_t *Comments; ///< Image comments + uint8_t *MediaManufacturer; ///< Manufacturer of the media represented by the image + uint8_t *MediaModel; ///< Model of the media represented by the image + uint8_t *MediaSerialNumber; ///< Serial number of the media represented by the image + uint8_t *MediaBarcode; ///< Barcode of the media represented by the image + uint8_t *MediaPartNumber; ///< Part number of the media represented by the image + uint32_t MediaType; ///< Media type represented by the image + int32_t MediaSequence; ///< Number in sequence for the media represented by the image + int32_t LastMediaSequence; ///< Last media of the sequence the media represented by the image corresponds to + uint8_t *DriveManufacturer; ///< Manufacturer of the drive used to read the media represented by the image + uint8_t *DriveModel; ///< Model of the drive used to read the media represented by the image + uint8_t *DriveSerialNumber; ///< Serial number of the drive used to read the media represented by the image + uint8_t *DriveFirmwareRevision; ///< Firmware revision of the drive used to read the media represented by the image + uint8_t XmlMediaType; ///< Type of the media represented by the image to use in XML sidecars // CHS geometry... - /** Cylinders of the media represented by the image */ - uint32_t Cylinders; - /** Heads of the media represented by the image */ - uint32_t Heads; - /** Sectors per track of the media represented by the image (for variable image, the smallest) */ - uint32_t SectorsPerTrack; + uint32_t Cylinders; ///< Cylinders of the media represented by the image + uint32_t Heads; ///< Heads of the media represented by the image + uint32_t SectorsPerTrack; ///< Sectors per track of the media represented by the image (for variable image, the + ///< smallest) } ImageInfo; -/** - * Metadata present for each sector (aka, "tag"). +/** \addtogroup SectorTags Per-sector metadata tag types + * \brief Optional auxiliary fragments accompanying a raw sector dump. + * + * Sector tags preserve on-disk / on-media structures that are not part of the main user data (sync/header/ECC, etc.). + * They enable exact reconstruction, verification or advanced analysis (error injection, subchannel decoding, etc.). + * Retrieval APIs generally expose presence queries and raw byte buffers of fixed size (unless documented as string). + * @{ */ +// NOLINTBEGIN(readability-identifier-naming) typedef enum { - AppleSectorTag = 0, /** Apple's GCR sector tags, 12 bytes */ - CdSectorSync = 1, /** Sync frame from CD sector, 12 bytes */ - CdSectorHeader = 2, /** CD sector header, 4 bytes */ - CdSectorSubHeader = 3, /** CD mode 2 sector subheader */ - CdSectorEdc = 4, /** CD sector EDC, 4 bytes */ - CdSectorEccP = 5, /** CD sector ECC P, 172 bytes */ - CdSectorEccQ = 6, /** CD sector ECC Q, 104 bytes */ - CdSectorEcc = 7, /** CD sector ECC (P and Q), 276 bytes */ - CdSectorSubchannelAaru = 8, /** CD sector subchannel, 96 bytes */ - CdTrackIsrc = 9, /** CD track ISRC, string, 12 bytes */ - CdTrackText = 10, /** CD track text, string, 13 bytes */ - CdTrackFlags = 11, /** CD track flags, 1 byte */ - DvdCmi = 12, /** DVD sector copyright information */ - FloppyAddressMark = 13, /** Floppy address mark (contents depend on underlying floppy format) */ + AppleSectorTag = 0, ///< Apple's GCR sector tags, 12 bytes (address prolog + checksum) + CdSectorSync = 1, ///< 12-byte CD sync pattern (00 FF*10 00) + CdSectorHeader = 2, ///< 4-byte CD header (minute, second, frame, mode) + CdSectorSubHeader = 3, ///< Mode 2 Form subheader (8 bytes: copy, submode, channel) + CdSectorEdc = 4, ///< 32-bit CRC (EDC) + CdSectorEccP = 5, ///< 172 bytes Reed-Solomon ECC (P) + CdSectorEccQ = 6, ///< 104 bytes Reed-Solomon ECC (Q) + CdSectorEcc = 7, ///< Combined P+Q ECC (276 bytes) + CdSectorSubchannelAaru = 8, ///< 96 raw subchannel bytes (P-W) + CdTrackIsrc = 9, ///< Track ISRC (12 ASCII chars, no terminator) + CdTrackText = 10, ///< Track text (CD-Text fragment, 13 bytes) + CdTrackFlags = 11, ///< Track flags (audio/data, copy permitted, pre-emphasis) + DvdCmi = 12, ///< DVD Copyright Management Information (CSS) + FloppyAddressMark = 13, ///< Raw address mark & sync preamble (format dependent) MaxSectorTag = FloppyAddressMark } SectorTagType; +/** @} */ /* end of SectorTags group */ + /* * Metadata present for each media. */ // NOLINTBEGIN(readability-identifier-naming) +/** \addtogroup MediaTags Per-media metadata tag types + * \brief High-level descriptors captured for the whole medium (lead-in/out, inquiry data, identification registers). + * + * Media tags are coarse-grained data blocks not tied to individual sectors. Absence indicates either unreadability + * (hardware limitation / error) or irrelevance for the specific media. Consumers should treat absence as unknown, not + * failure. Enum values are stable and serialized; append only. + * @{ */ typedef enum { /* CD table of contents */ - CD_TOC = 0, /* CD session information */ - CD_SessionInfo = 1, /* CD full table of contents */ - CD_FullTOC = 2, /* CD PMA */ - CD_PMA = 3, /* CD Adress-Time-In-Pregroove */ - CD_ATIP = 4, /* CD-Text */ - CD_TEXT = 5, /* CD Media Catalogue Number */ - CD_MCN = 6, /* DVD/HD DVD Physical Format Information */ - DVD_PFI = 7, /* DVD Lead-in Copyright Management Information */ - DVD_CMI = 8, /* DVD disc key */ - DVD_DiscKey = 9, /* DVD/HD DVD Burst Cutting Area */ - DVD_BCA = 10, /* DVD/HD DVD Lead-in Disc Manufacturer Information */ - DVD_DMI = 11, /* Media identifier */ - DVD_MediaIdentifier = 12, /* Media key block */ - DVD_MKB = 13, /* DVD-RAM/HD DVD-RAM DDS information */ - DVDRAM_DDS = 14, /* DVD-RAM/HD DVD-RAM Medium status */ - DVDRAM_MediumStatus = 15, /* DVD-RAM/HD DVD-RAM Spare area information */ - DVDRAM_SpareArea = 16, /* DVD-R/-RW/HD DVD-R RMD in last border-out */ - DVDR_RMD = 17, /* Pre-recorded information from DVD-R/-RW lead-in */ - DVDR_PreRecordedInfo = 18, /* DVD-R/-RW/HD DVD-R media identifier */ - DVDR_MediaIdentifier = 19, /* DVD-R/-RW/HD DVD-R physical format information */ - DVDR_PFI = 20, /* ADIP information */ - DVD_ADIP = 21, /* HD DVD Lead-in copyright protection information */ - HDDVD_CPI = 22, /* HD DVD-R Medium Status */ - HDDVD_MediumStatus = 23, /* DVD+/-R DL Layer capacity */ - DVDDL_LayerCapacity = 24, /* DVD-R DL Middle Zone start address */ - DVDDL_MiddleZoneAddress = 25, /* DVD-R DL Jump Interval Size */ - DVDDL_JumpIntervalSize = 26, /* DVD-R DL Start LBA of the manual layer jump */ - DVDDL_ManualLayerJumpLBA = 27, /* Blu-ray Disc Information */ - BD_DI = 28, /* Blu-ray Burst Cutting Area */ - BD_BCA = 29, /* Blu-ray Disc Definition Structure */ - BD_DDS = 30, /* Blu-ray Cartridge Status */ - BD_CartridgeStatus = 31, /* Blu-ray Status of Spare Area */ - BD_SpareArea = 32, /* AACS volume identifier */ - AACS_VolumeIdentifier = 33, /* AACS pre-recorded media serial number */ - AACS_SerialNumber = 34, /* AACS media identifier */ - AACS_MediaIdentifier = 35, /* Lead-in AACS media key block */ - AACS_MKB = 36, /* AACS data keys */ - AACS_DataKeys = 37, /* LBA extents flagged for bus encryption by AACS */ - AACS_LBAExtents = 38, /* CPRM media key block in Lead-in */ - AACS_CPRM_MKB = 39, /* Recognized layer formats in hybrid discs */ - Hybrid_RecognizedLayers = 40, /* Disc write protection status */ - MMC_WriteProtection = 41, /* Disc standard information */ - MMC_DiscInformation = 42, /* Disc track resources information */ - MMC_TrackResourcesInformation = 43, /* BD-R Pseudo-overwrite information */ - MMC_POWResourcesInformation = 44, /* SCSI INQUIRY response */ - SCSI_INQUIRY = 45, /* SCSI MODE PAGE 2Ah */ - SCSI_MODEPAGE_2A = 46, /* ATA IDENTIFY DEVICE response */ - ATA_IDENTIFY = 47, /* ATA IDENTIFY PACKET DEVICE response */ - ATAPI_IDENTIFY = 48, /* PCMCIA/CardBus Card Information Structure */ - PCMCIA_CIS = 49, /* SecureDigital CID */ - SD_CID = 50, /* SecureDigital CSD */ - SD_CSD = 51, /* SecureDigital SCR */ - SD_SCR = 52, /* SecureDigital OCR */ - SD_OCR = 53, /* MultiMediaCard CID */ - MMC_CID = 54, /* MultiMediaCard CSD */ - MMC_CSD = 55, /* MultiMediaCard OCR */ - MMC_OCR = 56, /* MultiMediaCard Extended CSD */ - MMC_ExtendedCSD = 57, /* Xbox Security Sector */ - Xbox_SecuritySector = 58, /* - * On floppy disks, data in last cylinder usually in a different format that contains - * duplication or manufacturing information - */ - Floppy_LeadOut = 59, /* DVD Disc Control Blocks */ - DCB = 60, /* Compact Disc First Track Pregap */ - CD_FirstTrackPregap = 61, /* Compact Disc Lead-out */ - CD_LeadOut = 62, /* SCSI MODE SENSE (6) */ - SCSI_MODESENSE_6 = 63, /* SCSI MODE SENSE (10) */ - SCSI_MODESENSE_10 = 64, /* USB descriptors */ - USB_Descriptors = 65, /* XGD unlocked DMI */ - Xbox_DMI = 66, /* XDG unlocked PFI */ - Xbox_PFI = 67, /* Compact Disc Lead-in */ - CD_LeadIn = 68 + CD_TOC = 0, ///< Standard CD Table Of Contents (lead-in, first session) + CD_SessionInfo = 1, ///< Per-session summary (start/end addresses, track count) + CD_FullTOC = 2, ///< Complete multi-session TOC including hidden tracks + CD_PMA = 3, ///< Program Memory Area (temporary track info before finalization) + CD_ATIP = 4, ///< Absolute Time In Pregroove (writable media timing & power metadata) + CD_TEXT = 5, ///< CD-Text blocks (titles, performers, etc.) + CD_MCN = 6, ///< Media Catalogue Number (EAN/UPC style identifier) + DVD_PFI = 7, ///< Physical Format Information (layer geometry & book type) + DVD_CMI = 8, ///< Copyright Management Information (CSS/CPRM flags) + DVD_DiscKey = 9, ///< Encrypted disc key block (CSS) + DVD_BCA = 10, ///< Burst Cutting Area (etched manufacturer / AACS info) + DVD_DMI = 11, ///< Disc Manufacturer Information (lead-in descriptor) + DVD_MediaIdentifier = 12, ///< Writable media dye / manufacturer ID + DVD_MKB = 13, ///< Media Key Block (AACS/DVD) + DVDRAM_DDS = 14, ///< Defect Data Structure (DVD-RAM mapping) + DVDRAM_MediumStatus = 15, ///< Medium Status (allocated spare info) + DVDRAM_SpareArea = 16, ///< Spare area descriptors + DVDR_RMD = 17, ///< Recorded Media Data (RMD) last border-out + DVDR_PreRecordedInfo = 18, ///< Pre-recorded info area (lead-in) + DVDR_MediaIdentifier = 19, ///< DVD-R/-RW writable media identifier + DVDR_PFI = 20, ///< DVD-R physical format (layer data) + DVD_ADIP = 21, ///< Address In Pregroove (DVD+ / wobble timing) + HDDVD_CPI = 22, ///< Content Protection Info (HD DVD) + HDDVD_MediumStatus = 23, ///< HD DVD Medium status (spares/defects) + DVDDL_LayerCapacity = 24, ///< Dual layer capacity & break info + DVDDL_MiddleZoneAddress = 25, ///< Middle zone start LBA + DVDDL_JumpIntervalSize = 26, ///< Jump interval size (opposite track path) + DVDDL_ManualLayerJumpLBA = 27, ///< Manual layer jump LBA (OTP) + BD_DI = 28, ///< Disc Information (BD) + BD_BCA = 29, ///< Blu-ray Burst Cutting Area + BD_DDS = 30, ///< Disc Definition Structure (recordable) + BD_CartridgeStatus = 31, ///< Cartridge presence / write protect (BD-RE/BD-R in caddy) + BD_SpareArea = 32, ///< BD spare area allocation map + AACS_VolumeIdentifier = 33, ///< AACS Volume Identifier + AACS_SerialNumber = 34, ///< Pre-recorded media serial number (AACS) + AACS_MediaIdentifier = 35, ///< AACS Media Identifier (unique per disc) + AACS_MKB = 36, ///< AACS Media Key Block + AACS_DataKeys = 37, ///< Extracted AACS title/volume keys (when decrypted) + AACS_LBAExtents = 38, ///< LBA extents requiring bus encryption + AACS_CPRM_MKB = 39, ///< CPRM Media Key Block + Hybrid_RecognizedLayers = 40, ///< Hybrid disc recognized layer combinations (e.g. CD/DVD/BD) + MMC_WriteProtection = 41, ///< Write protection status (MMC GET CONFIG) + MMC_DiscInformation = 42, ///< Disc Information (recordable status, erasable, last session) + MMC_TrackResourcesInformation = 43, ///< Track Resources (allocated/open track data) + MMC_POWResourcesInformation = 44, ///< Pseudo OverWrite resources (BD-R POW) + SCSI_INQUIRY = 45, ///< SCSI INQUIRY standard data (SPC-*) + SCSI_MODEPAGE_2A = 46, ///< SCSI Mode Page 2Ah (CD/DVD capabilities) + ATA_IDENTIFY = 47, ///< ATA IDENTIFY DEVICE (512 bytes) + ATAPI_IDENTIFY = 48, ///< ATA PACKET IDENTIFY DEVICE + PCMCIA_CIS = 49, ///< PCMCIA/CardBus CIS tuple chain + SD_CID = 50, ///< SecureDigital Card ID register + SD_CSD = 51, ///< SecureDigital Card Specific Data + SD_SCR = 52, ///< SecureDigital Configuration Register + SD_OCR = 53, ///< SecureDigital Operation Conditions (voltage) + MMC_CID = 54, ///< MMC Card ID + MMC_CSD = 55, ///< MMC Card Specific Data + MMC_OCR = 56, ///< MMC Operation Conditions + MMC_ExtendedCSD = 57, ///< MMC Extended CSD (512 bytes) + Xbox_SecuritySector = 58, ///< Xbox/Xbox 360 Security Sector (SS.bin) + Floppy_LeadOut = 59, ///< Manufacturer / duplication cylinder (floppy special data) + DCB = 60, ///< DVD Disc Control Blocks + CD_FirstTrackPregap = 61, ///< First track pregap (index 0) + CD_LeadOut = 62, ///< Lead-out area contents + SCSI_MODESENSE_6 = 63, ///< Raw MODE SENSE (6) data + SCSI_MODESENSE_10 = 64, ///< Raw MODE SENSE (10) data + USB_Descriptors = 65, ///< Concatenated USB descriptors (device/config/interface) + Xbox_DMI = 66, ///< Xbox Disc Manufacturing Info (DMI) + Xbox_PFI = 67, ///< Xbox Physical Format Information (PFI) + CD_LeadIn = 68 ///< Raw lead-in (TOC frames) } MediaTagType; +/** @} */ /* end of MediaTags group */ + // NOLINTEND(readability-identifier-naming) #ifndef _MSC_VER #pragma clang diagnostic pop #endif -#endif // LIBAARUFORMAT_AARU_H \ No newline at end of file +#endif // LIBAARUFORMAT_AARU_H diff --git a/include/aaruformat/consts.h b/include/aaruformat/consts.h index 9c89553..59809f6 100644 --- a/include/aaruformat/consts.h +++ b/include/aaruformat/consts.h @@ -24,43 +24,90 @@ #pragma ide diagnostic ignored "OCUnusedMacroInspection" #endif -/** Magic identidier = "DICMFRMT". */ -#define DIC_MAGIC 0x544D52464D434944 -/** Magic identidier = "AARUFRMT". */ -#define AARU_MAGIC 0x544D524655524141 -/** Image format version. A change in this number indicates an incompatible change to the format that prevents older - * implementations from reading it correctly, if at all. */ -#define AARUF_VERSION 2 -/** First version of AaruFormat, created in C#. - * CRC64 was byte-swapped +/** \file aaruformat/consts.h + * \brief Core public constants and compile‑time limits for the Aaru container format implementation. + * + * This header exposes magic identifiers, format version selectors, resource limits, codec parameter bounds, + * and bit masks used across libaaruformat. All values are immutable interface contracts; changing them breaks + * backward compatibility unless a new format version is declared. + * + * Summary: + * - Magic numbers (DIC_MAGIC, AARU_MAGIC) identify container families (legacy DiscImageChef vs AaruFormat). + * - Version macros distinguish format generations (V1 C# / legacy CRC endianness, V2 current C implementation). + * - Cache and table size limits provide protective upper bounds against runaway memory consumption. + * - Audio constants (SAMPLES_PER_SECTOR, MIN/MAX_FLAKE_BLOCK) align with Red Book (CD‑DA) and FLAC encoding best + * practices. + * - CD_* masks assist with extracting flags / positional subfields in deduplicated Compact Disc sector tables. + * - CRC64 constants implement ECMA‑182 polynomial and standard seed, enabling deterministic end‑to‑end block + * integrity. + * + * Notes: + * - Magic values are stored little‑endian on disk when written as 64‑bit integers; when inspecting raw bytes make + * sure to account for host endianness. + * - AARUF_VERSION must be incremented only when an incompatible on‑disk layout change is introduced. + * - MAX_DDT_ENTRY_CACHE is a soft upper bound sized to balance deduplication hit rate vs RAM; tune in future builds + * via configuration if adaptive heuristics are introduced. + * - The LZMA properties length (5) derives from the standard LZMA header (lc/lp/pb + dict size) and is constant for + * raw LZMA streams used here. + * - FLAC sample block guidance: empirical evaluation shows >4608 samples per block does not yield meaningful ratio + * gains for typical optical audio captures while increasing decode buffer size. + * + * Thread safety: All macros are compile‑time constants; no synchronization required. + * Portability: Constants chosen to fit within 64‑bit targets; arithmetic assumes two's complement. */ -#define AARUF_VERSION_V1 1 -/** Second version of AaruFormat, created in C. - * Introduced new header, many new features, and blocks. - */ -#define AARUF_VERSION_V2 2 -/** Maximum read cache size, 512MiB. */ -#define MAX_CACHE_SIZE 536870912 -/** Size in bytes of LZMA properties. */ -#define LZMA_PROPERTIES_LENGTH 5 -/** Maximum number of entries for the DDT cache. */ -#define MAX_DDT_ENTRY_CACHE 16000000 -/** How many samples are contained in a RedBook sector. */ -#define SAMPLES_PER_SECTOR 588 -/** Maximum number of samples for a FLAC block. Bigger than 4608 gives no benefit. */ -#define MAX_FLAKE_BLOCK 4608 -/** Minimum number of samples for a FLAC block. CUETools.Codecs.FLAKE does not support it to be smaller than 256. */ -#define MIN_FLAKE_BLOCK 256 -/** This mask is to check for flags in CompactDisc suffix/prefix DDT */ -#define CD_XFIX_MASK 0xFF000000 -/** This mask is to check for position in CompactDisc suffix/prefix deduplicated block */ -#define CD_DFIX_MASK 0x00FFFFFF -#define CRC64_ECMA_POLY 0xC96C5795D7870F42 -#define CRC64_ECMA_SEED 0xFFFFFFFFFFFFFFFF +/** Magic identifier for legacy DiscImageChef container (ASCII "DICMFRMT"). + * Retained for backward compatibility / migration tooling. */ +#define DIC_MAGIC 0x544D52464D434944ULL +/** Magic identifier for AaruFormat container (ASCII "AARUFRMT"). + * Used in the primary header to assert correct file type. */ +#define AARU_MAGIC 0x544D524655524141ULL + +/** Current image format major version (incompatible changes bump this). + * Readers should reject headers with a higher number unless explicitly forward compatible. */ +#define AARUF_VERSION 2 +/** First on‑disk version (C# implementation). + * Quirk: CRC64 values were stored byte‑swapped relative to ECMA‑182 canonical output. */ +#define AARUF_VERSION_V1 1 +/** Second on‑disk version (C implementation). + * Introduced: extended header (GUID, feature bitmaps), hierarchical DDT v2, improved index (v2/v3), + * multi‑codec compression, refined metadata blocks. */ +#define AARUF_VERSION_V2 2 + +/** Maximum read cache size (bytes). 512 MiB chosen to prevent excessive resident memory while + * still enabling efficient sequential and moderate random access patterns. */ +#define MAX_CACHE_SIZE 536870912ULL + +/** Size in bytes of the fixed LZMA properties header (lc/lp/pb + dictionary size). */ +#define LZMA_PROPERTIES_LENGTH 5 + +/** Maximum number of cached DDT entry descriptors retained in memory for fast duplicate detection. + * At 16,000,000 entries with a compact structure, this caps hash_map overhead while covering large images. + * (Approx memory just for lookup bookkeeping: ~16 bytes * N ≈ 256 MB worst case; typical effective <50% of cap.) */ +#define MAX_DDT_ENTRY_CACHE 16000000 + +/** Red Book (CD‑DA) PCM samples per 2352‑byte sector: 44,100 Hz / 75 sectors per second = 588 samples. */ +#define SAMPLES_PER_SECTOR 588 + +/** FLAC maximum block size used for encoding audio sectors. + * Empirically >4608 samples yields diminishing compression returns and higher decode latency. */ +#define MAX_FLAKE_BLOCK 4608 +/** FLAC minimum block size. CUETools.Codecs.FLAKE does not accept blocks smaller than 256 samples. */ +#define MIN_FLAKE_BLOCK 256 + +/** Mask for extracting correction / fix flags in Compact Disc suffix/prefix DDT entries. + * High 8 bits store status (see SectorStatus / CdFixFlags relationships). */ +#define CD_XFIX_MASK 0xFF000000U +/** Mask for extracting positional index (lower 24 bits) in Compact Disc suffix/prefix deduplicated block entries. */ +#define CD_DFIX_MASK 0x00FFFFFFU + +/** ECMA‑182 CRC64 polynomial (reflected form used in standard implementations). */ +#define CRC64_ECMA_POLY 0xC96C5795D7870F42ULL +/** Initial seed value for CRC64 computations (all bits set). */ +#define CRC64_ECMA_SEED 0xFFFFFFFFFFFFFFFFULL #ifndef _MSC_VER #pragma clang diagnostic pop #endif -#endif // LIBAARUFORMAT_CONSTS_H \ No newline at end of file +#endif // LIBAARUFORMAT_CONSTS_H diff --git a/include/aaruformat/context.h b/include/aaruformat/context.h index 8931fa5..0ce0db2 100644 --- a/include/aaruformat/context.h +++ b/include/aaruformat/context.h @@ -25,6 +25,41 @@ #include "structs.h" #include "utarray.h" +/** \file aaruformat/context.h + * \brief Central runtime context structures for libaaruformat (image state, caches, checksum buffers). + * + * The principal structure, \ref aaruformatContext, aggregates: header metadata, open stream handle, deduplication + * tables (DDT) currently in memory, optical disc auxiliary data (sector prefix/suffix/subchannel), track listings, + * geometry & metadata blocks, checksum accumulators, CRC & ECC helper contexts, hash map for deduplication, and + * transient write buffers. + * + * Memory ownership model (unless otherwise stated): if a pointer field is non-NULL it is owned by the context and + * will be freed (or otherwise released) during context close / destruction. Callers must not free or reallocate + * these pointers directly. External callers should treat all internal buffers as read‑only unless explicitly writing. + * + * Threading: a single context instance is NOT thread-safe; serialize access if used across threads. + * Lifetime: allocate, initialize/open, perform read/write/verify operations, then close/free. + * + * Deduplication tables (DDT): only a subset (primary table + an active secondary + optional cache) is retained in RAM; + * large images may rely on lazy loading of secondary tables. Flags (inMemoryDdt, userDataDdt*, cachedSecondary*) + * indicate what is currently resident. + * + * Optical auxiliary buffers (sectorPrefix / sectorSuffix / subchannel / corrected variants) are populated only for + * images where those components exist (e.g., raw CD dumps). They may be NULL for block devices / non‑optical media. + * + * Index handling: indexEntries (UT_array) holds a flattened list of \ref IndexEntry structures (regardless of + * v1/v2/v3). hash_map_t *sectorHashMap provides fast duplicate detection keyed by content fingerprint / sparse sector + * key. + * + * Invariants / sanity expectations (not strictly enforced everywhere): + * - magic == AARU_MAGIC after successful open/create. + * - header.imageMajorVersion <= AARUF_VERSION. + * - imageStream != NULL when any I/O method is in progress. + * - If deduplicate == false, sectorHashMap may still be populated for bookkeeping but duplicates are stored + * independently. + * - If userDataDdtMini != NULL then userDataDdtBig == NULL (and vice versa) for a given level. + */ + #ifndef MD5_DIGEST_LENGTH #define MD5_DIGEST_LENGTH 16 #endif @@ -37,121 +72,186 @@ #define SHA256_DIGEST_LENGTH 32 #endif +/** \struct Crc64Context + * \brief Internal (legacy) CRC64 computation context (superseded by crt \ref crc64_ctx usage). + * + * Kept for compatibility with earlier code paths; new code should prefer the opaque crc64_ctx API. + */ typedef struct Crc64Context { - uint64_t finalSeed; - uint64_t table[256]; - uint64_t hashInt; + uint64_t finalSeed; ///< Final CRC value (post processing) or running seed. + uint64_t table[256]; ///< Precomputed 256-entry lookup table for the ECMA polynomial. + uint64_t hashInt; ///< Intermediate accumulator. } Crc64Context; +/** \struct CdEccContext + * \brief Lookup tables and state for Compact Disc EDC/ECC (P/Q) regeneration / verification. + * + * Fields may be lazily allocated; inited_edc indicates tables are ready. + */ typedef struct CdEccContext { - bool inited_edc; - uint8_t *ecc_b_table; - uint8_t *ecc_f_table; - uint32_t *edc_table; + bool inited_edc; ///< True once EDC/ECC tables have been initialized. + uint8_t *ecc_b_table; ///< Backward (B) ECC table (allocated, size implementation-defined). + uint8_t *ecc_f_table; ///< Forward (F) ECC table. + uint32_t *edc_table; ///< EDC (CRC) lookup table. } CdEccContext; +/** \struct Checksums + * \brief Collected whole‑image checksums / hashes present in a checksum block. + * + * Only hash arrays with corresponding has* flags set contain valid data. spamsum is a dynamically allocated + * NUL‑terminated buffer (original SpamSum signature bytes followed by appended '\0'). + */ typedef struct Checksums { - bool hasMd5; - bool hasSha1; - bool hasSha256; - bool hasSpamSum; - uint8_t md5[MD5_DIGEST_LENGTH]; - uint8_t sha1[SHA1_DIGEST_LENGTH]; - uint8_t sha256[SHA256_DIGEST_LENGTH]; - uint8_t *spamsum; + bool hasMd5; ///< True if md5[] buffer populated. + bool hasSha1; ///< True if sha1[] buffer populated. + bool hasSha256; ///< True if sha256[] buffer populated. + bool hasSpamSum; ///< True if spamsum pointer allocated and signature read. + uint8_t md5[MD5_DIGEST_LENGTH]; ///< MD5 digest (16 bytes). + uint8_t sha1[SHA1_DIGEST_LENGTH]; ///< SHA-1 digest (20 bytes). + uint8_t sha256[SHA256_DIGEST_LENGTH]; ///< SHA-256 digest (32 bytes). + uint8_t *spamsum; ///< SpamSum fuzzy hash (ASCII), allocated length+1 with trailing 0. } Checksums; +/** \struct mediaTagEntry + * \brief Hash table entry for an arbitrary media tag (e.g., proprietary drive/medium descriptor). + * + * Stored via uthash (hh handle). Type is a format‑specific integer identifier mapping to external interpretation. + */ typedef struct mediaTagEntry { - uint8_t *data; - int32_t type; - uint32_t length; - UT_hash_handle hh; + uint8_t *data; ///< Tag data blob (opaque to library core); length bytes long. + int32_t type; ///< Numeric type identifier. + uint32_t length; ///< Length in bytes of data. + UT_hash_handle hh; ///< uthash linkage. } mediaTagEntry; +/** \struct aaruformatContext + * \brief Master context representing an open or in‑creation Aaru image. + * + * Contains stream handle, parsed headers, deduplication structures, optical extras, metadata blocks, checksum + * information, caches, and write-state. Allocate with library factory (or zero‑init + explicit open) and destroy + * with corresponding close/free routine. + * + * Field grouping: + * - Core & header: magic, library*Version, imageStream, header. + * - Optical sector adjuncts: sectorPrefix/sectorSuffix/subchannel plus corrected variants & mode2Subheaders. + * - Deduplication: inMemoryDdt, userDataDdt*, userDataDdtHeader, mini/big/cached secondary arrays, version tags. + * - Metadata & geometry: geometryBlock, metadataBlockHeader+metadataBlock, cicmBlockHeader+cicmBlock, tracksHeader. + * - Tracks & hardware: trackEntries, dataTracks, dumpHardwareHeader, dumpHardwareEntriesWithData. + * - Integrity & ECC: checksums, eccCdContext, crc64Context. + * - Index & dedup lookup: indexEntries (UT_array of IndexEntry), sectorHashMap (duplicate detection), deduplicate + * flag. + * - Write path: isWriting, currentBlockHeader, writingBuffer(+position/offset), nextBlockPosition. + * + * Notes: + * - userDataDdt points to memory-mapped or fully loaded DDT (legacy path); userDataDdtMini / userDataDdtBig + * supersede. + * - shift retained for backward compatibility with earlier single‑level address shift semantics. + * - mappedMemoryDdtSize is meaningful only if userDataDdt references an mmapped region. + */ typedef struct aaruformatContext { - uint64_t magic; - uint8_t libraryMajorVersion; - uint8_t libraryMinorVersion; - FILE *imageStream; - AaruHeaderV2 header; - uint8_t *sectorPrefix; - uint8_t *sectorPrefixCorrected; - uint8_t *sectorSuffix; - uint8_t *sectorSuffixCorrected; - uint8_t *sectorSubchannel; - uint8_t *mode2Subheaders; - uint8_t shift; - bool inMemoryDdt; - uint64_t *userDataDdt; - size_t mappedMemoryDdtSize; - uint32_t *sectorPrefixDdt; - uint32_t *sectorSuffixDdt; - GeometryBlockHeader geometryBlock; - MetadataBlockHeader metadataBlockHeader; - uint8_t *metadataBlock; - TracksHeader tracksHeader; - TrackEntry *trackEntries; - CicmMetadataBlock cicmBlockHeader; - uint8_t *cicmBlock; - DumpHardwareHeader dumpHardwareHeader; - struct DumpHardwareEntriesWithData *dumpHardwareEntriesWithData; - ImageInfo imageInfo; - CdEccContext *eccCdContext; - uint8_t numberOfDataTracks; - TrackEntry *dataTracks; - bool *readableSectorTags; - struct CacheHeader blockHeaderCache; - struct CacheHeader blockCache; - Checksums checksums; - mediaTagEntry *mediaTags; - DdtHeader2 userDataDdtHeader; - int ddtVersion; - uint16_t *userDataDdtMini; - uint32_t *userDataDdtBig; - uint16_t *sectorPrefixDdtMini; - uint16_t *sectorSuffixDdtMini; - uint64_t cachedDdtOffset; - uint64_t cachedDdtPosition; - uint64_t primaryDdtOffset; - uint16_t *cachedSecondaryDdtSmall; - uint32_t *cachedSecondaryDdtBig; - bool isWriting; - BlockHeader currentBlockHeader; - uint8_t *writingBuffer; - int currentBlockOffset; - crc64_ctx *crc64Context; - int writingBufferPosition; - uint64_t nextBlockPosition; - UT_array *indexEntries; - hash_map_t *sectorHashMap; - bool deduplicate; + uint64_t magic; ///< File magic (AARU_MAGIC) post-open. + uint8_t libraryMajorVersion; ///< Linked library major version. + uint8_t libraryMinorVersion; ///< Linked library minor version. + FILE *imageStream; ///< Underlying FILE* stream (binary mode). + AaruHeaderV2 header; ///< Parsed container header (v2). + + /* Optical auxiliary buffers (NULL if not present) */ + uint8_t *sectorPrefix; ///< Raw per-sector prefix (e.g., sync+header) uncorrected. + uint8_t *sectorPrefixCorrected; ///< Corrected variant (post error correction) if stored. + uint8_t *sectorSuffix; ///< Raw per-sector suffix (EDC/ECC) uncorrected. + uint8_t *sectorSuffixCorrected; ///< Corrected suffix if stored separately. + uint8_t *sectorSubchannel; ///< Raw 96-byte subchannel (if captured). + uint8_t *mode2Subheaders; ///< MODE2 Form1/Form2 8-byte subheaders (concatenated). + + uint8_t shift; ///< Legacy overall shift (deprecated by data_shift/table_shift). + bool inMemoryDdt; ///< True if primary (and possibly secondary) DDT loaded. + uint64_t *userDataDdt; ///< Legacy flat DDT pointer (NULL when using v2 mini/big arrays). + size_t mappedMemoryDdtSize; ///< Length of mmapped DDT if userDataDdt is mmapped. + uint32_t *sectorPrefixDdt; ///< Legacy CD sector prefix DDT (deprecated by *_Mini/Big). + uint32_t *sectorSuffixDdt; ///< Legacy CD sector suffix DDT. + + GeometryBlockHeader geometryBlock; ///< Logical geometry block (if present). + MetadataBlockHeader metadataBlockHeader; ///< Metadata block header. + uint8_t *metadataBlock; ///< Raw metadata UTF-16LE concatenated strings. + TracksHeader tracksHeader; ///< Tracks header (optical) if present. + TrackEntry *trackEntries; ///< Full track list (tracksHeader.entries elements). + CicmMetadataBlock cicmBlockHeader; ///< CICM metadata header (if present). + uint8_t *cicmBlock; ///< CICM XML payload. + DumpHardwareHeader dumpHardwareHeader; ///< Dump hardware header. + struct DumpHardwareEntriesWithData *dumpHardwareEntriesWithData; ///< Array of dump hardware entries + strings. + ImageInfo imageInfo; ///< Exposed high-level image info summary. + + CdEccContext *eccCdContext; ///< CD ECC/EDC helper tables (allocated on demand). + uint8_t numberOfDataTracks; ///< Count of tracks considered "data" (sequence 1..99 heuristics). + TrackEntry *dataTracks; ///< Filtered list of data tracks (subset of trackEntries). + bool *readableSectorTags; ///< Per-sector boolean array (optical tags read successfully?). + + struct CacheHeader blockHeaderCache; ///< LRU/Cache header for block headers. + struct CacheHeader blockCache; ///< LRU/Cache header for block payloads. + + Checksums checksums; ///< Whole-image checksums discovered. + mediaTagEntry *mediaTags; ///< Hash table of extra media tags (uthash root). + + DdtHeader2 userDataDdtHeader; ///< Active user data DDT v2 header (primary table meta). + int ddtVersion; ///< DDT version in use (1=legacy, 2=v2 hierarchical). + uint16_t *userDataDdtMini; ///< DDT entries (small variant) primary/secondary current. + uint32_t *userDataDdtBig; ///< DDT entries (big variant) primary/secondary current. + uint16_t *sectorPrefixDdtMini; ///< CD sector prefix corrected DDT (small) if present. + uint16_t *sectorSuffixDdtMini; ///< CD sector suffix corrected DDT (small) if present. + + uint64_t cachedDdtOffset; ///< File offset of currently cached secondary DDT (0=none). + uint64_t cachedDdtPosition; ///< Position index of cached secondary DDT. + uint64_t primaryDdtOffset; ///< File offset of the primary DDT v2 table. + uint16_t *cachedSecondaryDdtSmall; ///< Cached secondary table (small entries) or NULL. + uint32_t *cachedSecondaryDdtBig; ///< Cached secondary table (big entries) or NULL. + + bool isWriting; ///< True if context opened/created for writing. + BlockHeader currentBlockHeader; ///< Header for block currently being assembled (write path). + uint8_t *writingBuffer; ///< Accumulation buffer for current block data. + int currentBlockOffset; ///< Logical offset inside block (units: bytes or sectors depending on path). + crc64_ctx *crc64Context; ///< Opaque CRC64 context for streaming updates. + int writingBufferPosition; ///< Current size / position within writingBuffer. + uint64_t nextBlockPosition; ///< Absolute file offset where next block will be written. + + UT_array *indexEntries; ///< Flattened index entries (UT_array of IndexEntry). + hash_map_t *sectorHashMap; ///< Deduplication hash map (fingerprint->entry mapping). + bool deduplicate; ///< Storage deduplication active (duplicates coalesce). } aaruformatContext; +/** \struct DumpHardwareEntriesWithData + * \brief In-memory representation of a dump hardware entry plus decoded variable-length fields & extents. + * + * All string pointers are NUL-terminated UTF-8 copies of on-disk data (or NULL if absent). extents array may be NULL + * when no ranges were recorded. Freed during context teardown. + */ typedef struct DumpHardwareEntriesWithData { - DumpHardwareEntry entry; - struct DumpExtent *extents; - uint8_t *manufacturer; - uint8_t *model; - uint8_t *revision; - uint8_t *firmware; - uint8_t *serial; - uint8_t *softwareName; - uint8_t *softwareVersion; - uint8_t *softwareOperatingSystem; + DumpHardwareEntry entry; ///< Fixed-size header with lengths & counts. + struct DumpExtent *extents; ///< Array of extents (entry.extents elements) or NULL. + uint8_t *manufacturer; ///< Manufacturer string (UTF-8) or NULL. + uint8_t *model; ///< Model string or NULL. + uint8_t *revision; ///< Hardware revision string or NULL. + uint8_t *firmware; ///< Firmware version string or NULL. + uint8_t *serial; ///< Serial number string or NULL. + uint8_t *softwareName; ///< Dump software name or NULL. + uint8_t *softwareVersion; ///< Dump software version or NULL. + uint8_t *softwareOperatingSystem; ///< Host operating system string or NULL. } DumpHardwareEntriesWithData; #pragma pack(push, 1) +/** \struct DumpExtent + * \brief Inclusive [start,end] logical sector range contributed by a single hardware environment. + */ typedef struct DumpExtent { - uint64_t start; - uint64_t end; + uint64_t start; ///< Starting LBA (inclusive). + uint64_t end; ///< Ending LBA (inclusive); >= start. } DumpExtent; #pragma pack(pop) diff --git a/include/aaruformat/crc64.h b/include/aaruformat/crc64.h index 2fbd050..303514d 100644 --- a/include/aaruformat/crc64.h +++ b/include/aaruformat/crc64.h @@ -20,11 +20,49 @@ #define LIBAARUFORMAT_CRC64_H #include +/** \file aaruformat/crc64.h + * \brief CRC64 (ECMA-182) core context and precomputed slicing-by-4 tables. + * + * Exposes: + * - \ref crc64_ctx: minimal incremental state (initialize crc to CRC64_ECMA_SEED). + * - crc64_table[4][256]: 4-way (slicing-by-4) lookup tables for high-throughput updates. + * - CRC64_ECMA_POLY / CRC64_ECMA_SEED macros matching ECMA-182 (reflected polynomial, all-bits-set seed). + * + * Algorithm characteristics: + * - Polynomial: 0xC96C5795D7870F42 (reflected form). + * - Seed / initial value: 0xFFFFFFFFFFFFFFFFULL. + * - Final XOR: none (raw accumulator is the result). + * - Bit order: reflected; least significant bit processed first. + * + * Table layout & optimization: + * Four 256-entry tables are used (slicing-by-4) allowing 4-byte chunks to be folded per iteration, reducing data + * dependency chains compared to a single-table approach. This improves throughput on modern CPUs with abundant ILP. + * + * Incremental usage (pseudo-code): + * \code{.c} + * crc64_ctx ctx = { .crc = CRC64_ECMA_SEED }; + * ctx.crc = crc64_update(ctx.crc, buf, len); // internal helper using crc64_table + * // ctx.crc now holds ECMA-182 CRC64 value. + * \endcode + * + * Thread safety: The table is read-only; each thread must use its own crc64_ctx. + * Endianness: Table values are host-endian 64-bit constants; algorithm result is endianness-agnostic. + */ + +/** \struct crc64_ctx + * \brief Minimal ECMA-182 CRC64 incremental state container (running value only). + */ typedef struct { - uint64_t crc; + uint64_t crc; ///< Running CRC value (initialize to CRC64_ECMA_SEED before first update). } crc64_ctx; +/** \var crc64_table + * \brief Precomputed slicing-by-4 ECMA-182 CRC64 lookup tables (4 * 256 * 8 = 8192 bytes). + * + * Each row corresponds to one byte lane in a 4-byte block update; actual folding logic resides in the implementation. + * Content generated offline; do not modify manually. + */ const static uint64_t crc64_table[4][256] = { {0x0000000000000000, 0xB32E4CBE03A75F6F, 0xF4843657A840A05B, 0x47AA7AE9ABE7FF34, 0x7BD0C384FF8F5E33, 0xC8FE8F3AFC28015C, 0x8F54F5D357CFFE68, 0x3C7AB96D5468A107, 0xF7A18709FF1EBC66, 0x448FCBB7FCB9E309, @@ -236,7 +274,9 @@ const static uint64_t crc64_table[4][256] = { 0x1E5CD90C6EC2440D} }; -#define CRC64_ECMA_POLY 0xC96C5795D7870F42 -#define CRC64_ECMA_SEED 0xFFFFFFFFFFFFFFFF +/** ECMA-182 reflected polynomial constant. */ +#define CRC64_ECMA_POLY 0xC96C5795D7870F42ULL +/** ECMA-182 initial seed (all bits set). */ +#define CRC64_ECMA_SEED 0xFFFFFFFFFFFFFFFFULL #endif // LIBAARUFORMAT_CRC64_H diff --git a/include/aaruformat/errors.h b/include/aaruformat/errors.h index 6f71601..f415480 100644 --- a/include/aaruformat/errors.h +++ b/include/aaruformat/errors.h @@ -19,35 +19,136 @@ #ifndef LIBAARUFORMAT_ERRORS_H #define LIBAARUFORMAT_ERRORS_H -#define AARUF_ERROR_NOT_AARUFORMAT (-1) -#define AARUF_ERROR_FILE_TOO_SMALL (-2) -#define AARUF_ERROR_INCOMPATIBLE_VERSION (-3) -#define AARUF_ERROR_CANNOT_READ_INDEX (-4) -#define AARUF_ERROR_SECTOR_OUT_OF_BOUNDS (-5) -#define AARUF_ERROR_CANNOT_READ_HEADER (-6) -#define AARUF_ERROR_CANNOT_READ_BLOCK (-7) -#define AARUF_ERROR_UNSUPPORTED_COMPRESSION (-8) -#define AARUF_ERROR_NOT_ENOUGH_MEMORY (-9) -#define AARUF_ERROR_BUFFER_TOO_SMALL (-10) -#define AARUF_ERROR_MEDIA_TAG_NOT_PRESENT (-11) -#define AARUF_ERROR_INCORRECT_MEDIA_TYPE (-12) -#define AARUF_ERROR_TRACK_NOT_FOUND (-13) -#define AARUF_ERROR_REACHED_UNREACHABLE_CODE (-14) -#define AARUF_ERROR_INVALID_TRACK_FORMAT (-15) -#define AARUF_ERROR_SECTOR_TAG_NOT_PRESENT (-16) -#define AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK (-17) -#define AARUF_ERROR_INVALID_BLOCK_CRC (-18) -#define AARUF_ERROR_CANNOT_CREATE_FILE (-19) -#define AARUF_ERROR_INVALID_APP_NAME_LENGTH (-20) -#define AARUF_ERROR_CANNOT_WRITE_HEADER (-21) -#define AARUF_READ_ONLY (-22) -#define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER (-23) -#define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA (-24) -#define AARUF_ERROR_CANNOT_SET_DDT_ENTRY (-25) +/** \file aaruformat/errors.h + * \brief Public error and status code definitions for libaaruformat. + * + * Negative values represent fatal / non-recoverable error conditions returned by library functions. + * Non-negative values (>=0) are either success (0) or sector-level status annotations used when + * decoding per-sector metadata (e.g. a sector not dumped or with corrected/unrecoverable errors). + * + * Usage guidelines: + * - Always test for < 0 to check generic failure without enumerating all codes. + * - Use exact comparisons for caller-specific handling (e.g. retry on AARUF_ERROR_CANNOT_READ_BLOCK). + * - Sector status codes are never returned as fatal function results; they appear in output parameters + * populated by read/identify routines. + * + * Helper: see aaruformat_error_string() for a human-readable textual description suitable for logs. + */ -#define AARUF_STATUS_OK 0 -#define AARUF_STATUS_SECTOR_NOT_DUMPED 1 -#define AARUF_STATUS_SECTOR_WITH_ERRORS 2 -#define AARUF_STATUS_SECTOR_DELETED 3 +/** \name Fatal / library-level error codes (negative) + * @{ */ +#define AARUF_ERROR_NOT_AARUFORMAT (-1) ///< Input file/stream failed magic or structural validation. +#define AARUF_ERROR_FILE_TOO_SMALL (-2) ///< File size insufficient for mandatory header / structures. +#define AARUF_ERROR_INCOMPATIBLE_VERSION (-3) ///< Image uses a newer incompatible on-disk version. +#define AARUF_ERROR_CANNOT_READ_INDEX (-4) ///< Index block unreadable / truncated / bad identifier. +#define AARUF_ERROR_SECTOR_OUT_OF_BOUNDS (-5) ///< Requested logical sector outside media bounds. +#define AARUF_ERROR_CANNOT_READ_HEADER (-6) ///< Failed to read container header. +#define AARUF_ERROR_CANNOT_READ_BLOCK (-7) ///< Generic block read failure (seek/read error). +#define AARUF_ERROR_UNSUPPORTED_COMPRESSION (-8) ///< Block marked with unsupported compression algorithm. +#define AARUF_ERROR_NOT_ENOUGH_MEMORY (-9) ///< Memory allocation failure (critical). +#define AARUF_ERROR_BUFFER_TOO_SMALL (-10) ///< Caller-supplied buffer insufficient for data. +#define AARUF_ERROR_MEDIA_TAG_NOT_PRESENT (-11) ///< Requested media tag absent. +#define AARUF_ERROR_INCORRECT_MEDIA_TYPE (-12) ///< Operation incompatible with image media type. +#define AARUF_ERROR_TRACK_NOT_FOUND (-13) ///< Referenced track number not present. +#define AARUF_ERROR_REACHED_UNREACHABLE_CODE (-14) ///< Internal logic assertion hit unexpected path. +#define AARUF_ERROR_INVALID_TRACK_FORMAT (-15) ///< Track metadata internally inconsistent or malformed. +#define AARUF_ERROR_SECTOR_TAG_NOT_PRESENT (-16) ///< Requested sector tag (e.g. subchannel/prefix) not stored. +#define AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK (-17) ///< Decompression routine failed or size mismatch. +#define AARUF_ERROR_INVALID_BLOCK_CRC (-18) ///< CRC64 mismatch indicating corruption. +#define AARUF_ERROR_CANNOT_CREATE_FILE (-19) ///< Output file could not be created / opened for write. +#define AARUF_ERROR_INVALID_APP_NAME_LENGTH (-20) ///< Application name field length invalid (sanity limit). +#define AARUF_ERROR_CANNOT_WRITE_HEADER (-21) ///< Failure writing container header. +#define AARUF_READ_ONLY (-22) ///< Operation requires write mode but context is read-only. +#define AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER (-23) ///< Failure writing block header. +#define AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA (-24) ///< Failure writing block payload. +#define AARUF_ERROR_CANNOT_SET_DDT_ENTRY (-25) ///< Failed to encode/store a DDT entry (overflow or IO). +/** @} */ + +/** \name Non-fatal sector status codes (non-negative) + * Returned through output parameters to describe individual sector state. + * @{ */ +#define AARUF_STATUS_OK 0 ///< Sector present and read without uncorrectable errors. +#define AARUF_STATUS_SECTOR_NOT_DUMPED 1 ///< Sector not captured (gap / missing / intentionally skipped). +#define AARUF_STATUS_SECTOR_WITH_ERRORS 2 ///< Sector present but with unrecoverable or flagged errors. +#define AARUF_STATUS_SECTOR_DELETED 3 ///< Sector logically marked deleted (e.g. filesystem deleted area). + +/** @} */ + +/** \brief Convert an AaruFormat error or status code to a static human-readable string. + * + * Designed for diagnostics / logging; returns a constant string literal. Unknown codes yield + * "Unknown error/status". This helper is inline to avoid adding a separate translation unit. + * + * \param code Error (<0) or status (>=0) numeric code. + * \return Constant C string describing the code. + */ +static inline const char *aaruformat_error_string(int code) +{ + switch(code) + { + /* Errors */ + case AARUF_ERROR_NOT_AARUFORMAT: + return "Not an AaruFormat image"; + case AARUF_ERROR_FILE_TOO_SMALL: + return "File too small"; + case AARUF_ERROR_INCOMPATIBLE_VERSION: + return "Incompatible image version"; + case AARUF_ERROR_CANNOT_READ_INDEX: + return "Cannot read index"; + case AARUF_ERROR_SECTOR_OUT_OF_BOUNDS: + return "Sector out of bounds"; + case AARUF_ERROR_CANNOT_READ_HEADER: + return "Cannot read header"; + case AARUF_ERROR_CANNOT_READ_BLOCK: + return "Cannot read block"; + case AARUF_ERROR_UNSUPPORTED_COMPRESSION: + return "Unsupported compression"; + case AARUF_ERROR_NOT_ENOUGH_MEMORY: + return "Not enough memory"; + case AARUF_ERROR_BUFFER_TOO_SMALL: + return "Buffer too small"; + case AARUF_ERROR_MEDIA_TAG_NOT_PRESENT: + return "Media tag not present"; + case AARUF_ERROR_INCORRECT_MEDIA_TYPE: + return "Incorrect media type"; + case AARUF_ERROR_TRACK_NOT_FOUND: + return "Track not found"; + case AARUF_ERROR_REACHED_UNREACHABLE_CODE: + return "Internal unreachable code reached"; + case AARUF_ERROR_INVALID_TRACK_FORMAT: + return "Invalid track format"; + case AARUF_ERROR_SECTOR_TAG_NOT_PRESENT: + return "Sector tag not present"; + case AARUF_ERROR_CANNOT_DECOMPRESS_BLOCK: + return "Cannot decompress block"; + case AARUF_ERROR_INVALID_BLOCK_CRC: + return "Invalid block CRC"; + case AARUF_ERROR_CANNOT_CREATE_FILE: + return "Cannot create file"; + case AARUF_ERROR_INVALID_APP_NAME_LENGTH: + return "Invalid application name length"; + case AARUF_ERROR_CANNOT_WRITE_HEADER: + return "Cannot write header"; + case AARUF_READ_ONLY: + return "Read-only context"; + case AARUF_ERROR_CANNOT_WRITE_BLOCK_HEADER: + return "Cannot write block header"; + case AARUF_ERROR_CANNOT_WRITE_BLOCK_DATA: + return "Cannot write block data"; + case AARUF_ERROR_CANNOT_SET_DDT_ENTRY: + return "Cannot set DDT entry"; + + /* Status */ + case AARUF_STATUS_OK: + return "OK"; + case AARUF_STATUS_SECTOR_NOT_DUMPED: + return "Sector not dumped"; + case AARUF_STATUS_SECTOR_WITH_ERRORS: + return "Sector with errors"; + case AARUF_STATUS_SECTOR_DELETED: + return "Sector deleted"; + } + return "Unknown error/status"; +} #endif // LIBAARUFORMAT_ERRORS_H diff --git a/include/aaruformat/hash_map.h b/include/aaruformat/hash_map.h index 787e6e6..c8484e1 100644 --- a/include/aaruformat/hash_map.h +++ b/include/aaruformat/hash_map.h @@ -22,22 +22,40 @@ #include #include +/** \struct kv_pair_t + * \brief Single key/value slot used internally by the open-addressing hash map. + * + * Collision resolution strategy (implementation detail): linear or quadratic probing (see source). An empty + * slot is typically represented by a key sentinel (e.g. 0 or another reserved value) – callers never interact + * with individual kv_pair_t entries directly; they are managed through the map API. + */ typedef struct { - uint64_t key; - uint64_t value; + uint64_t key; ///< Stored key (64-bit). May use a reserved sentinel to denote an empty slot. + uint64_t value; ///< Associated value payload (64-bit) stored alongside the key. } kv_pair_t; +/** \struct hash_map_t + * \brief Minimal open-addressing hash map for 64-bit key/value pairs used in deduplication lookup. + * + * Fields: + * - table: Pointer to contiguous array of kv_pair_t entries (capacity == size). + * - size: Total number of slots allocated in table (must be >= 1). + * - count: Number of occupied (non-empty) slots currently in use. + * + * Load factor guidance: insert performance degrades as count approaches size; callers may rebuild with a larger + * size when (count * 10 / size) exceeds a chosen threshold (e.g. 70 – 80%). No automatic resizing is performed. + */ typedef struct { - kv_pair_t *table; - size_t size; - size_t count; + kv_pair_t *table; ///< Array of key/value slots of length == size. + size_t size; ///< Allocated slot capacity of table. + size_t count; ///< Number of active (filled) entries. } hash_map_t; hash_map_t *create_map(size_t size); -void free_map(hash_map_t *map); -bool insert_map(hash_map_t *map, uint64_t key, uint64_t value); -bool lookup_map(const hash_map_t *map, uint64_t key, uint64_t *out_value); +void free_map(hash_map_t *map); +bool insert_map(hash_map_t *map, uint64_t key, uint64_t value); +bool lookup_map(const hash_map_t *map, uint64_t key, uint64_t *out_value); #endif // LIBAARUFORMAT_HASH_MAP_H diff --git a/include/aaruformat/lru.h b/include/aaruformat/lru.h index 8244e4b..66d5a05 100644 --- a/include/aaruformat/lru.h +++ b/include/aaruformat/lru.h @@ -8,49 +8,49 @@ #include #include +/** \struct CacheEntry + * \brief Single hash entry in the in-memory cache. + * + * This structure is managed by uthash (open addressing with chaining semantics provided by macros). + * It represents one key/value association tracked by the cache. The cache implementation supports + * both string keys (null-terminated) and 64-bit numeric keys; numeric keys are stored by casting + * to a temporary string buffer upstream (see implementation). Callers do not allocate or free + * individual entries directly; use the cache API helpers. + * + * Lifetime & ownership: + * - key points either to a heap-allocated C string owned by the cache or to a short-lived buffer + * duplicated internally; callers must not free it after insertion. + * - value is an opaque pointer supplied by caller; the cache does not take ownership of the pointee + * (caller remains responsible for the underlying object unless documented otherwise). + */ struct CacheEntry { - char *key; - void *value; - UT_hash_handle hh; + char *key; ///< Null-terminated key string (unique within the cache). May encode numeric keys. + void *value; ///< Opaque value pointer associated with key (not freed automatically on eviction/clear). + UT_hash_handle hh; ///< uthash handle linking this entry into the hash table (must remain last or per uthash docs). }; +/** \struct CacheHeader + * \brief Cache top-level descriptor encapsulating the hash table root and capacity limit. + * + * The cache enforces an upper bound (max_items) on the number of tracked entries. Insert helpers are expected + * to evict (or refuse) when the limit is exceeded (strategy defined in implementation; current behavior may be + * simple non-evicting if not yet implemented as a true LRU). The cache pointer holds the uthash root (NULL when + * empty). + * + * Fields: + * - max_items: Maximum number of entries allowed; 0 means "no explicit limit" if accepted by implementation. + * - cache: uthash root pointer; NULL when the cache is empty. + */ struct CacheHeader { - uint64_t max_items; - struct CacheEntry *cache; + uint64_t max_items; ///< Hard limit for number of entries (policy: enforce/ignore depends on implementation). + struct CacheEntry *cache; ///< Hash root (uthash). NULL when empty. }; -/** - * Finds an item in the specified cache - * @param cache Pointer to the cache header - * @param key Key - * @return Value if found, NULL if not - */ void *find_in_cache(struct CacheHeader *cache, const char *key); - -/** - * Adds an item to the specified cache - * @param cache Pointer to the cache header - * @param key Key - * @param value Value - */ -void add_to_cache(struct CacheHeader *cache, const char *key, void *value); - -/** - * Finds an item in the specified cache using a 64-bit integer key - * @param cache Pointer to the cache header - * @param key Key - * @return Value if found, NULL if not - */ +void add_to_cache(struct CacheHeader *cache, const char *key, void *value); void *find_in_cache_uint64(struct CacheHeader *cache, uint64_t key); - -/** - * Adds an item to the specified cache using a 64-bit integer key - * @param cache Pointer to the cache header - * @param key Key - * @param value Value - */ -void add_to_cache_uint64(struct CacheHeader *cache, uint64_t key, void *value); +void add_to_cache_uint64(struct CacheHeader *cache, uint64_t key, void *value); #endif // LIBAARUFORMAT_LRU_H diff --git a/include/aaruformat/structs/checksum.h b/include/aaruformat/structs/checksum.h index 43d6753..a9a2646 100644 --- a/include/aaruformat/structs/checksum.h +++ b/include/aaruformat/structs/checksum.h @@ -19,29 +19,80 @@ #ifndef LIBAARUFORMAT_CHECKSUM_H #define LIBAARUFORMAT_CHECKSUM_H +#include // Fixed-width integer types for on-disk structures. + #pragma pack(push, 1) /** - * Checksum block, contains a checksum of all user data sectors (except for optical discs that is 2352 uint8_ts raw - * sector if available - * */ -typedef struct ChecksumHeader { - /**Identifier, */ - uint32_t identifier; - /**Length in uint8_ts of the block */ - uint32_t length; - /**How many checksums follow */ - uint8_t entries; + * \file aaruformat/structs/checksum.h + * \brief On-disk layout definitions for the checksum block (BlockType::ChecksumBlock). + * + * A checksum block stores one or more whole-image (user data) checksums. For optical media the + * user data definition follows the format's raw sector rules (e.g. 2352-byte raw sector when available). + * + * Binary layout (all integers are little-endian, structure is packed): + * + * +------------------------------+-------------------------------+ + * | Field | Size (bytes) | + * +==============================+===============================+ + * | ChecksumHeader | sizeof(ChecksumHeader)=9 | + * | identifier | 4 (BlockType::ChecksumBlock) | + * | length | 4 (payload bytes that follow)| + * | entries | 1 (number of checksum entries)| + * +------------------------------+-------------------------------+ + * | Repeated for each entry: | + * | ChecksumEntry | sizeof(ChecksumEntry)=5 | + * | type | 1 (ChecksumAlgorithm) | + * | length | 4 (digest length) | + * | digest bytes | length | + * +------------------------------+-------------------------------+ + * + * Thus, the payload size (ChecksumHeader.length) MUST equal the sum over all entries of: + * sizeof(ChecksumEntry) + entry.length. + * + * Typical digest lengths: + * - Md5: 16 bytes + * - Sha1: 20 bytes + * - Sha256: 32 bytes + * - SpamSum: variable length ASCII, NOT null-terminated on disk (a terminating '\0' may be appended in memory). + * + * \warning The structures are packed; never rely on host compiler default padding or directly casting from a buffer + * without ensuring correct endianness if porting to big-endian systems (current implementation assumes LE). + * + * \see BlockType + * \see ChecksumAlgorithm + */ + +/** + * \struct ChecksumHeader + * \brief Header that precedes the sequence of checksum entries for a checksum block. + * + * After this header, exactly \ref ChecksumHeader::length bytes follow containing \ref ChecksumHeader::entries + * consecutive \ref ChecksumEntry records, each immediately followed by its digest payload. + */ +typedef struct ChecksumHeader +{ + uint32_t identifier; ///< Block identifier, must be BlockType::ChecksumBlock. + uint32_t length; ///< Length in bytes of the payload (all entries + their digest data, excluding this header). + uint8_t entries; ///< Number of checksum entries that follow in the payload. } ChecksumHeader; -/**Checksum entry, followed by checksum data itself */ -typedef struct ChecksumEntry { - /**Checksum algorithm */ - uint8_t type; - /**Length in uint8_ts of checksum that follows this structure */ - uint32_t length; +/** + * \struct ChecksumEntry + * \brief Per-checksum metadata immediately followed by the digest / signature bytes. + * + * For fixed-length algorithms the \ref length MUST match the known digest size. For SpamSum it is variable. + * The bytes immediately following this structure (not null-terminated) constitute the digest and are exactly + * \ref length bytes long. + * + * Order of entries is not mandated; readers should scan all entries and match by \ref type. + */ +typedef struct ChecksumEntry +{ + uint8_t type; ///< Algorithm used (value from \ref ChecksumAlgorithm). + uint32_t length; ///< Length in bytes of the digest that immediately follows this structure. } ChecksumEntry; #pragma pack(pop) -#endif //LIBAARUFORMAT_CHECKSUM_H +#endif // LIBAARUFORMAT_CHECKSUM_H diff --git a/include/aaruformat/structs/data.h b/include/aaruformat/structs/data.h index 0b9b259..d374e59 100644 --- a/include/aaruformat/structs/data.h +++ b/include/aaruformat/structs/data.h @@ -19,37 +19,82 @@ #ifndef LIBAARUFORMAT_DATA_H #define LIBAARUFORMAT_DATA_H +#include // Fixed width integer types used in on-disk packed structs. + #pragma pack(push, 1) -/**Block header, precedes block data */ -typedef struct BlockHeader { - /**Identifier, */ - uint32_t identifier; - /**Type of data contained by this block */ - uint16_t type; - /**Compression algorithm used to compress the block */ - uint16_t compression; - /**Size in uint8_ts of each sector contained in this block */ - uint32_t sectorSize; - /**Compressed length for the block */ - uint32_t cmpLength; - /**Uncompressed length for the block */ - uint32_t length; - /**CRC64-ECMA of the compressed block */ - uint64_t cmpCrc64; - /**CRC64-ECMA of the uncompressed block */ - uint64_t crc64; +/** + * \file aaruformat/structs/data.h + * \brief On-disk layout structures for data-bearing and geometry blocks. + * + * These packed structures describe the headers that precede variable-length payloads + * inside blocks whose identifiers are enumerated in \ref BlockType. + * All integer fields are stored little-endian on disk. The library currently assumes a + * little-endian host; if ported to a big-endian architecture explicit byte swapping will be required. + * + * Layout of a data block (BlockType::DataBlock): + * BlockHeader (sizeof(BlockHeader) bytes) + * Compressed payload (cmpLength bytes) + * + * Payload decoding: + * - Apply the algorithm indicated by \ref BlockHeader::compression (\ref CompressionType) to the + * cmpLength bytes following the header to obtain exactly \ref BlockHeader::length bytes. + * - The uncompressed data MUST be an integer multiple of \ref BlockHeader::sectorSize. + * - A CRC64-ECMA is provided for both compressed (cmpCrc64) and uncompressed (crc64) forms to allow + * validation at either stage of the pipeline. + * + * Geometry block (BlockType::GeometryBlock) has a \ref GeometryBlockHeader followed by no additional + * fixed payload in the current format version; it conveys legacy CHS-style logical geometry metadata. + * + * \warning These structs are packed; do not take their address and assume natural alignment. + * \see BlockType + * \see DataType + * \see CompressionType + */ + +/** + * \struct BlockHeader + * \brief Header preceding the compressed data payload of a data block (BlockType::DataBlock). + * + * Invariants: + * - cmpLength > 0 unless length == 0 (empty block) + * - length == 0 implies cmpLength == 0 + * - If compression == CompressionType::None then cmpLength == length + * - length % sectorSize == 0 + * + * Validation strategy (recommended for readers): + * 1. Verify identifier == BlockType::DataBlock. + * 2. Verify sectorSize is non-zero and a power-of-two or a commonly used size (512/1024/2048/4096/2352). + * 3. Verify invariants above and CRCs after (de)compression. + */ +typedef struct BlockHeader +{ + uint32_t identifier; ///< Block identifier, must be BlockType::DataBlock. + uint16_t type; ///< Logical data classification (value from \ref DataType). + uint16_t compression; ///< Compression algorithm used (value from \ref CompressionType). + uint32_t sectorSize; ///< Size in bytes of each logical sector represented in this block. + uint32_t cmpLength; ///< Size in bytes of the compressed payload immediately following this header. + uint32_t length; ///< Size in bytes of the uncompressed payload resulting after decompression. + uint64_t cmpCrc64; ///< CRC64-ECMA of the compressed payload (cmpLength bytes). + uint64_t crc64; ///< CRC64-ECMA of the uncompressed payload (length bytes). } BlockHeader; -/**Geometry block, contains physical geometry information */ -typedef struct GeometryBlockHeader { - /**Identifier, */ - uint32_t identifier; - uint32_t cylinders; - uint32_t heads; - uint32_t sectorsPerTrack; +/** + * \struct GeometryBlockHeader + * \brief Legacy CHS style logical geometry metadata (BlockType::GeometryBlock). + * + * Total logical sectors implied by this header is cylinders * heads * sectorsPerTrack. + * Sector size is not included here and must be derived from context (e.g., accompanying metadata + * or defaulting to 512 for many block devices). + */ +typedef struct GeometryBlockHeader +{ + uint32_t identifier; ///< Block identifier, must be BlockType::GeometryBlock. + uint32_t cylinders; ///< Number of cylinders. + uint32_t heads; ///< Number of heads (tracks per cylinder). + uint32_t sectorsPerTrack; ///< Number of sectors per track. } GeometryBlockHeader; #pragma pack(pop) -#endif //LIBAARUFORMAT_DATA_H +#endif // LIBAARUFORMAT_DATA_H diff --git a/include/aaruformat/structs/ddt.h b/include/aaruformat/structs/ddt.h index 3c5c8b0..eebc94e 100644 --- a/include/aaruformat/structs/ddt.h +++ b/include/aaruformat/structs/ddt.h @@ -19,71 +19,149 @@ #ifndef LIBAARUFORMAT_DDT_H #define LIBAARUFORMAT_DDT_H +#include // fixed-width types for on-disk layout + #pragma pack(push, 1) -/**Header for a deduplication table. Table follows it */ +/** \file aaruformat/structs/ddt.h + * \brief On-disk headers for Deduplication Data Tables (DDT) versions 1 and 2. + * + * A DDT maps logical sector indices (LBAs within an image's logical address space) to (block, sector) + * pairs plus a base file offset, enabling content de-duplication inside the container. Two generations + * exist: + * - DdtHeader ("version 1") flat table. + * - DdtHeader2 ("version 2") hierarchical, multi-level subtables for scalability. + * + * All integers are little-endian. Structures are packed (1-byte alignment). When porting to a big-endian + * architecture callers must perform byte swapping. Do not rely on compiler-introduced padding. + * + * Compression of the table body (entries array) follows the same conventions as data blocks: first + * decompress according to the compression enum, then validate CRC64 for uncompressed contents. + * + * Related enumerations: + * - BlockType::DeDuplicationTable / BlockType::DeDuplicationTable2 + * - CompressionType + * - DataType + * - DdtSizeType (for DdtHeader2::sizeType) + */ + +/** + * \struct DdtHeader + * \brief Header preceding a version 1 (flat) deduplication table body. + * + * Immediately after this header there are \ref entries table records (compressed if \ref compression != None). + * Each table record encodes a pointer using an 8-bit file offset component and a sector offset inside a block: + * logicalEntryValue = ((uint64_t)fileByteOffset << shift) + sectorOffsetWithinBlock + * where fileByteOffset is measured in bytes (granularity depends on shift) and sectorOffsetWithinBlock is + * relative to the start of the referenced data block. The sector size must be taken from the corresponding + * data block(s) (see BlockHeader::sectorSize) or higher-level metadata. + * + * Invariants: + * - cmpLength == length if compression == CompressionType::None + * - length % (entrySize) == 0 after decompression (implementation-defined entry size) + * - entries * entrySize == length + * - entries > 0 implies length > 0 + */ typedef struct DdtHeader { - /**Identifier, */ - uint32_t identifier; - /**Type of data pointed by this DDT */ - uint16_t type; - /**Compression algorithm used to compress the DDT */ - uint16_t compression; - /**Each entry is ((uint8_t offset in file) << shift) + (sector offset in block) */ - uint8_t shift; - /**How many entries are in the table */ - uint64_t entries; - /**Compressed length for the DDT */ - uint64_t cmpLength; - /**Uncompressed length for the DDT */ - uint64_t length; - /**CRC64-ECMA of the compressed DDT */ - uint64_t cmpCrc64; - /**CRC64-ECMA of the uncompressed DDT */ - uint64_t crc64; + uint32_t identifier; ///< Block identifier, must be BlockType::DeDuplicationTable. + uint16_t type; ///< Data classification (\ref DataType) for sectors referenced by this table. + uint16_t compression; ///< Compression algorithm for the table body (\ref CompressionType). + uint8_t shift; ///< Left shift applied to per-entry file offset component forming logicalEntryValue. + uint64_t entries; ///< Number of deduplication entries contained in (uncompressed) table. + uint64_t cmpLength; ///< Size in bytes of compressed entries payload. + uint64_t length; ///< Size in bytes of uncompressed entries payload. + uint64_t cmpCrc64; ///< CRC64-ECMA of the compressed payload. + uint64_t crc64; ///< CRC64-ECMA of the uncompressed payload. } DdtHeader; +/** + * \struct DdtHeader2 + * \brief Header preceding a version 2 hierarchical deduplication table. + * + * Version 2 introduces multi-level tables to efficiently address very large images by subdividing + * the logical address space. Tables at higher levels partition regions; leaves contain direct + * (block, sector) entry mappings. Navigation uses \ref tableLevel (0 = root) and \ref levels (total depth). + * + * Logical sector (LBA) mapping (actual implementation in decode_ddt_{single,multi}_level_v2): + * 1. Let L be the requested logical sector (can be negative externally). Internal index I = L + negative. + * Valid range: 0 <= I < blocks. (Total user-data sectors often = blocks - negative - overflow.) + * 2. If tableShift == 0 (single-level): entryIndex = I. + * Else (multi-level): + * itemsPerPrimaryEntry = 1 << tableShift + * primaryIndex = I / itemsPerPrimaryEntry + * secondaryIndex = I % itemsPerPrimaryEntry + * The primary table entry at primaryIndex yields a secondary DDT file offset (scaled by 2^blockAlignmentShift), + * whose table entries are then indexed by secondaryIndex. + * 3. Read raw DDT entry value E (16-bit if sizeType == SmallDdtSizeType, 32-bit if BigDdtSizeType). + * 4. If E == 0: sector_status = SectorStatusNotDumped; offset=block_offset=0. + * Otherwise extract: + * statusBits = E >> 12 (small) or E >> 28 (big) + * baseBits = E & 0x0FFF (small) or E & 0x0FFFFFFF (big) + * sectorOffsetWithinBlock = baseBits & ((1 << dataShift) - 1) + * blockIndex = baseBits >> dataShift + * block_offset (bytes) = blockIndex << blockAlignmentShift + * offset (sector units inside block) = sectorOffsetWithinBlock + * 5. The consumer combines block_offset, offset, and the (external) logical sector size to locate data. + * + * Field roles: + * - negative: Count of leading negative LBAs supported; added to L to form internal index. + * - overflow: Count of trailing LBAs beyond the user area upper bound that are still dumped and have + * normal DDT entries (e.g. optical disc lead-out). Symmetrical to 'negative' on the high end. + * - start: For secondary tables, base internal index covered (written when creating new tables). Current decoding + * logic does not consult this field (future-proof placeholder). + * - blockAlignmentShift: log2 alignment of stored data blocks (byte granularity of block_offset). + * - dataShift: log2 of the number of addressable sectors per increment of blockIndex bitfield unit. + * - tableShift: log2 of number of logical sectors covered by a single primary-table pointer (multi-level only). + * - sizeType: Selects entry width (small=16b, big=32b) impacting available bits for blockIndex+offset. + * + * Notes & current limitations: + * - User area sector count = blocks - negative - overflow. + * - Valid external LBA range exposed by the image = [-negative, (blocks - negative - 1)]. + * * Negative range: [-negative, -1] + * * User area range: [0, (blocks - negative - overflow - 1)] + * * Overflow range: [(blocks - negative - overflow), (blocks - negative - 1)] + * - Both negative and overflow ranges are stored with normal DDT entries (if present), enabling complete + * reproduction of lead-in / lead-out or similar padding regions. + * - start is presently ignored during decoding; integrity checks against it may be added in future revisions. + * - No masking is applied to I besides array bounds; callers must ensure L is within representable range. + * + * Example (Compact Disc): + * Disc has 360000 user sectors. Lead-in captured as 15000 negative sectors and lead-out as 15000 overflow sectors. + * negative = 15000 + * overflow = 15000 + * user sectors = 360000 + * blocks (internal span) = negative + user + overflow = 390000 + * External LBA spans: -15000 .. 374999 + * * Negative: -15000 .. -1 (15000 sectors) + * * User: 0 .. 359999 (360000 sectors) + * * Overflow: 360000 .. 374999 (15000 sectors) + * Internal index I for any external L is I = L + negative. + * User area sector count reported to callers (ctx->imageInfo.Sectors) = blocks - negative - overflow = 360000. + */ typedef struct DdtHeader2 { - /**Identifier, */ - uint32_t identifier; - /**Type of data pointed by this DDT */ - uint16_t type; - /**Compression algorithm used to compress the DDT */ - uint16_t compression; - /**How many levels of subtables are present */ - uint8_t levels; - /**Which level this table belongs to */ - uint8_t tableLevel; - /**Pointer to absolute byte offset in file where the previous level table is located */ - uint64_t previousLevelOffset; - /**Negative displacement of LBAs */ - uint16_t negative; - /**Number of blocks in media */ - uint64_t blocks; - /**Positive overflow displacement of LBAs */ - uint16_t overflow; - /**First LBA contained in this table */ - uint64_t start; - /**Block alignment boundaries */ - uint8_t blockAlignmentShift; - /**Data shift */ - uint8_t dataShift; - /**Table shift */ - uint8_t tableShift; - /**Size type */ - uint8_t sizeType; - /**Entries in this table */ - uint64_t entries; - /**Compressed length for the DDT */ - uint64_t cmpLength; - /**Uncompressed length for the DDT */ - uint64_t length; - /**CRC64-ECMA of the compressed DDT */ - uint64_t cmpCrc64; - /**CRC64-ECMA of the uncompressed DDT */ - uint64_t crc64; + uint32_t identifier; ///< Block identifier, must be BlockType::DeDuplicationTable2. + uint16_t type; ///< Data classification (\ref DataType) for sectors referenced by this table. + uint16_t compression; ///< Compression algorithm for this table body (\ref CompressionType). + uint8_t levels; ///< Total number of hierarchy levels (root depth); > 0. + uint8_t tableLevel; ///< Zero-based level index of this table (0 = root, increases downward). + uint64_t previousLevelOffset; ///< Absolute byte offset of the parent (previous) level table; 0 if root. + uint16_t negative; ///< Leading negative LBA count; added to external L to build internal index. + uint64_t blocks; ///< Total internal span (negative + usable + overflow) in logical sectors. + uint16_t overflow; ///< Trailing dumped sectors beyond user area (overflow range), still mapped with entries. + uint64_t + start; ///< Base internal index covered by this table (used for secondary tables; currently informational). + uint8_t blockAlignmentShift; ///< 2^blockAlignmentShift = block alignment boundary in bytes. + uint8_t dataShift; ///< 2^dataShift = sectors represented per increment in blockIndex field. + uint8_t tableShift; ///< 2^tableShift = number of logical sectors per primary entry (multi-level only; 0 for + ///< single-level or secondary tables). + uint8_t sizeType; ///< Entry size variant (\ref DdtSizeType) controlling width of E. + uint64_t entries; ///< Number of entries contained in (uncompressed) table payload. + uint64_t cmpLength; ///< Compressed payload size in bytes. + uint64_t length; ///< Uncompressed payload size in bytes. + uint64_t cmpCrc64; ///< CRC64-ECMA of compressed table payload. + uint64_t crc64; ///< CRC64-ECMA of uncompressed table payload. } DdtHeader2; #pragma pack(pop) diff --git a/include/aaruformat/structs/dump.h b/include/aaruformat/structs/dump.h index 51f7745..80df6e6 100644 --- a/include/aaruformat/structs/dump.h +++ b/include/aaruformat/structs/dump.h @@ -19,42 +19,109 @@ #ifndef LIBAARUFORMAT_DUMP_H #define LIBAARUFORMAT_DUMP_H +#include /* Fixed-width integer types for on‑disk packed structures */ + #pragma pack(push, 1) -/**Dump hardware block, contains a list of hardware used to dump the media on this image */ -typedef struct DumpHardwareHeader { - /**Identifier, */ - uint32_t identifier; - /**How many entries follow this header */ - uint16_t entries; - /**Size of the whole block, not including this header, in uint8_ts */ - uint32_t length; - /**CRC64-ECMA of the block */ - uint64_t crc64; +/** \file aaruformat/structs/dump.h + * \brief Packed on-disk structures describing hardware and software used during image acquisition. + * + * A Dump Hardware block (identifier = BlockType::DumpHardwareBlock) records one or more dump "environments" – + * typically combinations of a physical device (drive, controller, adapter) and the software stack that + * performed the read operation. Each environment is represented by a \ref DumpHardwareEntry followed by a + * sequence of UTF‑8 strings and an optional array of extent ranges (\ref DumpExtent, defined in context.h) that + * delimit portions of the medium this environment contributed to. + * + * Binary layout (little-endian, packed, all multi-byte integers LE): + * + * DumpHardwareHeader (sizeof = 16 bytes) + * identifier (4) -> BlockType::DumpHardwareBlock + * entries (2) -> number of following hardware entries + * length (4) -> total bytes of payload that follow this header + * crc64 (8) -> CRC64-ECMA of the payload bytes + * + * Repeated for i in [0, entries): + * DumpHardwareEntry (36 bytes) + * manufacturerLength (4) + * modelLength (4) + * revisionLength (4) + * firmwareLength (4) + * serialLength (4) + * softwareNameLength (4) + * softwareVersionLength (4) + * softwareOperatingSystemLength (4) + * extents (4) -> number of DumpExtent structs after the strings + * + * Variable-length UTF-8 strings (not NUL-terminated on disk) appear immediately after the entry, in the + * exact order of the length fields above; each string is present only if its length > 0. The reader allocates + * an extra byte to append '\0' for in-memory convenience. + * + * Array of 'extents' DumpExtent structures (each 16 bytes: start, end) follows the strings if extents > 0. + * The semantic of each extent is an inclusive [start, end] logical sector (or unit) range contributed by + * this hardware/software combination. + * + * CRC semantics: + * - crc64 covers exactly 'length' bytes immediately following the header. + * - For legacy images with header.imageMajorVersion <= AARUF_VERSION_V1 the original C# writer produced a + * byte-swapped CRC; the library compensates internally (see process_dumphw_block()). + * + * Invariants / validation recommendations: + * - identifier == BlockType::DumpHardwareBlock + * - Accumulated size of all (entry + strings + extents arrays) == length + * - All length fields are trusted only after bounds checking against remaining payload bytes + * - Strings are raw UTF-8 data with no implicit terminator + * - extents * sizeof(DumpExtent) fits inside remaining payload + * + * Memory management notes (runtime library): + * - Each string is malloc'ed with +1 byte for terminator during processing. + * - Extents array is malloc'ed per entry when extents > 0. + * - See aaruformatContext::dumpHardwareEntriesWithData for owning pointers. + * + * \warning Structures are packed; never rely on natural alignment when mapping from a byte buffer. + * \see DumpHardwareHeader + * \see DumpHardwareEntry + * \see DumpExtent (in context.h) + * \see BlockType + */ + +/** \struct DumpHardwareHeader + * \brief Header that precedes a sequence of dump hardware entries and their variable-length payload. + */ +typedef struct DumpHardwareHeader +{ + uint32_t identifier; ///< Block identifier, must be BlockType::DumpHardwareBlock. + uint16_t entries; ///< Number of DumpHardwareEntry records that follow. + uint32_t length; ///< Total payload bytes after this header (sum of entries, strings, and extents arrays). + uint64_t crc64; ///< CRC64-ECMA of the payload (byte-swapped for legacy v1 images, handled automatically). } DumpHardwareHeader; -/**Dump hardware entry, contains length of strings that follow, in the same order as the length, this structure */ -typedef struct DumpHardwareEntry { - /**Length of UTF-8 manufacturer string */ - uint32_t manufacturerLength; - /**Length of UTF-8 model string */ - uint32_t modelLength; - /**Length of UTF-8 revision string */ - uint32_t revisionLength; - /**Length of UTF-8 firmware version string */ - uint32_t firmwareLength; - /**Length of UTF-8 serial string */ - uint32_t serialLength; - /**Length of UTF-8 software name string */ - uint32_t softwareNameLength; - /**Length of UTF-8 software version string */ - uint32_t softwareVersionLength; - /**Length of UTF-8 software operating system string */ - uint32_t softwareOperatingSystemLength; - /**How many extents are after the strings */ - uint32_t extents; +/** \struct DumpHardwareEntry + * \brief Per-environment length table describing subsequent UTF-8 strings and optional extent array. + * + * Immediately after this structure the variable-length UTF‑8 strings appear in the documented order, each + * present only if its corresponding length is non-zero. No padding is present between strings. When all + * strings are consumed, an array of \ref DumpExtent follows if \ref extents > 0. + * + * All length fields measure bytes (not characters) and exclude any in-memory NUL terminator added by the reader. + * + * Typical semantics: + * - manufacturer/model/revision/firmware/serial identify the hardware device. + * - softwareName/softwareVersion/softwareOperatingSystem identify the acquisition software environment. + * - extents list which logical ranges this environment actually dumped (useful for multi-device composites). + */ +typedef struct DumpHardwareEntry +{ + uint32_t manufacturerLength; ///< Length in bytes of manufacturer UTF-8 string. + uint32_t modelLength; ///< Length in bytes of model UTF-8 string. + uint32_t revisionLength; ///< Length in bytes of revision / hardware revision string. + uint32_t firmwareLength; ///< Length in bytes of firmware version string. + uint32_t serialLength; ///< Length in bytes of device serial number string. + uint32_t softwareNameLength; ///< Length in bytes of dumping software name string. + uint32_t softwareVersionLength; ///< Length in bytes of dumping software version string. + uint32_t softwareOperatingSystemLength; ///< Length in bytes of host operating system string. + uint32_t extents; ///< Number of DumpExtent records following the strings (0 = none). } DumpHardwareEntry; #pragma pack(pop) -#endif //LIBAARUFORMAT_DUMP_H +#endif // LIBAARUFORMAT_DUMP_H diff --git a/include/aaruformat/structs/header.h b/include/aaruformat/structs/header.h index 71d7132..588279d 100644 --- a/include/aaruformat/structs/header.h +++ b/include/aaruformat/structs/header.h @@ -19,73 +19,111 @@ #ifndef LIBAARUFORMAT_HEADER_H #define LIBAARUFORMAT_HEADER_H -#define AARU_HEADER_APP_NAME_LEN 64 -#define GUID_SIZE 16 +/** \file aaruformat/structs/header.h + * \brief On-disk container header structures (v1 and v2) for Aaru images. + * + * These packed headers appear at the very beginning (offset 0) of every Aaru image file and + * advertise container format version, creator application, indexing offset and optional extended + * feature capability bitfields (v2+). All multi-byte integers are little-endian. Strings stored + * in the fixed-size application field are UTF‑16LE and zero padded (not necessarily NUL-terminated + * if fully filled). The GUID field (v2) allows derivative / child images to reference an origin. + * + * Version progression: + * - v1: \ref AaruHeader (no GUID, no alignment or shift metadata, no feature bitfields). + * - v2: \ref AaruHeaderV2 introduces GUID, block/data/table shift hints (mirroring DDT metadata), + * and three 64‑bit feature bitmaps to negotiate reader/writer compatibility. + * + * Compatibility handling (recommended logic for consumers): + * 1. If any bit set in featureIncompatible is not implemented by the reader: abort (cannot safely read/write). + * 2. Else if any bit set in featureCompatibleRo is not implemented: allow read‑only operations. + * 3. Bits only present in featureCompatible but not implemented MAY be ignored for both read/write while + * still preserving round‑trip capability (writer should not clear unknown bits when re‑saving). + * + * Alignment & shift semantics (duplicated here for quick reference, see DdtHeader2 for full details): + * - blockAlignmentShift: underlying blocks are aligned to 2^blockAlignmentShift bytes. + * - dataShift: data pointer / DDT entry low bits encode offsets modulo 2^dataShift sectors/items. + * - tableShift: primary DDT entries span 2^tableShift logical sectors (0 implies single-level tables). + * + * Invariants: + * - identifier == AARU_MAGIC (external constant; not defined here). + * - For v1: sizeof(AaruHeader) exact and indexOffset > 0 (indexOffset == 0 => corrupt/unreadable image). + * - For v2: sizeof(AaruHeaderV2) exact; indexOffset > 0; blockAlignmentShift, dataShift, tableShift within + * sane bounds (e.g. < 63). Zero is permissible only for the shift fields (not for indexOffset). + * + * Security / robustness considerations: + * - Always bounds-check indexOffset against file size before seeking. + * - Treat application field as untrusted UTF‑16LE; validate surrogate pairs if necessary. + * - Unknown feature bits MUST be preserved if a file is rewritten to avoid capability loss. + */ + +#define AARU_HEADER_APP_NAME_LEN 64 /**< Size in bytes (UTF-16LE) of application name field (32 UTF-16 code units). */ +#define GUID_SIZE 16 /**< Size in bytes of GUID / UUID-like binary identifier. */ #pragma pack(push, 1) -/**Header, at start of file */ -typedef struct AaruHeader { - /**Header identifier, */ - uint64_t identifier; - /**UTF-16LE name of the application that created the image */ - uint8_t application[AARU_HEADER_APP_NAME_LEN]; - /**Image format major version. A new major version means a possibly incompatible change of format */ - uint8_t imageMajorVersion; - /**Image format minor version. A new minor version indicates a compatible change of format */ - uint8_t imageMinorVersion; - /**Major version of the application that created the image */ - uint8_t applicationMajorVersion; - /**Minor version of the application that created the image */ - uint8_t applicationMinorVersion; - /**Type of media contained on image */ - uint32_t mediaType; - /**Offset to index */ - uint64_t indexOffset; - /**Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image creation time */ - int64_t creationTime; - /**Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image last written time */ - int64_t lastWrittenTime; +/** \struct AaruHeader + * \brief Version 1 container header placed at offset 0 for legacy / initial format. + * + * Field summary: + * - identifier: magic signature (AARU_MAGIC) identifying the container. + * - application: UTF‑16LE creator application name (fixed 64 bytes, zero padded). + * - imageMajorVersion / imageMinorVersion: container format version of the file itself (not the app). + * - applicationMajorVersion / applicationMinorVersion: version of the creating application. + * - mediaType: media type enumeration (\ref MediaType). + * - indexOffset: byte offset to the first index block (must be > 0). + * - creationTime / lastWrittenTime: 64-bit Windows FILETIME timestamps (100 ns intervals since 1601-01-01 UTC). + */ +typedef struct AaruHeader +{ + uint64_t identifier; ///< File magic (AARU_MAGIC). + uint8_t application[AARU_HEADER_APP_NAME_LEN]; ///< UTF-16LE creator application name (fixed-size buffer). + uint8_t imageMajorVersion; ///< Container format major version (incompatible changes when incremented). + uint8_t imageMinorVersion; ///< Container format minor version (backward compatible evolutions). + uint8_t applicationMajorVersion; ///< Creator application major version. + uint8_t applicationMinorVersion; ///< Creator application minor / patch version. + uint32_t mediaType; ///< Media type enumeration (value from \ref MediaType). + uint64_t indexOffset; ///< Absolute byte offset to primary index block (MUST be > 0; 0 => corrupt/unreadable). + int64_t creationTime; ///< Creation FILETIME (100 ns since 1601-01-01 UTC). + int64_t lastWrittenTime; ///< Last modification FILETIME (100 ns since 1601-01-01 UTC). } AaruHeader; -/**Header, at start of file */ -typedef struct AaruHeaderV2 { - /**Header identifier, see AARU_MAGIC */ - uint64_t identifier; - /**UTF-16LE name of the application that created the image */ - uint8_t application[AARU_HEADER_APP_NAME_LEN]; - /**Image format major version. A new major version means a possibly incompatible change of format */ - uint8_t imageMajorVersion; - /**Image format minor version. A new minor version indicates a compatible change of format */ - uint8_t imageMinorVersion; - /**Major version of the application that created the image */ - uint8_t applicationMajorVersion; - /**Minor version of the application that created the image */ - uint8_t applicationMinorVersion; - /**Type of media contained on image */ - uint32_t mediaType; - /**Offset to index */ - uint64_t indexOffset; - /**Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image creation time */ - int64_t creationTime; - /**Windows filetime (100 nanoseconds since 1601/01/01 00:00:00 UTC) of image last written time */ - int64_t lastWrittenTime; - /**Unique identifier that allows children images to recognize and find this image.*/ - uint8_t guid[GUID_SIZE]; - /**Block alignment shift. All blocks in the image are aligned at 2 << blockAlignmentShift bytes */ - uint8_t blockAlignmentShift; - /**Data shift. All data blocks in the image contain 2 << dataShift items at most */ - uint8_t dataShift; - /**Table shift. All deduplication tables in the image use this shift to calculate the position of an item */ - uint8_t tableShift; - /**Features used in this image that if unsupported are still compatible for reading and writing implementations */ - uint64_t featureCompatible; - /**Features used in this image that if unsupported are still compatible for reading implementations but not for writing */ - uint64_t featureCompatibleRo; - /**Featured used in this image that if unsupported prevent reading or writing the image*/ - uint64_t featureIncompatible; +/** \struct AaruHeaderV2 + * \brief Version 2 container header with GUID, alignment shifts, and feature negotiation bitmaps. + * + * Additions over v1: + * - guid: stable 128-bit identifier enabling linkage by derivative images. + * - blockAlignmentShift / dataShift / tableShift: global structural hints copied into data & DDT blocks. + * - featureCompatible / featureCompatibleRo / featureIncompatible: capability bitmasks. + * + * Feature bitmask semantics: + * - featureCompatible: Optional features; absence of implementation should not impact R/W correctness. + * - featureCompatibleRo: If unimplemented, image MAY be opened read-only. + * - featureIncompatible: If any bit unimplemented, image MUST NOT be opened (prevent misinterpretation). + * + * Readers should AND their supported bit set with the header masks to decide access level (see file + * documentation). Writers must preserve unknown bits when saving an existing image. + */ +typedef struct AaruHeaderV2 +{ + uint64_t identifier; ///< File magic (AARU_MAGIC). + uint8_t application[AARU_HEADER_APP_NAME_LEN]; ///< UTF-16LE creator application name (fixed 64 bytes). + uint8_t imageMajorVersion; ///< Container format major version. + uint8_t imageMinorVersion; ///< Container format minor version. + uint8_t applicationMajorVersion; ///< Creator application major version. + uint8_t applicationMinorVersion; ///< Creator application minor / patch version. + uint32_t mediaType; ///< Media type enumeration (value from \ref MediaType). + uint64_t indexOffset; ///< Absolute byte offset to primary index block (MUST be > 0; 0 => corrupt/unreadable). + int64_t creationTime; ///< Creation FILETIME (100 ns since 1601-01-01 UTC). + int64_t lastWrittenTime; ///< Last modification FILETIME (100 ns since 1601-01-01 UTC). + uint8_t guid[GUID_SIZE]; ///< 128-bit image GUID (binary, not text); stable across children. + uint8_t blockAlignmentShift; ///< log2 block alignment (block size alignment = 2^blockAlignmentShift bytes). + uint8_t dataShift; ///< log2 sectors/items per block-index increment in DDT entries (2^dataShift). + uint8_t tableShift; ///< log2 sectors spanned by each primary DDT entry (0 = single-level). + uint64_t featureCompatible; ///< Feature bits: unimplemented bits are ignorable (still R/W safe). + uint64_t featureCompatibleRo; ///< Feature bits: unimplemented -> degrade to read-only access. + uint64_t featureIncompatible; ///< Feature bits: any unimplemented -> abort (cannot open safely). } AaruHeaderV2; #pragma pack(pop) -#endif //LIBAARUFORMAT_HEADER_H +#endif // LIBAARUFORMAT_HEADER_H diff --git a/include/aaruformat/structs/index.h b/include/aaruformat/structs/index.h index 8bfca49..fd6ec6d 100644 --- a/include/aaruformat/structs/index.h +++ b/include/aaruformat/structs/index.h @@ -21,50 +21,95 @@ #pragma pack(push, 1) -/**Header for the index, followed by entries */ +/** \file aaruformat/structs/index.h + * \brief On‑disk index block header and entry structures (versions 1, 2 and 3). + * + * The index provides a directory of all blocks contained in an Aaru image. Each index block starts with + * a versioned header (IndexHeader / IndexHeader2 / IndexHeader3) followed by a contiguous array of + * fixed‑size \ref IndexEntry records. Version 3 adds support for hierarchical (chained / nested) subindexes. + * + * Version mapping by block identifier (see \ref BlockType): + * - IndexBlock (v1) -> \ref IndexHeader followed by 16‑bit entry count entries. + * - IndexBlock2 (v2) -> \ref IndexHeader2 followed by 64‑bit entry count entries. + * - IndexBlock3 (v3) -> \ref IndexHeader3 with optional hierarchical subindex references. + * + * CRC coverage & endianness: + * - The crc64 field stores a CRC64-ECMA over the entries array ONLY (header bytes are excluded). + * - For images with imageMajorVersion <= AARUF_VERSION_V1 a legacy writer byte-swapped the CRC; readers + * compensate (see verify_index_v1/v2/v3). The value in the header remains whatever was originally written. + * + * Hierarchical (v3) behavior: + * - Entries whose blockType == IndexBlock3 refer to subindex blocks; readers recursively load and flatten. + * - IndexHeader3::previous can point to a preceding index segment (for append / incremental scenarios) or 0. + * - CRC of the main index does NOT cover subindex contents; each subindex has its own header + CRC. + * + * Invariants / validation recommendations: + * - identifier must equal the expected BlockType variant for that version. + * - entries > 0 implies the entries array byte size == entries * sizeof(IndexEntry). + * - crc64 must match recomputed CRC64( entries array ) (after legacy byte swap handling if required). + * - For v3, if previous != 0 it should point to another IndexBlock3 header (optional best‑effort check). + * + * Notes: + * - Structures are packed (1‑byte alignment). All multi-byte integers are little‑endian on disk. + * - The index does not store per-entry CRC; integrity relies on each individual block's own CRC plus the index CRC. + * - dataType in \ref IndexEntry is meaningful only for block types that carry typed data (e.g. DataBlock, + * DumpHardwareBlock, etc.). + * + * See also: verify_index_v1(), verify_index_v2(), verify_index_v3() for integrity procedures. + */ + +/** \struct IndexHeader + * \brief Index header (version 1) for legacy images (identifier == IndexBlock). + * + * Uses a 16‑bit entry counter limiting the number of indexable blocks in v1. + */ typedef struct IndexHeader { - /**Identifier, */ - uint32_t identifier; - /**How many entries follow this header */ - uint16_t entries; - /**CRC64-ECMA of the index */ - uint64_t crc64; + uint32_t identifier; ///< Block identifier (must be BlockType::IndexBlock). + uint16_t entries; ///< Number of \ref IndexEntry records that follow immediately. + uint64_t crc64; ///< CRC64-ECMA of the entries array (legacy byte-swapped for early images). } IndexHeader; -/**Header for the index, followed by entries */ +/** \struct IndexHeader2 + * \brief Index header (version 2) with 64‑bit entry counter (identifier == IndexBlock2). + * + * Enlarges the entry count field to 64 bits for large images; otherwise structurally identical to v1. + */ typedef struct IndexHeader2 { - /**Identifier, */ - uint32_t identifier; - /**How many entries follow this header */ - uint64_t entries; - /**CRC64-ECMA of the index */ - uint64_t crc64; + uint32_t identifier; ///< Block identifier (must be BlockType::IndexBlock2). + uint64_t entries; ///< Number of \ref IndexEntry records that follow immediately. + uint64_t crc64; ///< CRC64-ECMA of the entries array (legacy byte-swapped rule still applies for old versions). } IndexHeader2; -/**Header for the index, followed by entries */ +/** \struct IndexHeader3 + * \brief Index header (version 3) adding hierarchical chaining (identifier == IndexBlock3). + * + * Supports flattened hierarchical indexes: entries referencing additional IndexBlock3 subindexes. + * The 'previous' pointer allows chaining earlier index segments (e.g., incremental append) enabling + * cumulative discovery without rewriting earlier headers. + */ typedef struct IndexHeader3 { - /**Identifier, */ - uint32_t identifier; - /**How many entries follow this header */ - uint64_t entries; - /**CRC64-ECMA of the index */ - uint64_t crc64; - /**Pointer to the previous index header */ - uint64_t previous; + uint32_t identifier; ///< Block identifier (must be BlockType::IndexBlock3). + uint64_t entries; ///< Number of \ref IndexEntry records that follow in this (sub)index block. + uint64_t crc64; ///< CRC64-ECMA of the local entries array (does NOT cover subindexes or previous chains). + uint64_t previous; ///< File offset of a previous IndexBlock3 header (0 if none / root segment). } IndexHeader3; -/**Index entry */ +/** \struct IndexEntry + * \brief Single index entry describing a block's type, (optional) data classification, and file offset. + * + * Semantics by blockType (see \ref BlockType): + * - DataBlock / GeometryBlock / ChecksumBlock / etc.: dataType conveys specific stored data category (\ref DataType). + * - Deduplication (DDT) or Index blocks: dataType may be ignored or set to a sentinel. + * - IndexBlock3: this entry refers to a subindex; offset points to another IndexHeader3. + */ typedef struct IndexEntry { - /**Type of item pointed by this entry */ - uint32_t blockType; - /**Type of data contained by the block pointed by this entry */ - uint16_t dataType; - /**Offset in file where item is stored */ - uint64_t offset; + uint32_t blockType; ///< Block identifier of the referenced block (value from \ref BlockType). + uint16_t dataType; ///< Data classification (value from \ref DataType) or unused for untyped blocks. + uint64_t offset; ///< Absolute byte offset in the image where the referenced block header begins. } IndexEntry; #pragma pack(pop) diff --git a/include/aaruformat/structs/metadata.h b/include/aaruformat/structs/metadata.h index 2ffcecd..f53ae20 100644 --- a/include/aaruformat/structs/metadata.h +++ b/include/aaruformat/structs/metadata.h @@ -21,73 +21,95 @@ #pragma pack(push, 1) -/**Metadata block, contains metadata */ -typedef struct MetadataBlockHeader { - /**Identifier, */ - uint32_t identifier; - /**Size in uint8_ts of this whole metadata block */ - uint32_t blockSize; - /**Sequence of media set this media belongs to */ - int32_t mediaSequence; - /**Total number of media on the media set this media belongs to */ - int32_t lastMediaSequence; - /**Offset to start of creator string from start of this block */ - uint32_t creatorOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t creatorLength; - /**Offset to start of creator string from start of this block */ - uint32_t commentsOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t commentsLength; - /**Offset to start of creator string from start of this block */ - uint32_t mediaTitleOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t mediaTitleLength; - /**Offset to start of creator string from start of this block */ - uint32_t mediaManufacturerOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t mediaManufacturerLength; - /**Offset to start of creator string from start of this block */ - uint32_t mediaModelOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t mediaModelLength; - /**Offset to start of creator string from start of this block */ - uint32_t mediaSerialNumberOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t mediaSerialNumberLength; - /**Offset to start of creator string from start of this block */ - uint32_t mediaBarcodeOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t mediaBarcodeLength; - /**Offset to start of creator string from start of this block */ - uint32_t mediaPartNumberOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t mediaPartNumberLength; - /**Offset to start of creator string from start of this block */ - uint32_t driveManufacturerOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t driveManufacturerLength; - /**Offset to start of creator string from start of this block */ - uint32_t driveModelOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t driveModelLength; - /**Offset to start of creator string from start of this block */ - uint32_t driveSerialNumberOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t driveSerialNumberLength; - /**Offset to start of creator string from start of this block */ - uint32_t driveFirmwareRevisionOffset; - /**Length in uint8_ts of the null-terminated UTF-16LE creator string */ - uint32_t driveFirmwareRevisionLength; +/** \file aaruformat/structs/metadata.h + * \brief Packed on-disk metadata block headers for descriptive strings and CICM XML (if present). + * + * Two metadata-related block header layouts are defined: + * - \ref MetadataBlockHeader (BlockType::MetadataBlock): offsets + lengths for several UTF-16LE strings. + * - \ref CicmMetadataBlock (BlockType::CicmBlock): length of embedded CICM XML metadata payload. + * + * All multi-byte integers are little-endian. Structures are packed (1-byte alignment). All textual fields + * referenced by offsets are UTF-16LE, null-terminated (0x0000). Length fields include the terminating + * null (i.e. length >= 2 and an even number). Offsets are relative to the start of the corresponding block + * header (byte 0 = first byte of the header). No padding is implicitly added between strings; producers + * may pack them tightly or align them manually (alignment not required by the specification). + * + * Metadata block layout (conceptual): + * MetadataBlockHeader (fixed size) + * + * + * Invariants / validation recommendations for MetadataBlockHeader: + * - identifier == BlockType::MetadataBlock + * - blockSize >= sizeof(MetadataBlockHeader) + * - For every (offset,length) pair where length > 0: + * * offset >= sizeof(MetadataBlockHeader) + * * offset + length <= blockSize + * * length % 2 == 0 + * * The 16-bit code unit at (offset + length - 2) == 0x0000 (null terminator) + * - mediaSequence >= 0 and lastMediaSequence >= 0; if lastMediaSequence > 0 then 0 <= mediaSequence < + * lastMediaSequence + * + * CICM metadata block layout: + * CicmMetadataBlock (header) + * + * + * NOTE: The library code reading these blocks must not assume strings are present; a zero length means the + * corresponding field is omitted. Offsets for omitted fields MAY be zero or arbitrary; readers should skip them + * whenever length == 0. + */ + +/** \struct MetadataBlockHeader + * \brief Header for a metadata block containing offsets and lengths to UTF-16LE descriptive strings. + * + * Descriptive fields (all optional): creator, comments, media title/manufacturer/model/serial/barcode/part number, + * drive manufacturer/model/serial/firmware revision. Strings can be used to describe both physical medium and + * acquisition hardware. Length values include the UTF-16LE null terminator (two zero bytes). + */ +typedef struct MetadataBlockHeader +{ + uint32_t identifier; ///< Block identifier, must be BlockType::MetadataBlock. + uint32_t blockSize; ///< Total size in bytes of the entire metadata block (header + strings). + int32_t mediaSequence; ///< Sequence number within a multi-disc / multi-volume set (0-based or 1-based as + ///< producer defines). + int32_t lastMediaSequence; ///< Total number of media in the set; 0 or 1 if single item. + uint32_t creatorOffset; ///< Offset to UTF-16LE creator string (or undefined if creatorLength==0). + uint32_t creatorLength; ///< Length in bytes (including null) of creator string (0 if absent). + uint32_t commentsOffset; ///< Offset to UTF-16LE comments string. + uint32_t commentsLength; ///< Length in bytes (including null) of comments string. + uint32_t mediaTitleOffset; ///< Offset to UTF-16LE media title string. + uint32_t mediaTitleLength; ///< Length in bytes (including null) of media title string. + uint32_t mediaManufacturerOffset; ///< Offset to UTF-16LE media manufacturer string. + uint32_t mediaManufacturerLength; ///< Length in bytes (including null) of media manufacturer string. + uint32_t mediaModelOffset; ///< Offset to UTF-16LE media model string. + uint32_t mediaModelLength; ///< Length in bytes (including null) of media model string. + uint32_t mediaSerialNumberOffset; ///< Offset to UTF-16LE media serial number string. + uint32_t mediaSerialNumberLength; ///< Length in bytes (including null) of media serial number string. + uint32_t mediaBarcodeOffset; ///< Offset to UTF-16LE media barcode string. + uint32_t mediaBarcodeLength; ///< Length in bytes (including null) of media barcode string. + uint32_t mediaPartNumberOffset; ///< Offset to UTF-16LE media part number string. + uint32_t mediaPartNumberLength; ///< Length in bytes (including null) of media part number string. + uint32_t driveManufacturerOffset; ///< Offset to UTF-16LE drive manufacturer string. + uint32_t driveManufacturerLength; ///< Length in bytes (including null) of drive manufacturer string. + uint32_t driveModelOffset; ///< Offset to UTF-16LE drive model string. + uint32_t driveModelLength; ///< Length in bytes (including null) of drive model string. + uint32_t driveSerialNumberOffset; ///< Offset to UTF-16LE drive serial number string. + uint32_t driveSerialNumberLength; ///< Length in bytes (including null) of drive serial number string. + uint32_t driveFirmwareRevisionOffset; ///< Offset to UTF-16LE drive firmware revision string. + uint32_t driveFirmwareRevisionLength; ///< Length in bytes (including null) of drive firmware revision string. } MetadataBlockHeader; -/**Geometry block, contains physical geometry information */ -typedef struct CicmMetadataBlock { - /**Identifier, */ - uint32_t identifier; - uint32_t length; +/** \struct CicmMetadataBlock + * \brief Header for a CICM XML metadata block (identifier == BlockType::CicmBlock). + * + * The following 'length' bytes immediately after the header contain the CICM XML payload. Encoding is typically + * UTF-8; the payload is not required to be null-terminated. + */ +typedef struct CicmMetadataBlock +{ + uint32_t identifier; ///< Block identifier, must be BlockType::CicmBlock. + uint32_t length; ///< Length in bytes of the CICM metadata payload that follows. } CicmMetadataBlock; #pragma pack(pop) -#endif //LIBAARUFORMAT_METADATA_H +#endif // LIBAARUFORMAT_METADATA_H diff --git a/include/aaruformat/structs/optical.h b/include/aaruformat/structs/optical.h index ee2c9b6..23b37bf 100644 --- a/include/aaruformat/structs/optical.h +++ b/include/aaruformat/structs/optical.h @@ -21,36 +21,65 @@ #pragma pack(push, 1) -/**Contains list of optical disc tracks */ -typedef struct TracksHeader { - /**Identifier, */ - uint32_t identifier; - /**How many entries follow this header */ - uint16_t entries; - /**CRC64-ECMA of the block */ - uint64_t crc64; +/** \file aaruformat/structs/optical.h + * \brief On-disk structures describing optical disc tracks (Track list block). + * + * An optical tracks block (identifier == BlockType::TracksBlock) stores a list of \ref TrackEntry + * records describing the logical layout of tracks and sessions for CD/DVD/BD and similar media. + * + * Layout: + * TracksHeader (fixed) + * TrackEntry[ entries ] (array, packed) + * + * CRC semantics: + * - TracksHeader::crc64 is a CRC64-ECMA over the contiguous TrackEntry array ONLY (header excluded). + * - For legacy images (imageMajorVersion <= AARUF_VERSION_V1) a byte swap is applied when verifying. + * + * Field semantics (TrackEntry): + * - sequence: Logical track number (1..99 typical for CD). Values outside that range may encode extras. + * - type: Value from \ref TrackType (Audio, Data, Mode variants, etc.). + * - start / end: Inclusive Logical Block Address (LBA) bounds for the track. end >= start. + * - pregap: Number of sectors of pre-gap *preceding* the track's first user-accessible sector (can be 0 or negative + * if representing lead-in semantics; negative interpretation is implementation-defined). + * - session: Session number starting at 1 for multi-session discs (1 for single session). + * - isrc: 13-byte ISRC (raw code, no terminating null). If fewer significant characters, remaining bytes are 0. + * - flags: Bitmask of track/control flags. Unless otherwise specified, recommended mapping (mirrors CD subchannel Q + * control bits) is: bit0 Pre-emphasis, bit1 Copy permitted, bit2 Data track, bit3 Four-channel audio, + * bits4-7 reserved. Actual semantics may be extended by the format specification. + * + * Invariants / validation recommendations: + * - identifier == BlockType::TracksBlock + * - entries * sizeof(TrackEntry) bytes are present after the header in the block image. + * - 1 <= sequence <= 99 for standard CD tracks (non-conforming values allowed but should be documented). + * - start <= end; pregap >= 0 (if negative pregaps unsupported in implementation). + * - ISRC bytes either all zero (no ISRC) or printable ASCII (A-Z 0-9 -) per ISO 3901 (without hyphen formatting). + */ + +/** \struct TracksHeader + * \brief Header for an optical tracks block listing track entries. + */ +typedef struct TracksHeader +{ + uint32_t identifier; ///< Block identifier (must be BlockType::TracksBlock). + uint16_t entries; ///< Number of TrackEntry records following this header. + uint64_t crc64; ///< CRC64-ECMA of the TrackEntry array (header excluded, legacy byte-swap for early versions). } TracksHeader; -/**Optical disc track */ -typedef struct TrackEntry { - /**Track sequence */ - uint8_t sequence; - /**Track type */ - uint8_t type; - /**Track starting LBA */ - int64_t start; - /**Track last LBA */ - int64_t end; - /**Track pregap in sectors */ - int64_t pregap; - /**Track session */ - uint8_t session; - /**Track's ISRC in ASCII */ - uint8_t isrc[13]; - /**Track flags */ - uint8_t flags; +/** \struct TrackEntry + * \brief Single optical disc track descriptor (sequence, type, LBAs, session, ISRC, flags). + */ +typedef struct TrackEntry +{ + uint8_t sequence; ///< Track number (1..99 typical for CD audio/data). 0 may indicate placeholder/non-standard. + uint8_t type; ///< Track type (value from \ref TrackType). + int64_t start; ///< Inclusive starting LBA of the track. + int64_t end; ///< Inclusive ending LBA of the track. + int64_t pregap; ///< Pre-gap length in sectors preceding track start (0 if none). + uint8_t session; ///< Session number (1-based). 1 for single-session discs. + uint8_t isrc[13]; ///< ISRC raw 13-byte code (no null terminator). All zeros if not present. + uint8_t flags; ///< Control / attribute bitfield (see file documentation for suggested bit mapping). } TrackEntry; #pragma pack(pop) -#endif //LIBAARUFORMAT_OPTICAL_H +#endif // LIBAARUFORMAT_OPTICAL_H diff --git a/include/aaruformat/structs/options.h b/include/aaruformat/structs/options.h index 583df16..7c7c4c6 100644 --- a/include/aaruformat/structs/options.h +++ b/include/aaruformat/structs/options.h @@ -19,19 +19,214 @@ #ifndef LIBAARUFORMAT_OPTIONS_H #define LIBAARUFORMAT_OPTIONS_H +#include ///< For bool type used in aaru_options. +#include ///< For fixed-width integer types. + +/** \file aaruformat/structs/options.h + * \brief Image creation / open tuning options structure and related semantics. + * + * The library accepts a semicolon-delimited key=value options string (see parse_options()). Recognized keys: + * compress=true|false Enable/disable block compression (LZMA for data blocks, FLAC for audio tracks). + * deduplicate=true|false If true, identical (duplicate) sectors are stored once (DDT entries point to same + * physical block). If false, duplicates are still tracked in DDT but each occurrence + * is stored independently (no storage savings). DDT itself is always present. + * dictionary= LZMA dictionary size in bytes (fallback default 33554432 if 0 or invalid). + * table_shift= DDT v2 table shift (default 9) (items per primary entry = 2^n when multi-level). + * data_shift= Global data shift (default 12). Defines per-block address granularity: the low + * 2^n range encodes the sector (or unit) offset within a block; higher bits combine + * with block_alignment to derive block file offsets. Used by DDT but not limited to it. + * block_alignment= log2 alignment of underlying data blocks (default 9 => 512 bytes) (block size = 2^n). + * md5=true|false Generate MD5 checksum (stored in checksum block if true). + * sha1=true|false Generate SHA-1 checksum. + * sha256=true|false Generate SHA-256 checksum. + * blake3=true|false Generate BLAKE3 checksum (may require build-time support; ignored if unsupported). + * spamsum=true|false Generate SpamSum fuzzy hash. + * + * Defaults (when option string NULL or key omitted): + * compress=true, deduplicate=true, dictionary=33554432, table_shift=9, data_shift=12, + * block_alignment=9, md5=false, sha1=false, sha256=false, blake3=false, spamsum=false. + * + * Validation / normalization done in parse_options(): + * - Zero / missing dictionary resets to default 33554432. + * - Zero table_shift resets to 9. + * - Zero data_shift resets to 12. + * - Zero block_alignment resets to 9. + * + * Rationale: + * - table_shift, data_shift and block_alignment mirror fields stored in on-disk headers (see AaruHeaderV2 & + * DdtHeader2); data_shift is a global per-block granularity exponent (not DDT-specific) governing how in-block offsets + * are encoded. + * - compress selects adaptive codec usage: LZMA applied to generic/data blocks, FLAC applied to audio track payloads. + * - deduplicate toggles storage optimization only: the DDT directory is always built for addressing; disabling simply + * forces each sector's content to be written even if already present (useful for forensic byte-for-byte + * duplication). + * - dictionary tunes compression ratio/memory use; large values increase memory footprint. + * - Checksums are optional; enabling multiple increases CPU time at write finalization. + * + * Performance / space trade-offs (deduplicate=false): + * - Significantly larger image size: every repeated sector payload is written again. + * - Higher write I/O and longer creation time for highly redundant sources (e.g., zero-filled regions) compared to + * deduplicate=true, although CPU time spent on duplicate detection/hash lookups is reduced. + * - Potentially simpler post-process forensic validation (physical ordering preserved without logical coalescing). + * - Use when exact physical repetition is more critical than storage efficiency, or to benchmark raw device + * throughput. + * - For typical archival use-cases with large zero / repeated patterns, deduplicate=true markedly reduces footprint. + * + * Approximate in-RAM hash map usage for deduplication (deduplicate=true): + * The on-disk DDT can span many secondary tables, but only the primary table plus a currently loaded secondary (and + * possibly a small cache) reside in memory; their footprint is typically <<5% of total indexed media space and is + * often negligible compared to the hash map used to detect duplicate sectors. Therefore we focus here on the hash / + * lookup structure ("hash_map") memory, not the entire DDT on-disk size. + * + * Worst-case (all sectors unique) per 1 GiB of user data: + * sectors_per_GiB = 2^30 / sector_size + * hash_bytes ≈ sectors_per_GiB * H (H ≈ 16 bytes: 8-byte fingerprint + ~8 bytes map overhead) + * + * Resulting hash_map RAM per GiB (unique sectors): + * +--------------+------------------+------------------------------+ + * | Sector size | Sectors / GiB | Hash map (~16 B / sector) | + * +--------------+------------------+------------------------------+ + * | 512 bytes | 2,097,152 | ~33.5 MiB (≈32.0–36.0 MiB) | + * | 2048 bytes | 524,288 | ~ 8.0 MiB (≈7.5–8.5 MiB) | + * | 4096 bytes | 262,144 | ~ 4.0 MiB (≈3.8–4.3 MiB) | + * +--------------+------------------+------------------------------+ + * + * (Range reflects allocator + load factor variation.) + * + * Targeted projections (hash map only, R=1): + * 2048‑byte sectors (~8 MiB per GiB unique) + * Capacity | Hash map (MiB) | Hash map (GiB) + * ---------+---------------+---------------- + * 25 GiB | ~200 | 0.20 + * 50 GiB | ~400 | 0.39 + * + * 512‑byte sectors (~34 MiB per GiB unique; using 33.5 MiB for calc) + * Capacity | Hash map (MiB) | Hash map (GiB) + * ---------+---------------+---------------- + * 128 GiB | ~4288 | 4.19 + * 500 GiB | ~16750 | 16.36 + * 1 TiB* | ~34304 | 33.50 + * 2 TiB* | ~68608 | 67.00 + * + * *TiB = 1024 GiB binary. For decimal TB reduce by ~7% (×0.93). + * + * Duplicate ratio scaling: + * Effective hash RAM ≈ table_value * R, where R = unique_sectors / total_sectors. + * Example: 500 GiB @512 B, R=0.4 ⇒ ~16750 MiB * 0.4 ≈ 6700 MiB (~6.54 GiB). + * + * Quick rule of thumb (hash only): + * hash_bytes_per_GiB ≈ 16 * (2^30 / sector_size) ≈ (17.1799e9 / sector_size) bytes + * → ≈ 33.6 MiB (512 B), 8.4 MiB (2048 B), 4.2 MiB (4096 B) per GiB unique. + * + * Memory planning tip: + * If projected hash_map usage risks exceeding available RAM, consider: + * - Increasing table_shift (reduces simultaneous secondary loads / contention) + * - Lowering data_shift (if practical) to encourage earlier big DDT adoption with fewer unique blocks + * - Segmenting the dump into phases (if workflow permits) + * - Accepting higher duplicate ratio by pre-zero detection or sparse treatment externally. + * - Resuming the dump in multiple passes: each resume rebuilds the hash_map from scratch, so peak RAM still + * matches a single-pass estimate, but average RAM over total wall time can drop if you unload between passes. + * + * NOTE: DDT in-RAM portion (primary + one secondary) usually adds only a few additional MiB even for very large + * images, hence omitted from sizing tables. Include +5% safety margin if extremely tight on memory. + * + * Guidance for table_shift / data_shift selection: + * Let: + * S = total logical sectors expected in image (estimate if unknown). + * T = table_shift (items per primary DDT entry = 2^T when multi-level; 0 => single-level). + * D = data_shift (in-block sector offset span = 2^D). + * BA = block_alignment (bytes) = 2^block_alignment. + * SS = sector size (bytes). + * + * 1. data_shift constraints: + * - For SMALL DDT entries (12 payload bits after status): D must satisfy 0 < D < 12 and (12 - D) >= 1 so that at + * least one bit remains for block index. Practical range for small DDT: 6..10 (leaves 2+ bits for block index). + * - For BIG DDT entries (28 payload bits after status): D may be larger (up to 27) but values >16 rarely useful. + * - Effective address granularity inside a block = min(2^D * SS, physical block span implied by BA). + * - Choosing D too large wastes bits (larger offset range than block actually contains) and reduces the number of + * block index bits within a small entry, potentially forcing upgrade to big DDT earlier. + * + * Recommended starting points: + * * 512‑byte sectors, 512‑byte block alignment: D=9 (512 offsets) or D=8 (256 offsets) keeps small DDT viable. + * * 2048‑byte optical sectors, 2048‑byte alignment: D=8 (256 offsets) typically sufficient. + * * Mixed / large logical block sizes: keep D so that (2^D * SS) ≈ typical dedup block region you want + * addressable. + * + * 2. block capacity within an entry: + * - SMALL DDT: usable block index bits = 12 - D. + * Max representable block index (small) = 2^(12-D) - 1. + * - BIG DDT: usable block index bits = 28 - D. + * Max representable block index (big) = 2^(28-D) - 1. + * - If (requiredBlockIndex > max) you must either reduce D or rely on big DDT. + * + * Approximate requiredBlockIndex ≈ (TotalUniqueBlocks) where + * TotalUniqueBlocks ≈ (S * SS) / (BA * (2^D * SS / (SS))) = S / (2^D * (BA / SS)) + * Simplified (assuming BA = SS): TotalUniqueBlocks ≈ S / 2^D. + * + * 3. table_shift considerations (multi-level DDT): + * - Primary entries count ≈ ceil(S / 2^T). Choose T so this count fits memory and keeps lookup fast. + * - Larger T reduces primary table size, increasing secondary table dereferences. + * - Typical balanced values: T in [8..12] (256..4096 sectors per primary entry). + * - Set T=0 for single-level when S is small enough that all entries fit comfortably in memory. + * + * Memory rough estimate for single-level SMALL DDT: + * bytes ≈ S * 2 (each small entry 2 bytes). For BIG DDT: bytes ≈ S * 4. + * Multi-level: primary table bytes ≈ (S / 2^T) * entrySize + sum(secondary tables). + * + * 4. Example scenarios: + * - 50M sectors (≈25 GiB @512B), want small DDT: pick D=8 (256); block index bits=4 (max 16 blocks) insufficient. + * Need either D=6 (1024 block indices) or accept BIG DDT (28-8=20 bits => million+ blocks). So prefer BIG DDT + * here. + * - 2M sectors, 2048B alignment, optical: D=8 gives S/2^D ≈ 7812 unique offsets; small DDT block index bits=4 (max + * 16) inadequate → choose D=6 (offset span 64 sectors) giving 6 block index bits (max 64) or just use big DDT. + * + * 5. Practical recommendations: + * - If unsure and image > ~1M sectors: keep defaults (data_shift=12, table_shift=9) and allow big DDT. + * - For small archival (<100k sectors): T=0 (single-level), D≈8..10 to keep small DDT feasible. + * - Benchmark before lowering D purely to stay in small DDT; increased secondary lookups or larger primary tables + * can offset saved space. + * + * Recommended presets (approximate bands): + * +----------------------+----------------------+---------------------------+-------------------------------+ + * | Total logical sectors | table_shift (T) | data_shift (D) | Notes | + * +----------------------+----------------------+---------------------------+-------------------------------+ + * | < 50,000 | 0 | 8 – 10 | Single-level small DDT likely | + * | 50K – 1,000,000 | 8 – 9 | 9 – 10 | Still feasible small DDT | + * | 1M – 10,000,000 | 9 – 10 | 10 – 12 | Borderline small -> big DDT | + * | 10M – 100,000,000 | 10 – 11 | 11 – 12 | Prefer big DDT; tune T for mem| + * | > 100,000,000 | 11 – 12 | 12 | Big DDT; higher T saves memory| + * +----------------------+----------------------+---------------------------+-------------------------------+ + * Ranges show typical stable regions; pick the lower end of table_shift if memory is ample, higher if minimizing + * primary table size. Always validate actual unique block count vs payload bits. + * + * NOTE: The library will automatically fall back to BIG DDT where needed; these settings bias structure, they do not + * guarantee small DDT retention. + * + * Thread-safety: aaru_options is a plain POD struct; caller may copy freely. parse_options() returns by value. + * + * Future compatibility: unknown keys are ignored by current parser; consumers should preserve original option + * strings if round-tripping is required. + */ + +/** \struct aaru_options + * \brief Parsed user-specified tunables controlling compression, deduplication, hashing and DDT geometry. + * + * All shifts are exponents of two. + */ typedef struct { - bool compress; - bool deduplicate; - uint32_t dictionary; - uint8_t table_shift; - uint8_t data_shift; - uint8_t block_alignment; - bool md5; - bool sha1; - bool sha256; - bool blake3; - bool spamsum; + bool compress; ///< Enable adaptive compression (LZMA for data blocks, FLAC for audio). Default: true. + bool deduplicate; ///< Storage dedup flag (DDT always exists). true=share identical sector content, false=store + ///< each instance. + uint32_t dictionary; ///< LZMA dictionary size in bytes (>= 4096 recommended). Default: 33554432 (32 MiB). + uint8_t table_shift; ///< DDT table shift (multi-level fan-out exponent). Default: 9. + uint8_t data_shift; ///< Global data shift: low bits encode sector offset inside a block (2^data_shift span). + uint8_t block_alignment; ///< log2 underlying block alignment (2^n bytes). Default: 9 (512 bytes). + bool md5; ///< Generate MD5 checksum (ChecksumAlgorithm::Md5) when finalizing image. + bool sha1; ///< Generate SHA-1 checksum (ChecksumAlgorithm::Sha1) when finalizing image. + bool sha256; ///< Generate SHA-256 checksum (ChecksumAlgorithm::Sha256) when finalizing image. + bool blake3; ///< Generate BLAKE3 checksum if supported (not stored if algorithm unavailable). + bool spamsum; ///< Generate SpamSum fuzzy hash (ChecksumAlgorithm::SpamSum) if enabled. } aaru_options; #endif // LIBAARUFORMAT_OPTIONS_H