#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv)
{
    char id[128];
    memset(&id,0,128);
    if(argv[1]==NULL) {
        printf("No iso given\n");
        return 1;
    }
    FILE *f=fopen(argv[1],"ro");
    unsigned char *buf=malloc(65536*2),c;
    fread(buf,65536,2,f);
    fclose(f);

    if(memcmp(buf+32768+1,"CD001",5)) {
        printf("Not an iso file\n");
        return 2;
    }

    int i,j,bootcat,rootdir;
    printf("Descriptors:\n");
    for(i=0;i<128;i++) {
        c=buf[32768+i*2048];
        printf("  %x: %d ", 32768+i*2048, c);
        if(c==0) {
            printf("Boot record\n    Version: %d\n", buf[32768+i*2048+6]);
            printf("    Identifier: '%s'\n", &buf[32768+i*2048+7]);
            bootcat=*((int*)&buf[32768+i*2048+0x47]);
            printf("    Boot catalog: %d (%x)\n", bootcat, bootcat*2048);
        }
        if(c==1) {
            printf("Primary Volume Descriptor\n");
            memcpy((char*)&id,&buf[32768+8],32);
            printf("    System Identifier: '%s'\n",&id);
            printf("    Volume Identifier: '%s'\n",&buf[32768+40]);
            printf("    Volume Size: %d\n",*((int*)&buf[32768+80]));
            printf("    Volume Set Size: %02x%02x\n",buf[32768+121],buf[32768+120]);
            printf("    Volume Sequence: %02x%02x\n",buf[32768+125],buf[32768+124]);
            printf("    Block Size: %02x%02x\n",buf[32768+129],buf[32768+128]);
            printf("    Path Size: %d\n",*((int*)&buf[32768+132]));
            printf("    Type L Path: %02x%02x\n",buf[32768+141],buf[32768+140]);
            printf("    Type L Opt Path: %02x%02x\n",buf[32768+145],buf[32768+144]);
            printf("    Type M Path: %02x%02x\n",buf[32768+149],buf[32768+148]);
            printf("    Type M Opt Path: %02x%02x\n",buf[32768+153],buf[32768+152]);
            printf("    Root Directory Size: %02x\n",buf[32768+156]);
            printf("    Root Directory Extended Attribute length: %02x\n",buf[32768+157]);
            rootdir=*((int*)&buf[32768+158]);
            printf("    Root Directory Extent: %d (%x)\n",rootdir,rootdir*2048);
            printf("    Root Directory Datasize: %d\n",*((int*)&buf[32768+166]));
            printf("    Root Directory Date: %d-%02d-%02d %02d:%02d:%02d GMT+%d\n",buf[32768+174]+1900,buf[32768+175],buf[32768+176],
                buf[32768+177],buf[32768+178],buf[32768+179],buf[32768+180]);
            printf("    Root Directory Flags: %02x\n",buf[32768+181]);
            printf("    Root Directory Unitsize: %02x\n",buf[32768+182]);
            printf("    Root Directory Interleave: %02x\n",buf[32768+183]);
            printf("    Root Directory Sequence: %02x%02x\n",buf[32768+185],buf[32768+184]);
            printf("    Root Directory Filename len: %02x\n",buf[32768+188]);
            printf("    Root Directory Filename: '%s'\n",(char*)&buf[32768+189]);
            memcpy((char*)&id,&buf[32768+190],127);
            printf("    Volume Set Identifier:  '%s'\n",(char*)&id);
            memcpy((char*)&id,&buf[32768+318],127);
            printf("    Publisher Identifier:   '%s'\n",&id);
            memcpy((char*)&id,&buf[32768+446],127);
            printf("    Preparer Identifier:    '%s'\n",&id);
            memcpy((char*)&id,&buf[32768+574],127);
            printf("    Application Identifier: '%s'\n",&id);
            printf("    Creation: '%s'\n",&buf[32768+813]);
            printf("    Modification: '%s'\n",&buf[32768+830]);
            printf("    Expiration: '%s'\n",&buf[32768+847]);
            printf("    Effective: '%s'\n",&buf[32768+864]);
            printf("    Structure version: %02x\n",buf[32768+881]);
        }
        if(c==255||c==-1) {
            printf("Terminator\n");
            break;
        }
    }
    printf("\n");

    if(bootcat) {
        printf("Boot catalog:\n");
        printf("  %x: Validation entry\n", bootcat*2048);
        printf("    Header id: %02x\n",buf[bootcat*2048]);
        printf("    Platform: %02x\n",buf[bootcat*2048+1]);
        printf("    Identifier: '%s'\n", &buf[bootcat*2048+4]);
        printf("    Chksum: %02x%02x\n",buf[bootcat*2048+29],buf[bootcat*2048+28]);
        printf("  %x: Initial/default entry\n", bootcat*2048+32);
        printf("    Bootable: %02x\n",buf[bootcat*2048+32]);
        printf("    Media type: %02x\n",buf[bootcat*2048+33]);
        printf("    Load segment: %x\n",buf[bootcat*2048+35]*256+buf[bootcat*2048+34]);
        printf("    System type: %02x\n", buf[bootcat*2048+36]);
        printf("    Sector count: %x\n",buf[bootcat*2048+39]*256+buf[bootcat*2048+38]);
        printf("    Sector LBA: %x\n", *((int*)&buf[bootcat*2048+40]));
        printf("  %x: Section header\n", bootcat*2048+64);
        printf("    Header id: %02x\n",buf[bootcat*2048+64]);
        printf("    Platform: %02x\n",buf[bootcat*2048+65]);
        printf("    Numentries: %02x\n",buf[bootcat*2048+66]);
        printf("    Identifier: '%s'\n", &buf[bootcat*2048+68]);
        printf("  %x: Section entry\n", bootcat*2048+96);
        printf("    Bootable: %02x\n",buf[bootcat*2048+96]);
        printf("    Media type: %02x\n",buf[bootcat*2048+97]);
        printf("    Load segment: %x\n",buf[bootcat*2048+99]*256+buf[bootcat*2048+98]);
        printf("    System type: %02x\n", buf[bootcat*2048+100]);
        printf("    Sector count: %x\n",buf[bootcat*2048+103]*256+buf[bootcat*2048+102]);
        printf("    Sector LBA: %x (%x)\n", *((int*)&buf[bootcat*2048+104]),*((int*)&buf[bootcat*2048+104])*2048);
        printf("\n");
    }

    if(rootdir) {
        printf("Root directory:\n");
        i=0;
        while(buf[rootdir*2048+i]) {
            memset(&id,0,128);
            printf("  %x: length %x\n",rootdir*2048+i,(unsigned char)buf[rootdir*2048+i]);
            printf("    Extended Attribute length: %02x\n",buf[rootdir*2048+i+1]);
            printf("    Extent LBA: %d (%x)\n",*((int*)&buf[rootdir*2048+i+2]),*((int*)&buf[rootdir*2048+i+2])*2048);
            printf("    Datasize: %d\n",*((int*)&buf[rootdir*2048+i+10]));
            printf("    Date: %d-%02d-%02d %02d:%02d:%02d GMT+%d\n",buf[rootdir*2048+i+18]+1900,buf[rootdir*2048+i+19],buf[rootdir*2048+i+20],
                buf[rootdir*2048+i+21],buf[rootdir*2048+i+22],buf[rootdir*2048+i+23],buf[rootdir*2048+i+24]);
            printf("    Flags: %02x\n",buf[rootdir*2048+i+25]);
            printf("    Unitsize: %02x\n",buf[rootdir*2048+i+26]);
            printf("    Interleave: %02x\n",buf[rootdir*2048+i+27]);
            printf("    Sequence: %02x\n",buf[rootdir*2048+i+28]);
            memcpy(&id,&buf[rootdir*2048+i+33],buf[rootdir*2048+i+32]);
            printf("    Filename: %d (%02x %02x...) '%s'\n",buf[rootdir*2048+i+32],id[0],id[1],!id[0] ? "." : ( id[0]==1 ? ".." : id));
            j=(unsigned char)buf[rootdir*2048+i+32]+33+(buf[rootdir*2048+i+32]&1);
            printf("    Extra bytes: ");
            for(;j<(unsigned char)buf[rootdir*2048+i];j++) printf("%02x ", (unsigned char)buf[rootdir*2048+i+j]);
            printf("\n");
            i+=(unsigned char)buf[rootdir*2048+i];
        }
        printf("  %x: last\n",rootdir*2048+i);
    }
}
