From: mike@egf-bbs.uucp (System Operator)
Newsgroups: alt.supermodels
Subject: No more DL'ing bad GIF's!
Summary: giftest.shar
Keywords: giftest.c, GIF, nifty
Date: 3 Sep 92 03:21:18 GMT
Organization: East Grand Forks, MN Public Access Unix +1 218 773 3124

#!/bin/sh
# This is a shell archive (shar 3.32)
# made 06/19/1991 12:22 UTC
#
# existing files WILL be overwritten
# This format requires very little intelligence at unshar time.
# "echo" and "sed" will be needed.
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#  15653 -rw------- giftest.c
#
# ============= giftest.c ==============
echo "x - extracting giftest.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > giftest.c &&
X/*
X **
X ***
X *** giftest.c - an on-line GIF tester, pieced together by Jonathan O'Neal
X ***                                    18 jun 91
X ***
X *** Compiled and tested on SCO Unix SysV 3.2.2;  should work elsewhere.
X *** use: cc -O -o giftest giftest.c
X *** usage: giftest {giflist}, i.e. giftest *.gif
X *** does NOT add ".gif" to filenames (easily added if you like)
X ***
X *** While it doesn't catch every error known to man, it _does_ catch most
X *** unshar-uudecode related errors.
X ***
X *** I didn't write much of this;  original credits are below.  It could
X *** probably be made a lot more efficient...
X *** Don't E-mail me, we don't have a valid address yet so it WILL bounce.
X ***
X **
X *
X * DECODE.C - An LZW decoder for GIF
X * Copyright (C) 1987, by Steven A. Bennett
X *
X * Permission is given by the author to freely redistribute and include
X * this code in any program as long as this credit is given where due.
X *
X * In accordance with the above, I want to credit Steve Wilhite who wrote
X * the code which this is heavily inspired by...
X *
X * GIF and 'Graphics Interchange Format' are trademarks (tm) of
X * Compuserve, Incorporated, an H&R Block Company.
X *
X * Release Notes: This file contains a decoder routine for GIF images
X * which is similar, structurally, to the original routine by Steve Wilhite.
X * It is, however, somewhat noticably faster in most cases.
X */
X
X#include "stdio.h"
X#include "stdlib.h"
X#include "stddef.h"
X#include "string.h"
X#include "malloc.h"
X
Xtypedef unsigned char UCHAR;
Xtypedef short INT16;
Xtypedef unsigned short UINT16;
Xtypedef long INT32;
Xtypedef unsigned long UINT32;
X
X/*
X * Various error codes used by decoder
X * and my own routines...   It's okay
X * for you to define whatever you want,
X * as long as it's negative...  It will be
X * returned intact up the various subroutine
X * levels...
X */
X#define OUT_OF_MEMORY -10
X#define BAD_CODE_SIZE -20
X#define EARLY_EOF     -30
X#define READ_ERROR     -1
X#define BAD_HEADER    -40
X#define BAD_CODE      -50
X
XFILE  *GIFfp;
XINT16 Xres,
X      Yres,
X      PixelWidth;
XUINT32 FileOffset;
X
X#define MAX_CODES   4095
X
X/* Static variables */
Xstatic INT16 curr_size,                     /* The current code size */
X             clear,                         /* Value for a clear code */
X             ending,                        /* Value for a ending code */
X             newcodes,                      /* First available code */
X             top_slot,                      /* Highest code for current size */
X             slot;                          /* Last read code */
X
X/*
X * The following static variables are used
X * for seperating out codes
X */
Xstatic INT16 navail_bytes = 0,              /* # bytes left in block */
X             nbits_left = 0;                /* # bits left in current byte */
Xstatic UCHAR b1,                           /* Current byte */
X             byte_buff[257],               /* Current block */
X             *pbytes;                      /* Pointer to next byte in block */
X
Xstatic INT32 code_mask[13] = {
X     0,
X     0x0001, 0x0003,
X     0x0007, 0x000F,
X     0x001F, 0x003F,
X     0x007F, 0x00FF,
X     0x01FF, 0x03FF,
X     0x07FF, 0x0FFF
X     };
X
X/*
X * This function initializes the decoder for reading a new image.
X */
Xstatic INT16 init_exp(size)
XINT16 size;
X{
X   curr_size = size + 1;
X   top_slot = 1 << curr_size;
X   clear = 1 << size;
X   ending = clear + 1;
X   slot = newcodes = ending + 1;
X   navail_bytes = nbits_left = 0;
X
X   return(0);
X}
X
X/*
X * INT32 get_byte()
X *
X *   - This external (machine specific) function is expected to return
X * either the next byte from the GIF file, or a negative number, as
X * defined in ERRS.H.
X */
XINT32 get_byte()
X{
X   INT32 ch;
X
X   if ((ch = getc(GIFfp)) == EOF)
X      return(READ_ERROR);
X   ++FileOffset;
X   return(ch & 0xff);
X}
X
XINT32 GetWord()
X{
X   INT32  ret,
X          x;
X   UINT32 r;
X
X   if ((ret = get_byte()) < 0)
X      return(ret);
X   if ((x = get_byte()) < 0)
X      return(x);
X
X   r = ((x << 8) | ret);
X   return(r & 0xffff);
X}
X
X/*
X * get_next_code()
X * gets the next code from the GIF file.  Returns the code, or else
X * a negative number in case of file errors...
X */
Xstatic INT32 get_next_code()
X{
X   INT16  i,
X          x;
X   UINT32 ret;
X
X   if (nbits_left == 0) {
X      if (navail_bytes <= 0) {
X         /*
X          * Out of bytes in current block, so read next block
X          */
X         pbytes = byte_buff;
X         if ((navail_bytes = get_byte()) < 0)
X            return(navail_bytes);
X         else if (navail_bytes) {
X            for (i = 0; i < navail_bytes; ++i) {
X               if ((x = get_byte()) < 0)
X                  return(x);
X               byte_buff[i] = x;
X               }
X            }
X         }
X      b1 = *pbytes++;
X      nbits_left = 8;
X      --navail_bytes;
X      }
X
X   ret = b1 >> (8 - nbits_left);
X   while (curr_size > nbits_left) {
X      if (navail_bytes <= 0) {
X         /*
X          * Out of bytes in current block, so read next block
X          */
X         pbytes = byte_buff;
X         if ((navail_bytes = get_byte()) < 0)
X            return(navail_bytes);
X         else if (navail_bytes) {
X            for (i = 0; i < navail_bytes; ++i) {
X               if ((x = get_byte()) < 0)
X                  return(x);
X               byte_buff[i] = x;
X               }
X            }
X         }
X      b1 = *pbytes++;
X      ret |= b1 << nbits_left;
X      nbits_left += 8;
X      --navail_bytes;
X      }
X   nbits_left -= curr_size;
X   ret &= code_mask[curr_size];
X   return((INT16)(ret & 0xffff));
X}
X
X
X/*
X * The reason we have these seperated like this instead of using
X * a structure like the original Wilhite code did, is because this
X * stuff generally produces significantly faster code when compiled...
X * This code is full of similar speedups...  (For a good book on writing
X * C for speed or for space optomisation, see Efficient C by Tom Plum,
X * published by Plum-Hall Associates...)
X */
Xstatic UCHAR stack[MAX_CODES + 1],            /* Stack for storing pixels */
X             suffix[MAX_CODES + 1];           /* Suffix table */
Xstatic UINT16 prefix[MAX_CODES + 1];           /* Prefix linked list */
X
X/*
X * INT16 decoder(INT16 linewidth)
X *
X *    This function decodes an LZW image, according to the method used
X * in the GIF spec.  The function gets its codes from
X * get_next_code() which is responsible for reading blocks of data and
X * seperating them into the proper size codes.  Finally, get_byte() is
X * the global routine to read the next byte from the GIF file.
X *
X * Returns: 0 if successful, else negative.
X */
X
XINT16 decoder(linewidth)
XINT16 linewidth;
X{
X   register UCHAR *sp,
X                  *bufptr;
X   UCHAR *buf;
X   register INT16 code,
X                  fc,
X                  oc,
X                  bufcnt;
X   INT16 c,
X         size,
X         ret;
X   INT32 lc;
X
X   /*
X    * Initialize for decoding a new image...
X    */
X   if ((lc = get_byte()) < 0)       /* get initial code size */
X      return(lc);
X   size = lc & 0xffff;
X   if (size < 2 || 9 < size)
X      return(BAD_CODE_SIZE);
X   init_exp(size);
X
X   /*
X    * Initialize in case they forgot to put in a clear code.
X    * (This shouldn't happen, but we'll try and decode it anyway...)
X    */
X   oc = fc = 0;
X
X   /*
X    * Allocate space for the decode buffer
X    */
X   if ((buf = (UCHAR *)malloc(linewidth + 1)) == (UCHAR *)NULL)
X      return(OUT_OF_MEMORY);
X
X   /*
X    * Set up the stack pointer and decode buffer pointer
X    */
X   sp = stack;
X   bufptr = buf;
X   bufcnt = linewidth;
X
X   /*
X    * This is the main loop.  For each code we get we pass through the
X    * linked list of prefix codes, pushing the corresponding "character" for
X    * each code onto the stack.  When the list reaches a single "character"
X    * we push that on the stack too, and then start unstacking each
X    * character for output in the correct order.  Special handling is
X    * included for the clear code, and the whole thing ends when we get
X    * an ending code.
X    */
X   while ((lc = get_next_code()) != ending) {
X      c = lc & 0xffff;
X
X      /*
X       * If we had a file error, return without completing the decode
X       */
X      if (lc < 0) {
X         free(buf);
X         return(EARLY_EOF);
X         }
X
X      /*
X       * If the code is a clear code, reinitialize all necessary items.
X       */
X      if (c == clear) {
X         curr_size = size + 1;
X         slot = newcodes;
X         top_slot = 1 << curr_size;
X
X         /*
X          * Continue reading codes until we get a non-clear code
X          * (Another unlikely, but possible case...)
X          */
X         while ((lc = get_next_code()) == clear) {
X            }
X
X         /*
X          * If we get an ending code immediately after a clear code
X          * (Yet another unlikely case), then break out of the loop.
X          */
X         c = lc;
X         if (c == ending)
X            break;
X
X         /*
X          * Finally, if the code is beyond the range of already set codes,
X          * (This one had better NOT happen...  I have no idea what will
X          * result from this, but I doubt it will look good...) then set it
X          * to color zero.
X          */
X         if (c >= slot)
X            c = 0;
X
X         oc = fc = c;
X
X         /*
X          * And let us not forget to put the char into the buffer... And
X          * if, on the off chance, we were exactly one pixel from the end
X          * of the line, we have to send the buffer to the out_line()
X          * routine...
X          */
X         *bufptr++ = c;
X         if (--bufcnt == 0) {
X            bufptr = buf;
X            bufcnt = linewidth;
X            }
X         }
X      else {
X         /*
X          * In this case, it's not a clear code or an ending code, so
X          * it must be a code code...  So we can now decode the code into
X          * a stack of character codes. (Clear as mud, right?)
X          */
X         code = c;
X
X         /*
X          * Here we go again with one of those off chances...
X          */
X         if (code >= slot) {
X            if (code > slot)
X               return(BAD_CODE);
X            code = oc;
X            *sp++ = fc;
X            }
X
X         /*
X          * Here we scan back along the linked list of prefixes, pushing
X          * helpless characters (ie. suffixes) onto the stack as we do so.
X          */
X         while (code >= newcodes) {
X            *sp++ = suffix[code];
X            code = prefix[code];
X            }
X
X         /*
X          * Push the last character on the stack, and set up the new
X          * prefix and suffix, and if the required slot number is greater
X          * than that allowed by the current bit size, increase the bit
X          * size.  (NOTE - If we are all full, we *don't* save the new
X          * suffix and prefix...  I'm not certain if this is correct...
X          * it might be more proper to overwrite the last code...
X          */
X         *sp++ = code;
X         if (slot < top_slot) {
X            suffix[slot] = fc = code;
X            prefix[slot++] = oc;
X            oc = c;
X            }
X         if (slot >= top_slot)
X            if (curr_size < 12) {
X               top_slot <<= 1;
X               ++curr_size;
X               } 
X
X         /*
X          * Now that we've pushed the decoded string (in reverse order)
X          * onto the stack, lets pop it off and put it into our decode
X          * buffer...  And when the decode buffer is full, write another
X          * line...
X          */
X         while (sp > stack) {
X            *bufptr++ = *(--sp);
X            if (--bufcnt == 0) {
X               bufptr = buf;
X               bufcnt = linewidth;
X               }
X            }
X         }
X      }
X
X   ret = 0;
X   free(buf);
X   return(ret);
X}
X
X
X/*
X * Read in (and display pertinent info about) the GIF header
X */
XINT16 Header()
X{
X   INT32 x,
X         y,
X         p;
X   UCHAR buf[128];
X
X   fread(buf, 1, 6, GIFfp);
X   buf[3] = '\0';
X   if (strcmp(buf, "GIF") != 0)        /* don't care about 87a or 89a or 93a... */
X      return(BAD_HEADER);
X
X   if ((x = GetWord()) < 0)            /* Get X resolution */
X      return(BAD_HEADER);
X   if ((y = GetWord()) < 0)            /* Get Y resolution */
X      return(BAD_HEADER);
X   if ((p = get_byte()) < 0)           /* Get pixel width & flags */
X      return(BAD_HEADER);
X   Xres = x;
X   Yres = y;
X   PixelWidth = (p & 7) + 1;
X   printf("[%dx%dx%d] ", Xres, Yres, 1 << PixelWidth);
X
X   if ((x = get_byte()) < 0)           /* read Background */
X      return(BAD_HEADER);
X
X   if ((x = get_byte()) < 0)           /* read <Reserved> */
X      return(BAD_HEADER);
X
X   if ((p & 0x80) != 0) {              /* global color map */
X      x = 1 << PixelWidth;
X      while (x--) {
X         if (get_byte() < 0)           /* read colors (RGB) */
X            return(BAD_HEADER);
X         if (get_byte() < 0)
X            return(BAD_HEADER);
X         if (get_byte() < 0)
X            return(BAD_HEADER);
X         }
X      }
X   if ((x = get_byte()) < 0)           /* get ',' or '!' */
X      return(BAD_HEADER);
X
X   while (x == '!') {                  /* GIF extension */
X      if (get_byte() < 0)              /* extended function code */
X         return(BAD_HEADER);
X      if ((x = get_byte()) < 0)        /* byte count */
X         return(BAD_HEADER);
X      do {
X         while (x--) {
X            if (get_byte() < 0)        /* extended function data */
X               return(BAD_HEADER);
X            }
X         } while ((x = get_byte()) > 0);
X      if (x < 0)
X         return(BAD_HEADER);
X      if ((x = get_byte()) < 0)        /* get ',' or '!' */
X         return(BAD_HEADER);
X      }
X
X   if ((x = GetWord()) < 0)            /* left offset */
X      return(BAD_HEADER);
X   if ((x = GetWord()) < 0)            /* top offset */
X      return(BAD_HEADER);
X
X   if ((x = GetWord()) < 0)            /* width */
X      return(BAD_HEADER);
X   if ((y = GetWord()) < 0)            /* height */
X      return(BAD_HEADER);
X
X   if ((x = get_byte()) < 0)           /* interlace?  local map? */
X      return(BAD_HEADER);
X
X   if (x & 0x40)
X      printf("[Interlaced] ");
X
X   if (x & 0x80) {                     /* get local color map */
X      x = 1 << ((x & 7) + 1);
X      while (x--) {
X         if (get_byte() < 0)           /* read color data (RGB) */
X            return(BAD_HEADER);
X         if (get_byte() < 0)
X            return(BAD_HEADER);
X         if (get_byte() < 0)
X            return(BAD_HEADER);
X         }
X      }
X
X   return(0);
X}
X
Xmain(argc, argv)
Xint  argc;
Xchar *argv[];
X{
X   INT32 ret;
X
X   while (--argc) {
X      if ((GIFfp = fopen(*++argv, "r")) == (FILE *)NULL)
X         printf("Can't open \"%s\".\n", *argv);
X      else {
X         printf("%s: ", *argv);
X         FileOffset = 0;
X         if ((ret = Header()) == 0)
X            ret = decoder(1024);
X
X         switch (ret) {
X            case 0 :
X               printf("OK\n");
X               break;
X            case OUT_OF_MEMORY :
X               printf("Memory allocation error\n");
X               break;
X            case BAD_CODE_SIZE :
X               printf("Bad code size at %08lx\n", FileOffset);
X               break;
X            case BAD_CODE :
X               printf("Bad code at %08lx\n", FileOffset);
X               break;
X            case EARLY_EOF :
X               printf("Premature EOF at %08lx\n", FileOffset);
X               break;
X            case READ_ERROR :
X               printf("Read error at %08lx\n", FileOffset);
X               break;
X            case BAD_HEADER :
X               printf("Bad header format at %08lx\n", FileOffset);
X               break;
X            default :
X               perror("?? huh ??");
X               printf("Unknown error at %08lx! (%d)\n", FileOffset, ret);
X               break;
X            }
X         fclose(GIFfp);
X         }
X      }
X
X   exit(0);
X}
X
SHAR_EOF
exit 0
-- 
Mike Aos         Preferred->  plains!egf-bbs!mike     This       egf-bbs.uucp
(218) 773-1084   Checked daily-> plains!milo!maos    message       Sun 2/120
RR#1 Box 40      Last resort-> maos@nyx.cs.du.edu    delayed    (218) 773-3124
East Grand Forks, MN 56721-9703                       24 hrs    Login as 'guest'
Newsgroups: alt.supermodels