home *** CD-ROM | disk | FTP | other *** search
-
- #include <stdio.h>
- #include <io.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
-
-
- #define PSZ 768 /* Maximum palette size */
- #define BSZ 16384 /* Size of write buffer for delzw() */
-
-
- struct gifhead {
- char s[6];
- unsigned int w, h;
- unsigned char c, b, z;
- };
-
- struct image {
- unsigned int l, t, w, h;
- unsigned char m;
- };
-
-
- int _readc(int f)
- /* Read a character from file f, return -1 on end of file */
- {
- unsigned char c;
-
- if (_read(f, &c, 1) == 1)
- return c;
- else
- return -1;
- }
-
-
- long delzw(int g, int h, int n)
- /* Decompress a .GIF style LZW compressed data stream of n-bit symbols,
- getting codes from file g and writing symbols (one per byte) to file
- h. delzw() returns the number of bytes written to file h. n must be
- in the range 2..8. */
- {
- int n2, /* 2^n */
- m, /* Current code size in bits */
- m2, /* 2^m */
- k, /* Next available table entry */
- c, /* Code being expanded */
- f, /* Last symbol decoded */
- i, /* Code just read */
- d, /* Code read before this one */
- j, /* Number of bits left in *p */
- a; /* Bytes in next block */
- unsigned char *p, /* Pointer to current byte in read buffer */
- *q, /* Pointer past liast byte in read buffer */
- b[255], /* Read buffer */
- *u, /* Stack pointer into r */
- r[4096], /* Stack for code expansion */
- s[4096]; /* Symbol entries in table */
- int t[4096]; /* Code entries in table */
- unsigned char *w; /* Write buffer pointer */
- unsigned char y[BSZ]; /* Write buffer */
- long e; /* Count of bytes written */
- static int z[] = {0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff,0x1ff,0x3ff,
- 0x7ff,0xfff,0x1fff,0x3fff,0x7fff};
-
-
- /* Initialize buffers */
- w = y;
- e = 0;
- p = q = b;
- j = 8;
-
- /* Setup decompression parameters */
- if (n < 2 || n > 8)
- return -5; /* Bad symbol size */
- n2 = 1 << n;
- k = n2 + 2;
- m2 = 1 << (m = n + 1);
- f = d = -1; /* There is no old code yet */
-
- /* Do until termination code (2^n + 1) is read */
- while (1)
- {
- /* Get next code: reads next m bits from file g, which is made of
- blocks of 1..255 bytes, each preceded by a one byte count. */
- if (j == 8)
- {
- if (++p >= q &&
- (((a = _readc(g)) < 1) ||
- (q = (p = b) + _read(g, b, a)) < b + a))
- return -4; /* Premature end of file */
- j = 0;
- }
- c = *p;
- if ((i = m + j) <= 8)
- {
- *p >>= m;
- j = i;
- }
- else
- {
- if (++p >= q &&
- (((a = _readc(g)) < 1) ||
- (q = (p = b) + _read(g, b, a)) < b + a))
- return -4; /* Premature end of file */
- c |= *p << (8 - j);
- if (i <= 16)
- *p >>= (j = i - 8);
- else
- {
- if (++p >= q &&
- (((a = _readc(g)) < 1) ||
- (q = (p = b) + _read(g, b, a)) < b + a))
- return -4; /* Premature end of file */
- c |= *p << (16 - j);
- *p >>= (j = i - 16);
- }
- }
- c &= z[m];
- i = c;
-
- /* Check code */
- if (c == n2 + 1)
- break; /* Terminator symbol */
- if (c > k)
- return -3; /* Bad code */
-
- /* See if clear code */
- if (c == n2)
- {
- k = n2 + 2;
- m2 = 1 << (m = n + 1);
- f = d = -1;
- continue;
- }
-
- /* Empty stack */
- u = r;
-
- /* Check for special case---if code is next code to be defined */
- if (c == k)
- {
- if (d == -1)
- return -2; /* First code is not a symbol */
- *u++ = f;
- c = d;
- }
-
- /* Build string backwards */
- while (c >= n2)
- {
- *u++ = s[c];
- c = t[c];
- }
-
- /* Write string out forwards, update final character (f) */
- f = c;
- do {
- *w++ = c;
- if (w == y + BSZ)
- {
- _write(h, y, BSZ);
- e += BSZ;
- w = y;
- }
- if (u <= r)
- break;
- c = *--u;
- } while (1);
-
- /* Put new entry in table, update code length, old code */
- if (k < 4096 && d != -1)
- {
- t[k] = d;
- s[k] = f;
- if (++k >= m2 && m < 12)
- m2 = 1 << ++m;
- }
- d = i;
- }
-
- /* Check that termination code was in the last byte of data */
- if (_readc(g) != 0)
- return -1; /* File didn't end after terminator */
-
- /* Flush write buffer and return bytes written */
- if (w - y)
- {
- _write(h, y, w - y);
- e += w - y;
- }
- return e;
- }
-
-
- void gif(int f, int w, int e)
- /* Decode .gif file f: if e is 1, do an extended decode, of e is 2,
- write a decompressed version of the .gif file to file w. */
- {
- long n, t;
- int b, c;
- struct gifhead g;
- struct image d;
- unsigned char p[PSZ];
-
- /* Check GIF header */
- if (_read(f, &g, sizeof(g)) != sizeof(g) ||
- strncmp(g.s, "GIF87a", 6))
- printf(" is not a GIF87a file.\n");
- else
- {
- /* Show header information */
- printf(" is %dx%dx%d bits and %d bits/color with ",
- g.w, g.h, (g.c & 7) + 1, ((g.c >> 4) & 7) + 1);
- if (g.c & 0x80)
- printf("a ");
- else
- printf("no ");
- printf("global color map\n");
- if ((g.c & 8) || g.z)
- printf(" !reserved bits were not all zero\n");
-
- /* If extended decode, read entire file */
- if (e)
- {
- /* Show one more detail from header */
- printf(" background color is %d\n", g.b);
-
- /* If /w, write crucial header information */
- if (e == 2)
- {
- _write(w, "PX", 2);
- _write(w, &(g.w), 6);
- }
-
- /* Global color table is next */
- if (g.c & 0x80)
- {
- c = 3 * (1 << ((g.c & 7) + 1));
- if (e != 2)
- {
- if (lseek(f, c, SEEK_CUR) == -1L)
- {
- printf(" !file stopped in global color table\n");
- return;
- }
- }
- else /* Save global color table in p */
- {
- if (_read(f, p, c) != c)
- {
- printf(" !file stopped in global color table\n");
- return;
- }
- for (b = 0; b < c; b++)
- p[b] >>= 2;
- for (; b < PSZ; b++)
- p[b] = 0;
- }
- }
- else
- printf(" !no global color table---.pix file unusable\n");
-
- /* Read images and extension blocks */
- while ((c = _readc(f)) == ',' || c == '!')
-
- /* Process image */
- if (c == ',')
- {
- /* Initialize bits per pixel */
- b = (g.c & 7) + 1;
-
- /* Read image descriptor */
- if (_read(f, &d, sizeof(d)) != sizeof(d))
- {
- printf(" !file stopped in image descriptor\n");
- return;
- }
- printf(" image: start %d/%d pixels from left/top,",
- d.l, d.t);
- printf(" is %dx%d %s\n",
- d.w, d.h, d.m & 0x40 ? "interlaced" : "sequential");
- if (d.m & 0x38)
- printf(" !reserved bits were not all zero\n");
- if (e == 2)
- {
- if (d.l || d.t || d.w != g.w || d.h != g.h || (d.m & 0x40))
- printf(" !image not standard---.pix file unusable\n");
- _write(w, &d, 8);
- _write(w, p, PSZ);
- }
-
- /* Local color map (if any) is next */
- if (d.m & 0x80)
- {
- b = (d.m & 7) + 1;
- printf(" local color map with %d bits/pixel\n", b);
- if (lseek(f, 3 * (1L << b), SEEK_CUR) == -1L)
- {
- printf(" !file stopped in local color map\n");
- return;
- }
- if (e == 2)
- printf(" !has local color map---.pix file unusable\n");
- }
-
- /* Get bits per symbol for compressed image */
- if ((c = _readc(f)) == -1)
- {
- printf(" !file stopped in raster data\n");
- return;
- }
- printf(" code size = %d bits\n", c);
-
- /* Go over image blocks if just /e */
- if (e != 2)
- {
- n = t = 0;
- while ((c = _readc(f)) != 0)
- {
- if (c == -1 || lseek(f, c, SEEK_CUR) == -1L)
- {
- printf(" !file stopped in raster data block\n");
- return;
- }
- n++;
- t += c;
- }
- printf(" compressed image = %ld bytes in %ld blocks\n",
- t, n);
- }
-
- /* If /w, decompress image and write it out */
- else
- if ((t = delzw(f, w, c)) < 0)
- printf(" !error %ld decompressing image\n", t);
- else
- printf(" decompressed image = %ld pixels\n", t);
- }
-
- /* Process extension block */
- else
- {
- if ((c = _readc(f)) == -1)
- {
- printf(" !file stopped in extension block\n");
- return;
- }
- printf(" gif extension block with function code %d\n", c);
- n = t = 0;
- while ((c = _readc(f)) != 0)
- {
- if (c == -1 || lseek(f, c, SEEK_CUR) == -1L)
- {
- printf(" !file stopped in extension data block\n");
- return;
- }
- n++;
- t += c;
- }
- printf(" total extension data = %ld bytes in %ld blocks\n",
- t, n);
- }
-
- /* Make sure images and extensions terminated with a semicolon */
- if (c == ';')
- printf(" file");
- else
- printf(" !file not");
- printf(" properly terminated");
-
- /* See if hit end of file */
- if (eof(f) != 1)
- printf(" (but extra data at end)");
-
- /* Done reading file */
- printf("\n\n");
- }
- }
-
- /* Close files */
- _close(f);
- if (e == 2)
- _close(w);
- }
-
-
- void main(int argc, char *argv[])
- /* Process .gif files and options---only options allowed are /e for an
- extended decode, and /w for a full decompression, writing the results
- to the same filename, but with extension .pix. */
- {
- int i, e, f, w;
- char a[128];
-
- e = 0; /* Extended list off */
- for (i = 1; i < argc; i++)
- if (argv[i][0] == '/')
- if ((argv[i][1] & 0x5f) == 'E')
- e = 1; /* Extended list on */
- else if ((argv[i][1] & 0x5f) == 'W')
- e = 2; /* Write image data */
- else
- printf("(invalid option)\n");
- else
- {
- printf(argv[i]);
- strcat(strcpy(a, argv[i]), ".gif");
- if ((f = _open(a, O_RDONLY)) == -1)
- printf(".gif not found.\n");
- else
- {
- if (e == 2)
- {
- strcat(strcpy(a, argv[i]), ".pix");
- if ((w = _creat(a, 0)) == -1)
- {
- printf(".pix could not be created---downgrading to /e\n");
- e = 1;
- printf(argv[i]);
- }
- }
- gif(f, w, e);
- }
- }
- }