//------------------------------------------------
//--- 010 Editor v8.0.1 Binary Template
//
//      File: aaruformat.bt
//   Authors: Natalia Portillo
//   Version: 1.2
//   Purpose: Aaru format
//  Category: Misc
// File Mask: *.aif
//  ID Bytes: 41 41 52 55 46 52 4D 54 // AARUFRMT
//   History:
//   1.0 2018-01-26 Natalia Portillo: Initial release
//   1.1 2020-02-29 Natalia Portillo: Rebranding
//   1.2 2020-03-04 Natalia Portillo: Add version 2 index
//------------------------------------------------

#define DIC_MAGIC 0x544D52464D434944
#define AARU_MAGIC 0x544D524655524141

enum <uint> MediaType
{
    Unknown = 0,
    UnknownMO = 1,
    GENERIC_HDD = 2,
    Microdrive  = 3,
    Zone_HDD    = 4,
    FlashDrive = 5,
    UnknownTape = 6,

    CD = 10,
    CDDA = 11,
    CDG = 12,
    CDEG = 13,
    CDI = 14,
    CDROM = 15,
    CDROMXA = 16,
    CDPLUS = 17,
    CDMO = 18,
    CDR = 19,
    CDRW = 20,
    CDMRW = 21,
    VCD = 22,
    SVCD = 23,
    PCD = 24,
    SACD = 25,
    DDCD = 26,
    DDCDR = 27,
    DDCDRW = 28,
    DTSCD = 29,
    CDMIDI = 30,
    CDV = 31,
    PD650 = 32,
    PD650_WORM = 33,
    CDIREADY = 34,
    FMTOWNS = 35,

    DVDROM = 40,
    DVDR = 41,
    DVDRW = 42,
    DVDPR = 43,
    DVDPRW = 44,
    DVDPRWDL = 45,
    DVDRDL = 46,
    DVDPRDL = 47,
    DVDRAM = 48,
    DVDRWDL = 49,
    DVDDownload = 50,

    HDDVDROM = 51,
    HDDVDRAM = 52,
    HDDVDR = 53,
    HDDVDRW = 54,
    HDDVDRDL = 55,
    HDDVDRWDL = 56,

    BDROM = 60,
    BDR = 61,
    BDRE = 62,
    BDRXL = 63,
    BDREXL = 64,

    EVD = 70,
    FVD = 71,
    HVD = 72,
    CBHD = 73,
    HDVMD = 74,
    VCDHD = 75,
    SVOD = 76,
    FDDVD = 77,

    LD = 80,
    LDROM = 81,
    LDROM2 = 82,
    LVROM = 83,
    MegaLD = 84,

    HiMD = 90,
    MD = 91,
    MDData = 92,
    MDData2 = 93,
    MD60 = 94,
    MD74 = 95,
    MD80 = 96,

    UDO = 100,
    UDO2 = 101,
    UDO2_WORM = 102,

    PlayStationMemoryCard = 110,
    PlayStationMemoryCard2 = 111,
    PS1CD = 112,
    PS2CD = 113,
    PS2DVD = 114,
    PS3DVD = 115,
    PS3BD = 116,
    PS4BD = 117,
    UMD = 118,
    PlayStationVitaGameCard = 119,

    XGD = 130,
    XGD2 = 131,
    XGD3 = 132,
    XGD4 = 133,

    MEGACD = 150,
    SATURNCD = 151,
    GDROM = 152,
    GDR = 153,
    SegaCard = 154,
    MilCD = 155,

    HuCard = 170,
    SuperCDROM2 = 171,
    JaguarCD = 172,
    ThreeDO = 173,
    PCFX = 174,
    NeoGeoCD = 175,
    CDTV = 176,
    CD32 = 177,
    Nuon = 178,
    Playdia = 179,

    Apple32SS = 180,
    Apple32DS = 181,
    Apple33SS = 182,
    Apple33DS = 183,
    AppleSonySS = 184,
    AppleSonyDS = 185,
    AppleFileWare = 186,

