X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=samples%2Fgunzip65.c;h=9d21c2137c27dbfb296e426a63854adb8788877c;hb=f328481a480e253a86dd74598dc8c5044fb574e3;hp=3b84982b756544507dc25e90a3b1bd40eb675d17;hpb=0f9f3d6abd7caf134b4c2dd45d24ac3d762f2e50;p=cc65 diff --git a/samples/gunzip65.c b/samples/gunzip65.c index 3b84982b7..9d21c2137 100644 --- a/samples/gunzip65.c +++ b/samples/gunzip65.c @@ -1,228 +1,240 @@ /* - * gunzip65 - a gunzip utility for 6502-based machines. - * - * Piotr Fusik - * - * This should be considered as a test of my zlib-compatible library - * rather than a real application. - * It's not user-friendly, fault-tolerant, whatever. - * However, it really works for real GZIP files, provided they are small - * enough to fit in buffer[] (after decompression!). - */ +** gunzip65 - a gunzip utility for 6502-based machines. +** +** Piotr Fusik +** +** This should be considered as a test of my zlib-compatible library +** rather than a real application. +** It's not user-friendly, fault-tolerant, whatever. +** However, it really works for real GZIP files, provided they are small +** enough to fit in buffer[] (after decompression!). +*/ #include #include #include +#ifdef __CC65__ +#include +#include +#endif + #ifndef __CC65__ /* - * Emulate inflatemem() if using original zlib. - * As you can see, this program is quite portable. - */ +** Emulate inflatemem() if using original zlib. +** As you can see, this program is quite portable. +*/ unsigned inflatemem(char* dest, const char* source) { - z_stream stream; + z_stream stream; - stream.next_in = (Bytef*) source; - stream.avail_in = 65535; + stream.next_in = (Bytef*) source; + stream.avail_in = 65535; - stream.next_out = dest; - stream.avail_out = 65535; + stream.next_out = dest; + stream.avail_out = 65535; - stream.zalloc = (alloc_func) 0; - stream.zfree = (free_func) 0; + stream.zalloc = (alloc_func) 0; + stream.zfree = (free_func) 0; - inflateInit2(&stream, -MAX_WBITS); - inflate(&stream, Z_FINISH); - inflateEnd(&stream); + inflateInit2(&stream, -MAX_WBITS); + inflate(&stream, Z_FINISH); + inflateEnd(&stream); - return stream.total_out; + return stream.total_out; } #endif /* __CC65__ */ /* - * Structure of a GZIP file: - * - * 1. GZIP header: - * Offset 0: Signature (2 bytes: 0x1f, 0x8b) - * Offset 2: Compression method (1 byte: 8 == "deflate") - * Offset 3: Flags (1 byte: see below) - * Offset 4: File date and time (4 bytes) - * Offset 8: Extra flags (1 byte) - * Offset 9: Target OS (1 byte: DOS, Amiga, Unix, etc.) - * if (flags & FEXTRA) { 2 bytes of length, then length bytes } - * if (flags & FNAME) { ASCIIZ filename } - * if (flags & FCOMMENT) { ASCIIZ comment } - * if (flags & FHCRC) { 2 bytes of CRC } - * - * 2. Deflate compressed data. - * - * 3. GZIP trailer: - * Offset 0: CRC-32 (4 bytes) - * Offset 4: uncompressed file length (4 bytes) - */ +** Structure of a GZIP file: +** +** 1. GZIP header: +** Offset 0: Signature (2 bytes: 0x1f, 0x8b) +** Offset 2: Compression method (1 byte: 8 == "deflate") +** Offset 3: Flags (1 byte: see below) +** Offset 4: File date and time (4 bytes) +** Offset 8: Extra flags (1 byte) +** Offset 9: Target OS (1 byte: DOS, Amiga, Unix, etc.) +** if (flags & FEXTRA) { 2 bytes of length, then length bytes } +** if (flags & FNAME) { ASCIIZ filename } +** if (flags & FCOMMENT) { ASCIIZ comment } +** if (flags & FHCRC) { 2 bytes of CRC } +** +** 2. Deflate compressed data. +** +** 3. GZIP trailer: +** Offset 0: CRC-32 (4 bytes) +** Offset 4: uncompressed file length (4 bytes) +*/ /* Flags in the GZIP header. */ -#define FTEXT 1 /* Extra text */ -#define FHCRC 2 /* Header CRC */ -#define FEXTRA 4 /* Extra field */ -#define FNAME 8 /* File name */ -#define FCOMMENT 16 /* File comment */ +#define FTEXT 1 /* Extra text */ +#define FHCRC 2 /* Header CRC */ +#define FEXTRA 4 /* Extra field */ +#define FNAME 8 /* File name */ +#define FCOMMENT 16 /* File comment */ /* - * We read whole GZIP file into this buffer. - * Then we use this buffer for the decompressed data. - */ +** We read whole GZIP file into this buffer. +** Then we use this buffer for the decompressed data. +*/ static unsigned char buffer[26000]; /* - * Get a 16-bit little-endian unsigned number, using unsigned char* p. - * On many machines this could be (*(unsigned short*) p), - * but I really like portability. :-) - */ +** Get a 16-bit little-endian unsigned number, using unsigned char* p. +** On many machines this could be (*(unsigned short*) p), +** but I really like portability. :-) +*/ #define GET_WORD(p) (*(p) + ((unsigned) (p)[1] << 8)) /* Likewise, for a 32-bit number. */ #define GET_LONG(p) (GET_WORD(p) + ((unsigned long) GET_WORD(p + 2) << 16)) /* - * Uncompress a GZIP file. - * On entry, buffer[] should contain the whole GZIP file contents, - * and the argument complen should be equal to the length of the GZIP file. - * On return, buffer[] contains the uncompressed data, and the returned - * value is the length of the uncompressed data. - */ +** Uncompress a GZIP file. +** On entry, buffer[] should contain the whole GZIP file contents, +** and the argument complen should be equal to the length of the GZIP file. +** On return, buffer[] contains the uncompressed data, and the returned +** value is the length of the uncompressed data. +*/ unsigned uncompress_buffer(unsigned complen) { - unsigned char* ptr; - unsigned long crc; - unsigned long unclen; - void* ptr2; - unsigned unclen2; - - /* check GZIP signature */ - if (buffer[0] != 0x1f || buffer[1] != 0x8b) { - puts("Not GZIP format"); - return 0; - } - - /* check compression method (it is always (?) "deflate") */ - if (buffer[2] != 8) { - puts("Unsupported compression method"); - return 0; - } - - /* get CRC from GZIP trailer */ - crc = GET_LONG(buffer + complen - 8); - - /* get uncompressed length from GZIP trailer */ - unclen = GET_LONG(buffer + complen - 4); - if (unclen > sizeof(buffer)) { - puts("Uncompressed size too big"); - return 0; - } - - /* skip extra field, file name, comment and crc */ - ptr = buffer + 10; - if (buffer[3] & FEXTRA) - ptr = buffer + 12 + GET_WORD(buffer + 10); - if (buffer[3] & FNAME) - while (*ptr++ != 0); - if (buffer[3] & FCOMMENT) - while (*ptr++ != 0); - if (buffer[3] & FHCRC) - ptr += 2; - - /* - * calculate length of raw "deflate" data - * (without the GZIP header and 8-byte trailer) - */ - complen -= (ptr - buffer) + 8; - - /* - * We will move the compressed data to the end of buffer[]. - * Thus the compressed data and the decompressed data (written from - * the beginning of buffer[]) may overlap, as long as the decompressed - * data doesn't go further than unread compressed data. - * ptr2 points to the beginning of compressed data at the end - * of buffer[]. - */ - ptr2 = buffer + sizeof(buffer) - complen; - /* move the compressed data to end of buffer[] */ - memmove(ptr2, ptr, complen); - - /* uncompress */ - puts("Inflating..."); - unclen2 = inflatemem(buffer, ptr2); - - /* verify uncompressed length */ - if (unclen2 != (unsigned) unclen) { - puts("Uncompressed size does not match"); - return 0; - } - - /* verify CRC */ - puts("Calculating CRC..."); - if (crc32(crc32(0L, Z_NULL, 0), buffer, unclen2) != crc) { - puts("CRC mismatch"); - return 0; - } - - /* return number of uncompressed bytes */ - return unclen2; + unsigned char* ptr; + unsigned long crc; + unsigned long unclen; + void* ptr2; + unsigned unclen2; + + /* check GZIP signature */ + if (buffer[0] != 0x1f || buffer[1] != 0x8b) { + puts("Not GZIP format"); + return 0; + } + + /* check compression method (it is always (?) "deflate") */ + if (buffer[2] != 8) { + puts("Unsupported compression method"); + return 0; + } + + /* get CRC from GZIP trailer */ + crc = GET_LONG(buffer + complen - 8); + + /* get uncompressed length from GZIP trailer */ + unclen = GET_LONG(buffer + complen - 4); + if (unclen > sizeof(buffer)) { + puts("Uncompressed size too big"); + return 0; + } + + /* skip extra field, file name, comment and crc */ + ptr = buffer + 10; + if (buffer[3] & FEXTRA) + ptr = buffer + 12 + GET_WORD(buffer + 10); + if (buffer[3] & FNAME) + while (*ptr++ != 0); + if (buffer[3] & FCOMMENT) + while (*ptr++ != 0); + if (buffer[3] & FHCRC) + ptr += 2; + + /* + ** calculate length of raw "deflate" data + ** (without the GZIP header and 8-byte trailer) + */ + complen -= (ptr - buffer) + 8; + + /* + ** We will move the compressed data to the end of buffer[]. + ** Thus the compressed data and the decompressed data (written from + ** the beginning of buffer[]) may overlap, as long as the decompressed + ** data doesn't go further than unread compressed data. + ** ptr2 points to the beginning of compressed data at the end + ** of buffer[]. + */ + ptr2 = buffer + sizeof(buffer) - complen; + /* move the compressed data to end of buffer[] */ + memmove(ptr2, ptr, complen); + + /* uncompress */ + puts("Inflating..."); + unclen2 = inflatemem(buffer, ptr2); + + /* verify uncompressed length */ + if (unclen2 != (unsigned) unclen) { + puts("Uncompressed size does not match"); + return 0; + } + + /* verify CRC */ + puts("Calculating CRC..."); + if (crc32(crc32(0L, Z_NULL, 0), buffer, unclen2) != crc) { + puts("CRC mismatch"); + return 0; + } + + /* return number of uncompressed bytes */ + return unclen2; } /* - * Get a filename from standard input. - */ +** Get a filename from standard input. +*/ char* get_fname(void) { - static char filename[100]; - unsigned len; - fgets(filename, sizeof(filename), stdin); - len = strlen(filename); - if (len >= 1 && filename[len - 1] == '\n') - filename[len - 1] = '\0'; - return filename; + static char filename[100]; + unsigned len; + fgets(filename, sizeof(filename), stdin); + len = strlen(filename); + if (len >= 1 && filename[len - 1] == '\n') + filename[len - 1] = '\0'; + return filename; } int main(void) { - FILE* fp; - unsigned length; - - /* read GZIP file */ - puts("GZIP file name:"); - fp = fopen(get_fname(), "rb"); - if (!fp) { - puts("Can't open GZIP file"); - return 1; - } - length = fread(buffer, 1, sizeof(buffer), fp); - fclose(fp); - if (length == sizeof(buffer)) { - puts("File is too long"); - return 1; - } - - /* decompress */ - length = uncompress_buffer(length); - if (length == 0) - return 1; - - /* write uncompressed file */ - puts("Uncompressed file name:"); - fp = fopen(get_fname(), "wb"); - if (!fp) { - puts("Can't create output file"); - return 1; - } - if (fwrite(buffer, 1, length, fp) != length) { - puts("Error while writing output file"); - return 1; - } - fclose(fp); - - puts("Ok."); - return 0; + FILE* fp; + unsigned length; + +#ifdef __CC65__ + /* allow user to read exit messages */ + if (doesclrscrafterexit()) { + atexit((void (*)) getchar); + } +#endif /* __CC65__ */ + + /* read GZIP file */ + puts("GZIP file name:"); + fp = fopen(get_fname(), "rb"); + if (!fp) { + puts("Can't open GZIP file"); + return 1; + } + length = fread(buffer, 1, sizeof(buffer), fp); + fclose(fp); + if (length == sizeof(buffer)) { + puts("File is too long"); + return 1; + } + + /* decompress */ + length = uncompress_buffer(length); + if (length == 0) + return 1; + + /* write uncompressed file */ + puts("Uncompressed file name:"); + fp = fopen(get_fname(), "wb"); + if (!fp) { + puts("Can't create output file"); + return 1; + } + if (fwrite(buffer, 1, length, fp) != length) { + puts("Error while writing output file"); + return 1; + } + fclose(fp); + + puts("Ok."); + return 0; }