diff --git a/include/skip.h b/include/skip.h new file mode 100644 index 0000000..6d6b846 --- /dev/null +++ b/include/skip.h @@ -0,0 +1,57 @@ +/******************************************************************************/ +/* Skip File Format, skunkworks zip */ +/* */ +/* little-endian */ +/* */ +/* Main Header: */ +/* */ +/* bytes | what */ +/* ------+------------------------------------------------------------------- */ +/* 4 | 'SWZP' */ +/* 1 | version, currently 0x00 */ +/* 1 | compression format, currently only 0 supported, uncompressed */ +/* 4 | size of uncompressed data chunk */ +/* 4 | size of compressed data chunk (same as compressed if format 0) */ +/* 2 | file count */ +/* */ +/* File Header (appears 'file count' times in a row): */ +/* */ +/* bytes | what */ +/* ------+------------------------------------------------------------------- */ +/* 4 | offset from beginning of data chunk */ +/* 4 | file size (uncompressed) */ +/* 1 | length of filename */ +/* * | filename (not zero terminated) */ +/* */ +/* Rest of File: */ +/* */ +/* bytes | what */ +/* ------+------------------------------------------------------------------- */ +/* * | data chunk */ +/* 4 | length of file total (to easily find header if file is attached to */ +/* an executable) */ +/******************************************************************************/ + +#ifndef GUARD_62F584E45B48B8F6069643FC44702ED5 +#define GUARD_62F584E45B48B8F6069643FC44702ED5 + +#include "types.h" + +struct sw_skip { + u32 data_size; + u8 *data; + u16 file_count; + struct { + u32 offset; + u32 size; + char *name; + } *files; +}; + +struct sw_skip *sw_skip_create(); +struct sw_skip *sw_skip_load(char *filename); +void sw_skip_destroy(struct sw_skip *skip); + +void sw_skip_save(struct sw_skip *skip, char *filename); + +#endif /* GUARD_62F584E45B48B8F6069643FC44702ED5 */ diff --git a/src/skip.c b/src/skip.c new file mode 100644 index 0000000..cc87fcb --- /dev/null +++ b/src/skip.c @@ -0,0 +1,104 @@ +#include "skip.h" + +#include "error.h" +#include "file.h" +#include +#include +#include + +struct sw_skip *sw_skip_create() { + struct sw_skip *skip; + + skip = calloc(1, sizeof(struct sw_skip)); + + return skip; +} + +struct sw_skip *sw_skip_load(char *filename) { + FILE *fil; + struct sw_skip *skip; + char magic[5] = {0}; + u8 version, compression; + u16 i; + char str[257]; + u8 str_len; + + skip = sw_skip_create(); + fil = fopen(filename, "rb"); + + fread(magic, 1, 4, fil); + if(strcmp("SWZP", magic) != 0) { + sw_error("not a .skip file"); + } + + fread(&version, 1, 1, fil); + if(version > 0) { + sw_error("version %i of .skip not supported", version); + } + + fread(&compression, 1, 1, fil); + if(compression > 0) { + sw_error("unsupported .skip compression method"); + } + + fread(&skip->data_size, 1, 4, fil); + fseek(fil, 4, SEEK_CUR); /* ignore compressed size */ + fread(&skip->file_count, 1, 2, fil); + + skip->files = malloc(sizeof(skip->files[0]) * skip->file_count); + + for(i = 0; i < skip->file_count; ++i) { + memset(str, 0, 257); + fread(&skip->files[i].offset, 1, 4, fil); + fread(&skip->files[i].size, 1, 4, fil); + fread(&str_len, 1, 1, fil); + fread(str, str_len, 1, fil); + str[str_len] = 0; + + skip->files[i].name = malloc(str_len + 1); + strcpy(skip->files[i].name, str); + } + + fclose(fil); + return skip; +} + +void sw_skip_destroy(struct sw_skip *skip) { + i32 i; + + for(i = 0; i < skip->file_count; ++i) { + free(skip->files[i].name); + } + free(skip->files); + free(skip->data); + free(skip); +} + +void sw_skip_save(struct sw_skip *skip, char *filename) { + FILE *fil; + u32 size; + u16 i; + + size = 0; + for(i = 0; i < skip->file_count; ++i) { + size += skip->files[i].size; + } + + fil = fopen(filename, "wb"); + sw_fwrite_str_nozero(fil, "SWZP"); + sw_fwrite_u8(fil, 0); /* version */ + sw_fwrite_u8(fil, 0); /* compression */ + sw_fwrite_u32(fil, size); /* uncompressed size */ + sw_fwrite_u32(fil, size); /* compressed size */ + sw_fwrite_u16(fil, skip->file_count); /* file count */ + + for(i = 0; i < skip->file_count; ++i) { + sw_fwrite_u32(fil, skip->files[i].offset); /* offset */ + sw_fwrite_u32(fil, skip->files[i].size); /* file size */ + sw_fwrite_str_prefix8(fil, skip->files[i].name); /* file name */ + } + + sw_fwrite_u32(fil, ftell(fil) + 4); /* file length */ + + fclose(fil); +}