    DOS_525_SS_DD_8 = 190,
    DOS_525_SS_DD_9 = 191,
    DOS_525_DS_DD_8 = 192,
    DOS_525_DS_DD_9 = 193,
    DOS_525_HD = 194,
    DOS_35_SS_DD_8 = 195,
    DOS_35_SS_DD_9 = 196,
    DOS_35_DS_DD_8 = 197,
    DOS_35_DS_DD_9 = 198,
    DOS_35_HD = 199,
    DOS_35_ED = 200,
    DMF = 201,
    DMF_82 = 202,
    XDF_525 = 203,
    XDF_35 = 204,

    IBM23FD = 210,
    IBM33FD_128 = 211,
    IBM33FD_256 = 212,
    IBM33FD_512 = 213,
    IBM43FD_128 = 214,
    IBM43FD_256 = 215,
    IBM53FD_256 = 216,
    IBM53FD_512 = 217,
    IBM53FD_1024 = 218,

    RX01 = 220,
    RX02 = 221,
    RX03 = 222,
    RX50 = 223,

    ACORN_525_SS_SD_40 = 230,
    ACORN_525_SS_SD_80 = 231,
    ACORN_525_SS_DD_40 = 232,
    ACORN_525_SS_DD_80 = 233,
    ACORN_525_DS_DD = 234,
    ACORN_35_DS_DD = 235,
    ACORN_35_DS_HD = 236,

    ATARI_525_SD = 240,
    ATARI_525_ED = 241,
    ATARI_525_DD = 242,
    ATARI_35_SS_DD = 243,
    ATARI_35_DS_DD = 244,
    ATARI_35_SS_DD_11 = 245,
    ATARI_35_DS_DD_11 = 246,

    CBM_35_DD = 250,
    CBM_AMIGA_35_DD = 251,
    CBM_AMIGA_35_HD = 252,
    CBM_1540 = 253,
    CBM_1540_Ext = 254,
    CBM_1571 = 255,

    NEC_8_SD = 260,
    NEC_8_DD = 261,
    NEC_525_SS = 262,
    NEC_525_DS = 263,
    NEC_525_HD = 264,
    NEC_35_HD_8 = 265,
    NEC_35_HD_15 = 266,
    NEC_35_TD = 267,
    SHARP_525 = NEC_525_HD,
    SHARP_525_9 = 268,
    SHARP_35 = NEC_35_HD_8,
    SHARP_35_9 = 269,

    ECMA_99_8 = 270,
    ECMA_99_15 = 271,
    ECMA_99_26 = 272,
    ECMA_100 = DOS_35_DS_DD_9,
    ECMA_125 = DOS_35_HD,
    ECMA_147 = DOS_35_ED,
    ECMA_54 = 273,
    ECMA_59 = 274,
    ECMA_66 = 275,
    ECMA_69_8 = 276,
    ECMA_69_15 = 277,
    ECMA_69_26 = 278,
    ECMA_70 = 279,
    ECMA_78 = 280,
    ECMA_78_2 = 281,

    FDFORMAT_525_DD = 290,
    FDFORMAT_525_HD = 291,
    FDFORMAT_35_DD = 292,
    FDFORMAT_35_HD = 293,

    Apricot_35 = 309,

    ADR2120 = 310,
    ADR260 = 311,
    ADR30 = 312,
    ADR50 = 313,

    AIT1 = 320,
    AIT1Turbo = 321,
    AIT2 = 322,
    AIT2Turbo = 323,
    AIT3 = 324,
    AIT3Ex = 325,
    AIT3Turbo = 326,
    AIT4 = 327,
    AIT5 = 328,
    AITETurbo = 329,
    SAIT1 = 330,
    SAIT2 = 331,

    Bernoulli = 340,
    Bernoulli2 = 341,
    Ditto  = 342,
    DittoMax  = 343,
    Jaz        = 344,
    Jaz2   = 345,
    PocketZip = 346,
    REV120     = 347,
    REV35  = 348,
    REV70     = 349,
    ZIP100     = 350,
    ZIP250 = 351,
    ZIP750    = 352,
    Bernoulli35 = 353,
    Bernoulli44 = 354,
    Bernoulli65 = 355,
    Bernoulli90 = 356,
    Bernoulli105 = 357,
    Bernoulli150 = 358,
    Bernoulli230 = 359,

    CompactCassette = 360,
    Data8 = 361,
    MiniDV = 362,
    Dcas25 = 363,
    Dcas85 = 364,
    Dcas103 = 365,

