]> git.sur5r.net Git - cc65/blobdiff - samples/gunzip65.c
Fixed LinuxDoc Tools issues in some verbatim blocks in the Atari document.
[cc65] / samples / gunzip65.c
index 3b84982b756544507dc25e90a3b1bd40eb675d17..9d21c2137c27dbfb296e426a63854adb8788877c 100644 (file)
 /*
- * gunzip65 - a gunzip utility for 6502-based machines.
- *
- * Piotr Fusik <fox@scene.pl>
- *
- * 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 <fox@scene.pl>
+**
+** 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 <stdio.h>
 #include <string.h>
 #include <zlib.h>
 
+#ifdef __CC65__
+#include <stdlib.h>
+#include <cc65.h>
+#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;
 }