diff --git a/DiskFile.h b/DiskFile.h index d00472c..612e524 100644 --- a/DiskFile.h +++ b/DiskFile.h @@ -9,4 +9,8 @@ typedef struct DiskFile { uint64_t length; } DiskFile; +DiskFile * iso9660_enumfiles(); +DiskFile * iso9660_fopen_r(const char *filename); +DiskFile * iso9660_fopen_w(const char *filename); + #endif diff --git a/Makefile b/Makefile index 4f6621e..bf993cb 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ ZCODE_FILES = $(wildcard zcode/*.z*) IMAGE_FILES += $(patsubst %.z5,%.iso,$(ZCODE_FILES)) IMAGE_FILES += $(patsubst %.z8,%.iso,$(ZCODE_FILES)) -all: frotz.bin frotz.elf kernel.bin LostPig.iso +all: frotz.bin frotz.elf kernel.bin LostPig.iso.zip # $(IMAGE_FILES) $(FROTZLIB): @@ -145,6 +145,12 @@ LostPig.iso: LostPig.z8 bootkernel.bin isoboot.bin frotz.bin .c.o: gcc -c $(CFLAGS) -o $@ $< +tools/iso2zip: tools/iso2zip.c + gcc -o $@ $< + +%.iso.zip: %.iso tools/iso2zip + ./tools/iso2zip $< + clean: make -C $(FROTZDIR) clean diff --git a/iso9660.h b/iso9660.h index c948e0b..52d191d 100644 --- a/iso9660.h +++ b/iso9660.h @@ -2,8 +2,6 @@ #define ISO9660_H_ #include -#include "DiskFile.h" -#include "x86.h" typedef uint8_t u8; typedef uint16_t u16; @@ -87,10 +85,5 @@ typedef struct PrimaryVolumeDescriptor { u8 application_data[512]; u8 __unused5; } PrimaryVolumeDescriptor; -DiskFile * iso9660_enumfiles(); -DiskFile * iso9660_fopen_r(const char *filename); -DiskFile * iso9660_fopen_w(const char *filename); - -DONT_EMIT const void * iso9660_file_data(const DiskFile *df) { return df->data; } #endif diff --git a/stdio.c b/stdio.c index 39e5df2..959370b 100644 --- a/stdio.c +++ b/stdio.c @@ -1,7 +1,7 @@ #include #include #include -#include "iso9660.h" +#include "DiskFile.h" #include "kernel.h" FILE *fopen(const char *path, const char *mode) diff --git a/tools/iso2zip.c b/tools/iso2zip.c new file mode 100644 index 0000000..e49897d --- /dev/null +++ b/tools/iso2zip.c @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "../iso9660.h" + +#include "zip_crc32.c" + +#define ERRNO(X) if ((X) < 0) { perror(#X); } + +#define SECTOR_SIZE 2048 +#define PACKED __attribute__ ((__packed__)) + +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +typedef struct PACKED { + u32 signature; + u16 version_needed; + u16 bit_flags; + u16 method; + u16 time; + u16 date; + u32 crc32; + u32 comp_size; + u32 uncomp_size; + u16 filename_len; + u16 extra_len; + char filename[]; +// char m_extra[]; +} ZipLocalFileHeader; + +typedef struct PACKED { + u32 signature; + u16 version_made_by; + u16 version_needed; + u16 bit_flags; + u16 method; + u16 date; + u16 time; + u32 crc32; + u32 comp_size; + u32 uncomp_size; + u16 filename_len; + u16 extra_len; + u16 comment_len; + u16 disknum_start; + u16 internal_attr; + u32 external_attr; + u32 local_header_ofs; + char filename[]; +// char m_extra[]; +// char m_comment[]; +} ZipCentralDirFileHeader; + +typedef struct PACKED { + u32 signature; + u16 disk_num; + u16 disk_start; + u16 disk_num_records; + u16 total_num_records; + u32 central_dir_bytes; + u32 central_dir_start; // relative to start of archive + u16 comment_len; + u8 comment[]; +} ZipEndCentralDirRecord; + +void +create_zip_hdrs(ZipLocalFileHeader **out_lhdr, int *out_lhdr_len, + ZipCentralDirFileHeader **out_chdr, int *out_chdr_len, + const char *fn, int filesize) +{ + size_t fnlen = strlen(fn); + size_t extralen = 0; // SECTOR_SIZE - (filesize % SECTOR_SIZE); // XXX: whole extra sector if mod == 0 + size_t lhdrlen = sizeof(ZipLocalFileHeader) + fnlen + extralen; + ZipLocalFileHeader * lhdr = (ZipLocalFileHeader *) malloc(lhdrlen); + + lhdr->signature = 0x04034b50; + lhdr->version_needed = 0x00; + lhdr->bit_flags = 0x00; + lhdr->method = 0x00; + lhdr->time = 0x00; + lhdr->date = 0x00; + lhdr->crc32 = 0x00; + lhdr->comp_size = lhdr->uncomp_size = filesize; + lhdr->filename_len = fnlen; + lhdr->extra_len = extralen; + strcpy(lhdr->filename, fn); + + size_t chdrlen = sizeof(ZipCentralDirFileHeader) + fnlen; + ZipCentralDirFileHeader * chdr = (ZipCentralDirFileHeader *) malloc(chdrlen); + chdr->signature = 0x02014b50; + chdr->version_made_by = 0x00; + chdr->version_needed = 0x00; + chdr->bit_flags = 0x00; + chdr->method = 0x00; + chdr->date = 0x00; + chdr->time = 0x00; + chdr->crc32 = 0x00; + chdr->comp_size = chdr->uncomp_size = filesize; + chdr->filename_len = fnlen; + chdr->extra_len = extralen; + chdr->comment_len = 0; + chdr->disknum_start = 0; + chdr->internal_attr = 0x00; + chdr->external_attr = 0x00; + chdr->local_header_ofs = 0; + strcpy(chdr->filename, fn); +// char m_extra[]; +// char m_comment[]; +// + *out_lhdr = lhdr; + *out_lhdr_len = lhdrlen; + *out_chdr = chdr; + *out_chdr_len = chdrlen; +} + +#define SECTOR(N) (isoptr + (N) * SECTOR_SIZE) +#define NEXT_ENTRY(E) \ + ((const DirectoryRecord *) (((const u8 *) E) + E->record_len)) + +const DirectoryRecord *find_file_at_sector(void *isoptr, int sector_num) +{ + const PrimaryVolumeDescriptor *pvd = SECTOR(16); + const DirectoryRecord *rootrecord = &pvd->root_directory_record; + const DirectoryRecord *entry = SECTOR(rootrecord->data_sector); + for (; entry->record_len != 0; entry = NEXT_ENTRY(entry)) + { + int start = entry->data_sector; + int end = entry->data_sector + entry->data_len / SECTOR_SIZE; + + if (sector_num >= start && sector_num <= end) + { + return entry; + } + } + return NULL; +} + +int +main(int argc, char **argv) +{ + assert(crc32("123456789", 9) == 0xcbf43926); + assert(sizeof(ZipLocalFileHeader) == 30); + assert(sizeof(ZipCentralDirFileHeader) == 46); + assert(sizeof(ZipEndCentralDirRecord) == 22); + + char outfn[256]; + snprintf(outfn, 256, "%s.zip", argv[1]); + + int fdiso = open(argv[1], O_RDONLY); + ERRNO(fdiso); + + int fdout = open(outfn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + ERRNO(fdout); + + struct stat st; + ERRNO(fstat(fdiso, &st)); + + size_t isosize = st.st_size; + + void *isoptr = mmap(NULL, isosize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fdiso, 0); + + if (isoptr == MAP_FAILED) { + perror("mmap"); + exit(-1); + } + + const PrimaryVolumeDescriptor *pvd = SECTOR(16); + printf("# sectors=%d\n", pvd->num_sectors); + const DirectoryRecord *rootrecord = &pvd->root_directory_record; + assert(rootrecord->record_len == sizeof(DirectoryRecord) + rootrecord->id_len); + + ZipCentralDirFileHeader *cdir_entries[256] = { NULL }; + int num_files = 0; + + const DirectoryRecord *entry = SECTOR(rootrecord->data_sector); + + for (; entry->record_len > 0; entry = NEXT_ENTRY(entry)) + { + char fn[256] = { 0 }; + strncpy(fn, entry->id, entry->id_len); + + if (entry->id[0] == 0x0) { + fn[0] = '.'; + } else if (entry->id[0] == 0x01) { + fn[0] = '.'; + fn[1] = '.'; + } + + printf("CD file: %s at sector %d (%u bytes)\n", + fn, entry->data_sector, entry->data_len); + + if (fn[0] == '.') { + continue; + } + + const DirectoryRecord *prev_file = find_file_at_sector(isoptr, entry->data_sector - 1); + int prev_filesize = prev_file->data_len; + int leftover = SECTOR_SIZE - (prev_filesize % SECTOR_SIZE); + + if (leftover == SECTOR_SIZE) { + leftover = 0; + } + + ZipLocalFileHeader *local_hdr = NULL; + int localhdr_len = -1; + int centdirhdr_len = -1; + + create_zip_hdrs(&local_hdr, &localhdr_len, + &cdir_entries[num_files], ¢dirhdr_len, + fn, + entry->data_len); + + uint32_t crc = crc32( SECTOR(entry->data_sector), entry->data_len); + + cdir_entries[num_files]->crc32 = local_hdr->crc32 = crc; + + if (leftover >= localhdr_len) { + void *lhdr = SECTOR(entry->data_sector) - localhdr_len; + memcpy(lhdr, local_hdr, localhdr_len); + size_t lhdr_fpos = (entry->data_sector) * SECTOR_SIZE - localhdr_len; + cdir_entries[num_files]->local_header_ofs = lhdr_fpos; + num_files++; + } else { + + // need to insert + printf("not putting %s in .zip due to not enough leftover space in previous file (%d/%d)\n", fn, leftover, localhdr_len); + } + +/* + // for local file header + struct added_sector { + + }; + // note when writing, before the to add a sector + prepend_sectors_at[num_added_sectors++] = entry->data_sector; + + // increase by 1 the LBA for anything after this sector (in the mmap) + + actually, if leftover of file ending in previous sector is < this + + for each entry in the LSB path table + if location of extent >= this file's starting sector, + increment + + for each entry in the MSB path table + same, but don't forget to BSWAP + + for each entry in the root directory, + bump LBA extent in both LSB and MSB if >= as above + + // insert sector, adjust all tables + // + } +*/ + } + + assert (isosize % SECTOR_SIZE == 0); + + int i=0; + while (i < isosize) + { + ssize_t r = write(fdout, isoptr + i, SECTOR_SIZE); + assert (r == SECTOR_SIZE); + i += r; + } + + int cdirpos = i; + + // and now to write out the .zip central directory + + int cdir_len = 0; + for (num_files=0; cdir_entries[num_files]; ++num_files) + { + size_t entry_len = sizeof(ZipCentralDirFileHeader) + cdir_entries[num_files]->filename_len; + ssize_t r = write(fdout, cdir_entries[num_files], entry_len); + assert(r == entry_len); + + cdir_len += r; + } + + ZipEndCentralDirRecord endcdir; + endcdir.signature = 0x06054b50; + endcdir.disk_num = 0; + endcdir.disk_start = 0; + endcdir.disk_num_records = endcdir.total_num_records = num_files; + endcdir.central_dir_bytes = cdir_len; + endcdir.central_dir_start = cdirpos; + endcdir.comment_len = 0; + + ssize_t r = write(fdout, &endcdir, sizeof(ZipEndCentralDirRecord)); + assert(r == sizeof(ZipEndCentralDirRecord)); + + munmap(isoptr, isosize); + close(fdiso); + close(fdout); +} diff --git a/tools/zip_crc32.c b/tools/zip_crc32.c new file mode 100644 index 0000000..f6c482e --- /dev/null +++ b/tools/zip_crc32.c @@ -0,0 +1,53 @@ +#include + +uint32_t crc32(const uint8_t *buf, size_t bufLen) +{ + static const unsigned long crcTable[256] = { + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535, + 0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD, + 0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D, + 0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC, + 0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4, + 0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C, + 0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,0x26D930AC, + 0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, + 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB, + 0xB6662D3D,0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F, + 0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB, + 0x086D3D2D,0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E, + 0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA, + 0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,0x4DB26158,0x3AB551CE, + 0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A, + 0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409, + 0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81, + 0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739, + 0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8, + 0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,0xF00F9344,0x8708A3D2,0x1E01F268, + 0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0, + 0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8, + 0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, + 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF, + 0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703, + 0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7, + 0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A, + 0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE, + 0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242, + 0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6, + 0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D, + 0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5, + 0x47B2CF7F,0x30B5FFE9,0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605, + 0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94, + 0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D }; + uint32_t crc32; + size_t i; + + /** accumulate crc32 for buffer **/ + crc32 = 0xFFFFFFFF; + for (i=0; i < bufLen; i++) { + crc32 = (crc32 >> 8) ^ crcTable[ (crc32 ^ buf[i]) & 0xFF ]; + } + return( crc32 ^ 0xFFFFFFFF ); +} +