    CFast = 370,
    CompactFlash = 371,
    CompactFlashType2 = 372,

    DigitalAudioTape = 380,
    DAT160 = 381,
    DAT320 = 382,
    DAT72 = 383,
    DDS1 = 384,
    DDS2 = 385,
    DDS3 = 386,
    DDS4 = 387,

    CompactTapeI = 390,
    CompactTapeII = 391,
    DECtapeII = 392,
    DLTtapeIII = 393,
    DLTtapeIIIxt = 394,
    DLTtapeIV = 395,
    DLTtapeS4 = 396,
    SDLT1 = 397,
    SDLT2 = 398,
    VStapeI = 399,

    Exatape15m = 400,
    Exatape22m = 401,
    Exatape22mAME = 402,
    Exatape28m = 403,
    Exatape40m = 404,
    Exatape45m = 405,
    Exatape54m = 406,
    Exatape75m = 407,
    Exatape76m = 408,
    Exatape80m = 409,
    Exatape106m = 410,
    Exatape160mXL = 411,
    Exatape112m = 412,
    Exatape125m = 413,
    Exatape150m = 414,
    Exatape170m = 415,
    Exatape225m = 416,

    ExpressCard34 = 420,
    ExpressCard54 = 421,
    PCCardTypeI = 422,
    PCCardTypeII = 423,
    PCCardTypeIII = 424,
    PCCardTypeIV = 425,

    EZ135 = 430,
    EZ230 = 431,
    Quest = 432,
    SparQ = 433,
    SQ100 = 434,
    SQ200 = 435,
    SQ300 = 436,
    SQ310 = 437,
    SQ327 = 438,
    SQ400 = 439,
    SQ800 = 440,
    SQ1500 = 441,
    SQ2000 = 442,
    SyJet = 443,

    FamicomGamePak = 450,
    GameBoyAdvanceGamePak = 451,
    GameBoyGamePak = 452,
    GOD = 453,
    N64DD = 454,
    N64GamePak = 455,
    NESGamePak = 456,
    Nintendo3DSGameCard = 457,
    NintendoDiskCard = 458,
    NintendoDSGameCard = 459,
    NintendoDSiGameCard = 460,
    SNESGamePak = 461,
    SNESGamePakUS = 462,
    WOD = 463,
    WUOD = 464,
    SwitchGameCard = 465,

    IBM3470 = 470,
    IBM3480 = 471,
    IBM3490 = 472,
    IBM3490E = 473,
    IBM3592 = 474,

    LTO = 480,
    LTO2 = 481,
    LTO3 = 482,
    LTO3WORM = 483,
    LTO4 = 484,
    LTO4WORM = 485,
    LTO5 = 486,
    LTO5WORM = 487,
    LTO6 = 488,
    LTO6WORM = 489,
    LTO7 = 490,
    LTO7WORM = 491,

    MemoryStick = 510,
    MemoryStickDuo = 511,
    MemoryStickMicro = 512,
    MemoryStickPro = 513,
    MemoryStickProDuo = 514,

    microSD = 520,
    miniSD = 521,
    SecureDigital = 522,

    MMC = 530,
    MMCmicro = 531,
    RSMMC = 532,
    MMCplus = 533,
    MMCmobile = 534,

    MLR1 = 540,
    MLR1SL = 541,
    MLR3 = 542,
    SLR1 = 543,
    SLR2 = 544,
    SLR3 = 545,
    SLR32 = 546,
    SLR32SL = 547,
    SLR4 = 548,
    SLR5 = 549,
    SLR5SL = 550,
    SLR6 = 551,
    SLRtape7 = 552,
    SLRtape7SL = 553,
    SLRtape24 = 554,
    SLRtape24SL = 555,
    SLRtape40 = 556,
    SLRtape50 = 557,
    SLRtape60 = 558,
    SLRtape75 = 559,
    SLRtape100 = 560,
    SLRtape140 = 561,

    QIC11 = 570,
    QIC120 = 571,
    QIC1350 = 572,
    QIC150 = 573,
    QIC24 = 574,
    QIC3010 = 575,
    QIC3020 = 576,
    QIC3080 = 577,
    QIC3095 = 578,
    QIC320 = 579,
    QIC40 = 580,
    QIC525 = 581,
    QIC80 = 582,

    STK4480 = 590,
    STK4490 = 591,
    STK9490 = 592,
    T9840A = 593,
    T9840B = 594,
    T9840C = 595,
    T9840D = 596,
    T9940A = 597,
    T9940B = 598,
    T10000A = 599,
    T10000B = 600,
    T10000C = 601,
    T10000D = 602,

    Travan = 610,
    Travan1Ex = 611,
    Travan3 = 612,
    Travan3Ex = 613,
    Travan4 = 614,
    Travan5 = 615,
    Travan7 = 616,

    VXA1 = 620,
    VXA2 = 621,
    VXA3 = 622,

    ECMA_153 = 630,
    ECMA_153_512 = 631,
    ECMA_154 = 632,
    ECMA_183_512 = 633,
    ECMA_183 = 634,
    ECMA_184_512 = 635,
    ECMA_184 = 636,
    ECMA_189 = 637,
    ECMA_190 = 638,
    ECMA_195 = 639,
    ECMA_195_512 = 640,
    ECMA_201 = 641,
    ECMA_201_ROM = 642,
    ECMA_223 = 643,
    ECMA_223_512 = 644,
    ECMA_238 = 645,
    ECMA_239 = 646,
    ECMA_260 = 647,
    ECMA_260_Double = 648,
    ECMA_280 = 649,
    ECMA_317 = 650,
    ECMA_322 = 651,
    ECMA_322_2k = 652,
    GigaMo = 653,
    GigaMo2 = 654,

    CompactFloppy = 660,
    DemiDiskette = 661,
    Floptical = 662,
    HiFD = 663,
    QuickDisk = 664,
    UHD144 = 665,
    VideoFloppy = 666,
    Wafer = 667,
    ZXMicrodrive = 668,

    BeeCard = 670,
    Borsu = 671,
    DataStore = 672,
    DIR = 673,
    DST = 674,
    DTF = 675,
    DTF2 = 676,
    Flextra3020 = 677,
    Flextra3225 = 678,
    HiTC1 = 679,
    HiTC2 = 680,
    LT1 = 681,
    MiniCard = 872,
    Orb = 683,
    Orb5 = 684,
    SmartMedia = 685,
    xD = 686,
    XQD = 687,
    DataPlay = 688,

    AppleProfile = 690,
    AppleWidget = 691,
    AppleHD20 = 692,
    PriamDataTower = 693,
    Pippin = 694,

    RA60 = 700,
    RA80 = 701,
    RA81 = 702,
    RC25 = 703,
    RD31 = 704,
    RD32 = 705,
    RD51 = 706,
    RD52 = 707,
    RD53 = 708,
    RD54 = 709,
    RK06 = 710,
    RK06_18 = 711,
    RK07 = 712,
    RK07_18 = 713,
    RM02 = 714,
    RM03 = 715,
    RM05 = 716,
    RP02 = 717,
    RP02_18 = 718,
    RP03 = 719,
    RP03_18 = 720,
    RP04 = 721,
    RP04_18 = 722,
    RP05 = 723,
    RP05_18 = 724,
    RP06 = 725,
    RP06_18 = 726,

    LS120  = 730,
    LS240  = 731,
    FD32MB = 732,
    RDX = 733,
    RDX320 = 734,

    VideoNow = 740,
    VideoNowColor = 741,
    VideoNowXp = 742,

    Bernoulli10 = 750,
    Bernoulli20 = 751,
    BernoulliBox2_20 = 752,

    KodakVerbatim3 = 760,
    KodakVerbatim6 = 761,
    KodakVerbatim12 = 762,

    ProfessionalDisc = 770,
    ProfessionalDiscDual = 771,
    ProfessionalDiscTriple = 772,
    ProfessionalDiscQuad = 773,
    PDD = 774,
    PDD_WORM = 775,
    ArchivalDisc = 776,
    ArchivalDisc2 = 777,
    ArchivalDisc3 = 779,
    ODC300R = 778,
    ODC300RE = 780,
    ODC600R = 781,
    ODC600RE = 782,
    ODC1200RE = 783,
    ODC1500R = 784,
    ODC3300R = 785,
    ODC5500R = 786,

    ECMA_322_1k   = 800,
    ECMA_322_512  = 801,
    ISO_14517     = 802,
    ISO_14517_512 = 803,
    ISO_15041_512 = 804,
    HSM650        = 805,

    MetaFloppy_Mod_I = 820,
    HF12 = 823,
    HF24 = 824,

    AtariLynxCard        = 821,
    AtariJaguarCartridge = 822
};

enum <ushort> CompressionType
{
    None = 0,
    Lzma = 1,
    Flac = 2
};

enum <ushort> DataType
{
    NoData                           = 0,
    UserData                         = 1,
    CompactDiscPartialToc            = 2,
    CompactDiscSessionInfo           = 3,
    CompactDiscToc                   = 4,
    CompactDiscPma                   = 5,
    CompactDiscAtip                  = 6,
    CompactDiscLeadInCdText          = 7,
    DvdPfi                           = 8,
    DvdLeadInCmi                     = 9,
    DvdDiscKey                       = 10,
    DvdBca                           = 11,
    DvdDmi                           = 12,
    DvdMediaIdentifier               = 13,
    DvdMediaKeyBlock                 = 14,
    DvdRamDds                        = 15,
    DvdRamMediumStatus               = 16,
    DvdRamSpareArea                  = 17,
    DvdRRmd                          = 18,
    DvdRPrerecordedInfo              = 19,
    DvdRMediaIdentifier              = 20,
    DvdRPfi                          = 21,
    DvdAdip                          = 22,
    HdDvdCpi                         = 23,
    HdDvdMediumStatus                = 24,
    DvdDlLayerCapacity               = 25,
    DvdDlMiddleZoneAddress           = 26,
    DvdDlJumpIntervalSize            = 27,
    DvdDlManualLayerJumpLba          = 28,
    BlurayDi                         = 29,
    BlurayBca                        = 30,
    BlurayDds                        = 31,
    BlurayCartridgeStatus            = 32,
    BluraySpareArea                  = 33,
    AacsVolumeIdentifier             = 34,
    AacsSerialNumber                 = 35,
    AacsMediaIdentifier              = 36,
    AacsMediaKeyBlock                = 37,
    AacsDataKeys                     = 38,
    AacsLbaExtents                   = 39,
    CprmMediaKeyBlock                = 40,
    HybridRecognizedLayers           = 41,
    ScsiMmcWriteProtection           = 42,
    ScsiMmcDiscInformation           = 43,
    ScsiMmcTrackResourcesInformation = 44,
    ScsiMmcPowResourcesInformation   = 45,
    ScsiInquiry                      = 46,
    ScsiModePage2A                   = 47,
    AtaIdentify                      = 48,
    AtapiIdentify                    = 49,
    PcmciaCis                        = 50,
    SecureDigitalCid                 = 51,
    SecureDigitalCsd                 = 52,
    SecureDigitalScr                 = 53,
    SecureDigitalOcr                 = 54,
    MultiMediaCardCid                = 55,
    MultiMediaCardCsd                = 56,
    MultiMediaCardOcr                = 57,
    MultiMediaCardExtendedCsd        = 58,
    XboxSecuritySector               = 59,
    FloppyLeadOut                    = 60,
    DvdDiscControlBlock              = 61,
    CompactDiscFirstTrackPregap      = 62,
    CompactDiscLeadOut               = 63,
    ScsiModeSense6                   = 64,
    ScsiModeSense10                  = 65,
    UsbDescriptors                   = 66,
    XboxDmi                          = 67,
    XboxPfi                          = 68,
    CdSectorPrefix                   = 69,
    CdSectorSuffix                   = 70,
    CdSectorSubchannel               = 71,
    AppleProfileTag                  = 72,
    AppleSonyTag                     = 73,
    PriamDataTowerTag                = 74,
    CompactDiscMediaCatalogueNumber  = 75,
    CdSectorPrefixCorrected          = 76,
    CdSectorSuffixCorrected          = 77,
    CompactDiscMode2Subheader        = 78,
    CompactDiscLeadIn                = 79,
    DecryptedDVDDiscKey              = 80,
    DVD_CPI_MAI                      = 81,
    DecryptedDVDTitleKey             = 82,
    DvdSectorId                      = 83,
    DvdSectorIed                     = 84,
    DvdSectorEdc                     = 85,
    DvdSectorEccPi                   = 86,
    DvdEccBlockPo                    = 87,
    DvdPfi2ndLayer                   = 88,
    FluxData                         = 89,
    BitstreamData                    = 90
};

enum <uint> BlockType
{
    DataBlock                    = 0x4B4C4244,
    DeDuplicationTable           = 0X2A544444,
    DeDuplicationTable2          = 0x32544444,
    DeDuplicationTableSecondary  = 0x53544444,
    IndexBlock                   = 0X58444E49,
    IndexBlock2                  = 0x32584449,
    IndexBlock3                  = 0x33584449,
    GeometryBlockId              = 0x4D4F4547,
    MetadataBlockId              = 0x4154454D,
    TracksBlock                  = 0x534B5254,
    CicmBlock                    = 0x4D434943,
    ChecksumBlock                = 0x4D534B43,
    DataPositionMeasurementBlock = 0x2A4D5044,
    SnapshotBlock                = 0x50414E53,
    ParentBlock                  = 0x50524E54,
    DumpHardwareBlock            = 0x2A504D44,
    TapeFileBlock                = 0x454C4654,
    TapePartitionBlock           = 0x54425054,
    CompactDiscIndexesBlock      = 0x58494443,
    AaruMetadataJsonBlock        = 0x444D534A
};

enum <byte> TrackType
{
    Audio = 0,
    Data = 1,
    CdMode1 = 2,
    CdMode2Formless = 3,
    CdMode2Form1 = 4,
    CdMode2Form2 = 5
};

enum <byte> ChecksumAlgorithm
{
    Invalid = 0,
    Md5 = 1,
    Sha1 = 2,
    Sha256 = 3,
    SpamSum = 4,
    Blake3 = 5
};

typedef enum<uint64> {
    AARU_FEATURE_RW_BLAKE3 = 0x1
} FeaturesCompatible <edit=flags>;

typedef struct
{
    char                   identifier[8];

    // Skip application name
    FSeek(0x48);

    byte                   imageMajorVersion;
    byte                   imageMinorVersion;

    // Go back to application name
    FSeek(0x08);

    if(imageMajorVersion >= 2)
        char               application[64];
    else
        wchar_t            application[32];

    // Move to after image version
    FSeek(0x4A);

    byte                   applicationMajorVersion;
    byte                   applicationMinorVersion;
    MediaType              mediaType;
    uint64                 indexOffset;
    FILETIME               creationTime;
    FILETIME               lastWrittenTime;

    if(imageMajorVersion >= 2)
    {
        GUID               guid;
        byte               blockAlignmentShift;
        uint16             biggestSectorSize;
        FeaturesCompatible featureCompatible;
        uint64             featureCompatibleRo;
        uint64             featureIncompatible;
    }
} AaruHeader;

typedef struct
{
    BlockType identifier;
    DataType type;
    CompressionType compression;
    byte shift;
    uint64 entries;
    uint64 cmpLength;
    uint64 length;
    uint64 cmpCrc64 <format=hex>;
    uint64 crc64 <format=hex>;
} DdtHeader;

typedef struct
{
    BlockType identifier;
    DataType type;
    CompressionType compression;
    byte levels;
    byte tableLevel;
    uint64 previousLevelOffset;
    uint32 negative;
    uint64 blocks;
    uint32 overflow;
    uint64 start;
    byte blockAlignmentShift;
    byte dataShift;
    byte tableShift;
    uint64 entries;
    uint64 cmpLength;
    uint64 length;
    uint64 cmpCrc64 <format=hex>;
    uint64 crc64 <format=hex>;
} Ddt2Header;

typedef struct
{
    BlockType blockType;
    DataType dataType;
    uint64 offset;
} IndexEntry;

typedef struct
{
    BlockType identifier;
    ushort entries;
    uint64 crc64 <format=hex>;
    IndexEntry items[entries];
} Index;

typedef struct
{
    BlockType identifier;
    uint64 entries;
    uint64 crc64 <format=hex>;
    IndexEntry items[entries];
} Index2;

typedef struct
{
    BlockType identifier;
    uint64 entries;
    uint64 crc64 <format=hex>;
    uint64 previous;
    IndexEntry items[entries];
} Index3;

typedef struct
{
    BlockType identifier;
    DataType type;
    CompressionType compression;
    uint sectorSize;
    uint cmpLength;
    uint length;
    uint64 cmpCrc64 <format=hex>;
    uint64 crc64 <format=hex>;
} BlockHeader;

typedef struct
{
    BlockType identifier;
    uint      cylinders;
    uint      heads;
    uint      sectorsPerTrack;
} GeometryBlock;

typedef struct
{
    BlockType identifier;
    uint blockSize;
    int mediaSequence;
    int lastMediaSequence;
    uint creatorOffset;
    uint creatorLength;
    uint commentsOffset;
    uint commentsLength;
    uint mediaTitleOffset;
    uint mediaTitleLength;
    uint mediaManufacturerOffset;
    uint mediaManufacturerLength;
    uint mediaModelOffset;
    uint mediaModelLength;
    uint mediaSerialNumberOffset;
    uint mediaSerialNumberLength;
    uint mediaBarcodeOffset;
    uint mediaBarcodeLength;
    uint mediaPartNumberOffset;
    uint mediaPartNumberLength;
    uint driveManufacturerOffset;
    uint driveManufacturerLength;
    uint driveModelOffset;
    uint driveModelLength;
    uint driveSerialNumberOffset;
    uint driveSerialNumberLength;
    uint driveFirmwareRevisionOffset;
    uint driveFirmwareRevisionLength;
} MetadataBlock;

typedef struct
{
    byte      sequence;
    TrackType type;
    int64      start;
    int64      end;
    int64      pregap;
    byte      session;
    char isrc[13];
    byte   flags;
} TrackEntry;

typedef struct
{
    BlockType identifier;
    ushort entries;
    uint64 crc64;
    TrackEntry tracks[entries];
} TracksHeader;

typedef struct
{
    BlockType identifier;
    uint length;
    char xml[length];
} CicmMetadataBlock;

typedef struct
{
    BlockType identifier;
    uint length;
    char json[length];
} AaruJsonMetadataBlock;

typedef struct
{
    uint64 start;
    uint64 end;
} DumpHardwareExtent;

typedef struct
{
    uint manufacturerLength;
    uint modelLength;
    uint revisionLength;
    uint firmwareLength;
    uint serialLength;
    uint softwareNameLength;
    uint softwareVersionLength;
    uint softwareOperatingSystemLength;
    uint extentCount;
    char manufacturer[manufacturerLength];
    char model[modelLength];
    char revision[revisionLength];
    char firmware[firmwareLength];
    char serial[serialLength];
    char softwareName[softwareNameLength];
    char softwareVersion[softwareVersionLength];
    char softwareOperatingSystem[softwareOperatingSystemLength];
    DumpHardwareExtent extents[extentCount];
} DumpHardwareEntry <optimize=false>;

typedef struct
{
    BlockType identifier;
    ushort entries;
    uint length;
    uint64 crc64 <format=hex>;
    DumpHardwareEntry dumpHardware[entries];
} DumpHardwareHeader <optimize=false>;

typedef struct
{
    ChecksumAlgorithm type;
    uint length;
    if(type == 4)
        char checksum[length] <format=hex>;
    else
        byte checksum[length] <format=hex>;
} ChecksumEntry <optimize=false>;

typedef struct
{
    BlockType identifier;
    uint length;
    byte entries;
    ChecksumEntry checksums[entries];
} ChecksumHeader;

typedef struct
{
    uint file;
    char partition;
    uint64 first_block;
    uint64 last_block;
} TapeFileEntry;

typedef struct
{
    BlockType identifier;
    uint entries;
    uint64 length;
    uint64 crc64 <format=hex>;
    TapeFileEntry files[entries];
} TapeFileHeader;

typedef struct
{
    byte number;
    uint64 first_block;
    uint64 last_block;
} TapePartitionEntry;

typedef struct
{
    BlockType identifier;
    byte entries;
    uint64 length;
    uint64 crc64 <format=hex>;
    TapePartitionEntry partitions[entries];
} TapePartitionHeader;

typedef struct
{
    uint16 track;
    uint16 index;
    uint32 lba;
} CompactDiscIndexEntry;

typedef struct
{
    BlockType identifier;
    uint16 entries;
    uint64 length;
    uint64 crc64 <format=hex>;
    CompactDiscIndexEntry indexes[entries];
} CompactDiscIndexesBlock;

LittleEndian();

local int i;

Assert(ReadUInt64() == DIC_MAGIC || ReadUInt64() == AARU_MAGIC, "Incorrect signature!");

AaruHeader header;

FSeek(header.indexOffset);
local uint idxid = ReadUInt();
FSeek(header.indexOffset);

switch(idxid)
{
    case IndexBlock:
        Index index;
        break;
    case IndexBlock2:
        Index2 index;
        break;
    case IndexBlock3:
        Index3 index;
        break;
    default:
        Warning("Unknown index format");
        Exit(1);
        break;
}

for(i = 0; i < index.entries; i++)
{
    FSeek(index.items[i].offset);
    switch(index.items[i].blockType)
    {
        case DataBlock:
            BlockHeader dataBlock;
            break;
        case DeDuplicationTable:
            DdtHeader deduplicationTable;
            break;
        case DeDuplicationTable2:
            Ddt2Header deduplicationTable2;
            break;
        case DeDuplicationTableSecondary:
            Ddt2Header deduplicationTableSecondary;
            break;
        case GeometryBlockId:
            GeometryBlock geometry;
            break;
        case MetadataBlockId:
            MetadataBlock metadata;
            if(metadata.creatorOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.creatorOffset);
                wchar_t Creator[metadata.creatorLength / 2];
            }
            if(metadata.commentsOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.commentsOffset);
                wchar_t Comments[metadata.commentsLength / 2];
            }
            if(metadata.mediaTitleOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.mediaTitleOffset);
                wchar_t MediaTitle[metadata.mediaTitleLength / 2];
            }
            if(metadata.mediaManufacturerOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.mediaManufacturerOffset);
                wchar_t MediaManufacturer[metadata.mediaManufacturerLength / 2];
            }
            if(metadata.mediaModelOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.mediaModelOffset);
                wchar_t MediaModel[metadata.mediaModelLength / 2];
            }
            if(metadata.mediaSerialNumberOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.mediaSerialNumberOffset);
                wchar_t MediaSerialNumber[metadata.mediaSerialNumberLength / 2];
            }
            if(metadata.mediaBarcodeOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.mediaBarcodeOffset);
                wchar_t MediaBarcode[metadata.mediaBarcodeLength / 2];
            }
            if(metadata.mediaPartNumberOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.mediaPartNumberOffset);
                wchar_t MediaPartNumber[metadata.mediaPartNumberLength / 2];
            }
            if(metadata.driveManufacturerOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.driveManufacturerOffset);
                wchar_t DriveManufacturer[metadata.driveManufacturerLength / 2];
            }
            if(metadata.driveModelOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.driveModelOffset);
                wchar_t DriveModel[metadata.driveModelLength / 2];
            }
            if(metadata.driveSerialNumberOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.driveSerialNumberOffset);
                wchar_t DriveSerialNumber[metadata.driveSerialNumberLength / 2];
            }
            if(metadata.driveFirmwareRevisionOffset > 0)
            {
                FSeek(index.items[i].offset + metadata.driveFirmwareRevisionOffset);
                wchar_t DriveFirmwareRevision[metadata.driveFirmwareRevisionLength / 2];
            }
            break;
        case TracksBlock:
            TracksHeader tracks;
            break;
        case CicmBlock:
            CicmMetadataBlock cicmMetadata;
            break;
        case AaruMetadataJsonBlock:
            AaruJsonMetadataBlock cicmMetadata;
            break;
        case DumpHardwareBlock:
            DumpHardwareHeader dumpHardware;
            break;
        case ChecksumBlock:
            ChecksumHeader checksum;
            break;
        case TapePartitionBlock:
            TapePartitionHeader partitions;
            break;
        case TapeFileBlock:
            TapeFileHeader files;
            break;
        case IndexBlock3: // TODO: Index Continuation
            Index3 index;
            break;
        case 0x2A4D5044: // TODO: Data Position Measurement
            break;
        case 0x58494443:
            CompactDiscIndexesBlock compactDiscIndexes;
            break;
    }
}