*/
Want to see what people are talking about? See the latest forum posts.
*/

View \GIF.C

ManyThings 3.1 Screensaver in VB

Submitted By: Unknown
Rating: starhalf star (Rate It)


/* $change:Code cleanup, minor fixes.$ */
/*
**      $id: ssvcid gif.c 1.0 08/03/92 10:01 am$
**            Read a Compuserve GIF file into a DIB.
**
**      (C) 1992-1993 Larry Widing
*/

#define NOCOMM
#define NOKANJI
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include        <malloc.h>
#include        "bitmaps.h"

#define SEG_CBUF  01
#define FASTCALLS        01
#define GET_BYTES        01
#define PAL_SHIFT        0

/*
**      Local functions
*/

static short NEAR       decoder(short linewidth);
static short        init_exp(short  size);
static short NEAR       get_next_code(void);
static void               inittable(void);
static void               close_file(void);

/*
**      Local variables
*/

static int                                    rowcount;          /* row counter for screen */
static int                                    hin = NULL;
static unsigned int               height;

static unsigned char            dacbox[256][3];               /* Video-DAC (filled in by SETVIDEO) */

static unsigned char            decoderline[2049];    /* write-line routines use this */
static unsigned char            win_andmask[8];
static unsigned char            win_notmask[8];
static unsigned char            win_bitshift[8];

static int                                    xdots, ydots, colors;
static int                                    win_xdots, win_ydots;
static unsigned char huge       *pixels;                               /* the device-independent bitmap pixels */
static int                                    pixels_per_byte;        /* pixels/byte in the pixmap */
static long                              pixels_per_bytem1;      /* pixels / byte - 1 (for ANDing) */
static int                                    pixelshift_per_byte;    /* 0, 1, 2, or 3 */
static int                                    bytes_per_pixelline;    /* pixels/line / pixels/byte */
static long                              win_bitmapsize;                  /* bitmap size, in bytes */
static int                                    bad_code_count = 0;      /* needed by decoder module */
#if     SEG_CBUF
static BYTE _seg                                *cbuf = NULL;
static unsigned int               gbuf = 0;
#else
static BYTE FAR    *cbuf = NULL;
static BYTE FAR    *gbuf = NULL;
#endif
static HANDLE               hcbuf = NULL;
static unsigned int               gbn = 0;

#define cbufsize (32u * 1024u)        // (16u * 1024u)

static int NEAR
get_byte(void)
{
        if (gbn == 0)
        {
                gbn = _lread(hin,cbuf,cbufsize);
#if     SEG_CBUF
                gbuf = 0;
#else
                gbuf = NULL;
#endif
        }

        if (gbn)
        {
                --gbn;
#if     SEG_CBUF
                return (cbuf[gbuf++]) & 0x00ff;
#else
                return (*gbuf++) & 0x00ff;
#endif
        }
        else
                return (-1);
}

#if     GET_BYTES
static int NEAR
get_bytes(unsigned int count, char *dest)
{
        int     count2 = count;

        if (count <= 0)
        {
                return count;
        }

        while (count)
        {
                if (gbn == 0)
                {
                        gbn = _lread(hin,cbuf,cbufsize);
#if     SEG_CBUF
                        gbuf = NULL;
#else
                        gbuf = cbuf;
#endif

                        if (!gbn)
                                return -1;
                }

                if (gbn >= count)
                {
                        if (dest != NULL)
                        {
#if     SEG_CBUF
                                memcpy(dest, cbuf + gbuf, count);
#else
                                memcpy(dest, gbuf, count);
#endif
                        }
                        gbuf += count;
                        gbn -= count;
                        count = 0;
                }
                else
                {
                        if (dest != NULL)
                        {
#if     SEG_CBUF
                                memcpy(dest, cbuf + gbuf, gbn);
#else
                                memcpy(dest, gbuf, gbn);
#endif
                        }
                        count -= gbn;
                        dest += gbn;
                        gbn = 0;
                }
        }

        return count2;
}
#endif

static void NEAR
putcolor(int x, int y, int color)
{
        long i;

        i = win_ydots - 1 - y;
        i = (i * win_xdots) + x;

        if (x >= 0 && x < xdots && y >= 0 && y < ydots)
        {
                if (pixelshift_per_byte == 0)
                {
                        pixels[i] = color % colors;
                }
                else
                {
                        unsigned int j;

                        j = i & (unsigned int)pixels_per_bytem1;
                        i = i >> pixelshift_per_byte;
                        pixels[i] = (pixels[i] & win_notmask[j]) +
                                 (((unsigned char) (color % colors)) << win_bitshift[j]);
                }
        }
}

static int NEAR
put_line(int rownum, int leftpt, int rightpt, unsigned char *localvalues)
{
        int     i, len;
        long    startloc;

        len = rightpt - leftpt;
        if (rightpt >= xdots)
        {
                len = xdots - leftpt;
        }
        startloc = win_ydots - 1 - rownum;
        startloc = (startloc * win_xdots) + leftpt;

        if (rownum < 0 || rownum >= ydots || leftpt < 0)
        {
                return (0);
        }

        if (pixelshift_per_byte == 0)
        {
                /*
                **      Done this way because _fmemcpy() does not handle HUGE pointers
                **      that can wrap over a selector/segment boundry.
                */

                unsigned char huge      *ptr = pixels + startloc;

                if (HIWORD(ptr) != HIWORD(ptr + len))
                {
                        char    *src = (char *)localvalues;

                        while (len--)
                                *ptr++ = *src++;
                }
                else
                {
                        _fmemcpy(ptr, localvalues, len);
                }
        }
        else
        {
                unsigned int    j;
                long                k;

                for (i = 0 ;  i <= len ;  i++)
                {
                        k = startloc + i;
                        j = k & (unsigned int)pixels_per_bytem1;
                        k = k >> pixelshift_per_byte;
                        pixels[k] = (pixels[k] & win_notmask[j]) +
                                 (((unsigned char) (localvalues[i] % colors)) << win_bitshift[j]);
                }
        }
        putcolor(leftpt, rownum, localvalues[0]);

        return (1);
}

static int NEAR
out_line(unsigned char *localvalues, int numberofdots)
{
        return (put_line(rowcount++, 0, numberofdots, localvalues));
}


/*
**      Main entry decoder
*/


HDIB
ReadGifFile(const char FAR *filename)
{
        HDIB                        dib = (HANDLE)NULL, hbiCurrent;
        unsigned                                        numcolors;
        unsigned char         buffer[16];
        unsigned                                        width, finished;
        LPBITMAPINFOHEADER      lpbi;
        RGBQUAD FAR                    *pRgb;
        int                              status = 0;
        int                              i, j, planes;
        DWORD                  dwBits, dwLen;
   OFSTRUCT                         of;

   /* initialize the row count for write-lines */
        rowcount = 0;

   /* zero out the full write-line */
        for (width = 0 ;  width < 2049 ;  width++)
                decoderline[width] = 0;

   /* Open the file -- changed to OpenFile by mh */
   hin = OpenFile ((LPSTR)filename, (LPOFSTRUCT)&of, OF_READ);
        if (hin == -1)
        {
                return FALSE;
        }

        hcbuf = GlobalAlloc(GHND,cbufsize);
        cbuf = (BYTE FAR *)GlobalLock(hcbuf);
        if (cbuf == NULL)
        {
                close_file();
                return FALSE;
        }
        gbn = 0;
#if     SEG_CBUF
        gbuf = 0;
#else
        gbuf = NULL;
#endif

   /* Get the screen description */
        for (i = 0 ; i < 13 ; i++)
        {
                buffer[i] = (unsigned char) status = get_byte();
                if (status < 0)
                {
                        close_file();
                        return FALSE;
                }
        }

        if (strncmp((char *)buffer, "GIF87a", 3) ||     /* use updated GIF specs */
                 buffer[3] < '0' || buffer[3] > '9' ||
                 buffer[4] < '0' || buffer[4] > '9' ||
                 buffer[5] < 'A' || buffer[5] > 'z')
        {
                close_file();
                return FALSE;
        }

        planes = (buffer[10] & 0xF) + 1;

        if ((buffer[10] & 0x80) == 0)   /* color map (better be!) */
        {
                close_file();
                return FALSE;
        }
        numcolors = 1 << planes;

#if     GET_BYTES
        if (numcolors * 3 == get_bytes(numcolors * 3, dacbox))
        {
#if     PAL_SHIFT
                for (i = 0 ; i < numcolors ; ++i)
                {
                        for (j = 0 ; j < 3 ; ++j)
                        {
                                dacbox[i][j] >>= 2;
                        }
                }
#endif
        }
        else
        {
                close_file();
                return FALSE;
        }
#else
        for (i = 0 ;  i < numcolors ;  i++)
        {
                for (j = 0 ;  j < 3 ;  j++)
                {
                        status = get_byte();
                        if (status < 0)
                        {
                                close_file();
                                return FALSE;
                        }

                        dacbox[i][j] = (status & 0x00ff) >> 2;
                }
        }
#endif

   /* Now display one or more GIF objects */
        finished = 0;
        while (!finished)
        {
                switch (get_byte())
                {
                        case ';':                            /* End of the GIF dataset */
                                finished = 1;
                                status = 0;
                                break;

                        case '!':                            /* GIF Extension Block */
                                get_byte();          /* read (and ignore) the ID */
                                while ((i = get_byte()) > 0)    /* get the data length */
#if     GET_BYTES
                                        get_bytes(i, NULL);
#else
                                        for (j = 0;  j < i;  j++)
                                                get_byte();     /* flush the data */
#endif
                                break;

                        case ',':
                              /*
                             * Start of an image object. Read the image description.
                             */


#if     GET_BYTES
                                if (9 != get_bytes(9, buffer))
                                {
                                        status = -1;
                                }
                                else
                                {
                                        status = 0;
                                }
#else
                                for (i = 0;  i < 9;  i++)
                                {
                                        buffer[i] = (unsigned char) status = get_byte();
                                        if (status < 0)
                                        {
                                                status = -1;
                                                break;
                                        }
                                }
#endif
                                if (status < 0)
                                {
                                        finished = 1;
                                        break;
                                }

                                width = buffer[4] | (buffer[5] << 8);
                                height = buffer[6] | (buffer[7] << 8);
                                // fill in DIB stuff
                                xdots = width;
                                ydots = height;
                                colors = numcolors;
                                if (colors > 16)
                                        colors = 256;
                                if (colors > 2 && colors < 16)
                                        colors = 16;
                                win_xdots = (xdots + 3) & 0xFFFC;
                                win_ydots = ydots;
                                pixelshift_per_byte = 0;
                                pixels_per_byte = 1;
                                pixels_per_bytem1 = 0;
                                if (colors == 16)
                                {
                                        win_xdots = (xdots + 7) & 0xFFF8;
                                        pixelshift_per_byte = 1;
                                        pixels_per_byte = 2;
                                        pixels_per_bytem1 = 1;
                                        win_andmask[0] = 0xF0;
                                        win_notmask[0] = 0xF;
                                        win_bitshift[0] = 4;
                                        win_andmask[1] = 0xF;
                                        win_notmask[1] = 0xF0;
                                        win_bitshift[1] = 0;
                                }
                                if (colors == 2)
                                {
                                        win_xdots = (xdots + 31) & 0xFFE0;
                                        pixelshift_per_byte = 3;
                                        pixels_per_byte = 8;
                                        pixels_per_bytem1 = 7;
                                        win_andmask[0] = 0x80;
                                        win_notmask[0] = 0x7F;
                                        win_bitshift[0] = 7;
                                        for (i = 1 ;  i < 8 ;  i++)
                                        {
                                                win_andmask[i] = win_andmask[i - 1] >> 1;
                                                win_notmask[i] = (win_notmask[i - 1] >> 1) + 0x80;
                                                win_bitshift[i] = win_bitshift[i - 1] - 1;
                                        }
                                }
                                bytes_per_pixelline = win_xdots >> pixelshift_per_byte;

                                hbiCurrent = GlobalAlloc(GHND, (LONG) sizeof(BITMAPINFOHEADER) +
                                        colors * sizeof(RGBQUAD));
                                if (!hbiCurrent)
                                        return 0;

                                lpbi = (VOID FAR *) GlobalLock(hbiCurrent);
                                lpbi->biSize = sizeof(BITMAPINFOHEADER);
                                lpbi->biWidth = width;
                                lpbi->biHeight = height;
                                lpbi->biPlanes = 1;     //nb: NOT equal to planes from GIF
                                lpbi->biBitCount = 8 / pixels_per_byte;
                                lpbi->biCompression = BI_RGB;
                                dwBits =
                                        lpbi->biSizeImage = (DWORD) bytes_per_pixelline * win_ydots;
                                lpbi->biXPelsPerMeter = 0;
                                lpbi->biYPelsPerMeter = 0;
                                lpbi->biClrUsed = colors;
                                lpbi->biClrImportant = colors;

                                win_bitmapsize = (((long) win_xdots * (long) win_ydots) >> pixelshift_per_byte) + 1;

                    /* fill in intensities for all palette entry colors */

                                pRgb = (RGBQUAD FAR *) ((LPSTR) lpbi + (unsigned int)lpbi->biSize);
                                for (i = 0;  i < colors;  i++)
                                {
#if     PAL_SHIFT
                                        pRgb[i].rgbRed = ((BYTE) dacbox[i][0]) << 2;
                                        pRgb[i].rgbGreen = ((BYTE) dacbox[i][1]) << 2;
                                        pRgb[i].rgbBlue = ((BYTE) dacbox[i][2]) << 2;
#else
                                        pRgb[i].rgbRed = ((BYTE) dacbox[i][0]);
                                        pRgb[i].rgbGreen = ((BYTE) dacbox[i][1]);
                                        pRgb[i].rgbBlue = ((BYTE) dacbox[i][2]);
#endif
                                }

                                dwLen = lpbi->biSize + (DWORD) colors * sizeof(RGBQUAD) + dwBits;
                                dib = GlobalAlloc(GHND, dwLen);
                                if (!dib)
                                {
                                        finished = 1;
                                        status = -1;
                                        break;
                                }
                                pixels = (unsigned char huge *) GlobalLock(dib);
                                _fmemcpy(pixels, lpbi, (size_t) (dwLen - dwBits));
                                GlobalUnlock(hbiCurrent);
                                GlobalFree(hbiCurrent);
                                pixels += dwLen - dwBits;

                                decoder(width)//this does the grunt work

                                GlobalUnlock(dib);

                                status = 0;
                                finished = 1;
                                break;

                        default:
                                status = -1;
                                finished = 1;
                                break;
                }
        }

        close_file();

        return (status == 0) ? dib : 0;
}

static void
close_file()
{
        _lclose(hin)
        hin = NULL;
        if (hcbuf)
        {
                GlobalUnlock(hcbuf);
                GlobalFree(hcbuf);
                cbuf = NULL;
                hcbuf = NULL;
        }
}


/* DECODE.C - An LZW decoder for GIF
 * Copyright (C) 1987, by Steven A. Bennett
 *
 * Permission is given by the author to freely redistribute and include
 * this code in any program as long as this credit is given where due.
 *
 * In accordance with the above, I want to credit Steve Wilhite who wrote
 * the code which this is heavily inspired by...
 *
 * GIF and 'Graphics Interchange Format' are trademarks (tm) of
 * Compuserve, Incorporated, an H&R Block Company.
 *
 * Release Notes: This file contains a decoder routine for GIF images
 * which is similar, structurally, to the original routine by Steve Wilhite.
 * It is, however, somewhat noticably faster in most cases.
 *
 == This routine was modified for use in FRACTINT in two ways.
 ==
 == 1) The original #includes were folded into the routine strictly to hold
 ==    down the number of files we were dealing with.
 ==
 == 2) The 'stack', 'suffix', 'prefix', and 'buf' arrays were changed from
 ==    static and 'malloc()'ed to external only so that the assembler
 ==    program could use the same array space for several independent
 ==    chunks of code.  Also, 'stack' was renamed to 'dstack' for TASM
 ==    compatibility.
 ==
 == 3) The 'out_line()' external function has been changed to reference
 ==    '*outln()' for flexibility (in particular, 3D transformations)
 ==
 == 4) A call to 'keypressed()' has been added after the 'outln()' calls
 ==    to check for the presenc of a key-press as a bail-out signal
 ==
 == (Bert Tyler and Timothy Wegner)
 */

#define LOCAL static
#define IMPORT extern

#define FAST register

typedef unsigned short UWORD;
typedef char TEXT;
typedef unsigned char UTINY;
typedef unsigned long ULONG;
typedef int INT;


/* Various error codes used by decoder
 * and my own routines...   It's okay
 * for you to define whatever you want,
 * as long as it's negative...  It will be
 * returned intact up the various subroutine
 * levels...
 */

#define OUT_OF_MEMORY -10
#define BAD_CODE_SIZE -20
#define READ_ERROR -1
#define WRITE_ERROR -2
#define OPEN_ERROR -3
#define CREATE_ERROR -4



/* whups, here are more globals, added by PB: */
static INT skipxdots; /* 0 to get every dot, 1 for every 2nd, 2 every 3rd, ... */
static INT skipydots; /* ditto for rows */

#define MAX_CODES   4095

/* Static variables */
LOCAL short curr_size;        /* The current code size */
LOCAL short clear;                    /* Value for a clear code */
LOCAL short ending;                 /* Value for a ending code */
LOCAL short newcodes;           /* First available code */
LOCAL short top_slot;           /* Highest code for current size */
LOCAL short slot;                       /* Last read code */

/* The following static variables are used
 * for seperating out codes
 */

LOCAL short navail_bytes = 0;        /* # bytes left in block */
LOCAL short nbits_left = 0;            /* # bits left in current byte */
LOCAL UTINY b1;                           /* Current byte */
LOCAL UTINY byte_buff[257];            /* Current block, reuse shared mem */
LOCAL UTINY *pbytes;              /* Pointer to next byte in block */

LOCAL LONG code_mask[13] = {
     0,
     0x0001, 0x0003,
     0x0007, 0x000F,
     0x001F, 0x003F,
     0x007F, 0x00FF,
     0x01FF, 0x03FF,
     0x07FF, 0x0FFF
     };


/* This function initializes the decoder for reading a new image.
 */


LOCAL short
init_exp(short size)
{
        curr_size = size + 1;
        top_slot = 1 << curr_size;
        clear = 1 << size;
        ending = clear + 1;
        slot = newcodes = ending + 1;
        navail_bytes = nbits_left = 0;

        return (0);
}

#define GET_BLOCK        01

#if     GET_BLOCK
static int NEAR
get_block(void)
{
        register int    count;
        register        char    *dest = byte_buff;

        count = get_byte();
        if (count < 0)
        {
                return count;
        }
        navail_bytes = count;

        while (count)
        {
                if (gbn == 0)
                {
                        gbn = _lread(hin,cbuf,cbufsize);
#if     SEG_CBUF
                        gbuf = NULL;
#else
                        gbuf = cbuf;
#endif

                        if (!gbn)
                                return -1;
                }

                if (gbn >= count)
                {
#if     SEG_CBUF
                        memcpy(dest, cbuf + gbuf, count);
#else
                        memcpy(dest, gbuf, count);
#endif
                        gbuf += count;
                        gbn -= count;
                        count = 0;
                }
                else
                {
#if     SEG_CBUF
                        memcpy(dest, cbuf + gbuf, gbn);
#else
                        memcpy(dest, gbuf, gbn);
#endif
                        count -= gbn;
                        dest += gbn;
                        gbn = 0;
                }
        }

        return navail_bytes;
}
#endif

/* get_next_code()
 * - gets the next code from the GIF file.  Returns the code, or else
 * a negative number in case of file errors...
 */


LOCAL short NEAR
get_next_code(void)
{
        short   i, x;
        ULONG   ret;

        if (nbits_left == 0)
        {
                if (navail_bytes <= 0)
                {
                       /*
                        **      Out of bytes in current block, so read next block
                      */

                        pbytes = byte_buff;
#if GET_BLOCK
                        if ((navail_bytes = get_block()) < 0)
                                return (navail_bytes);
#else
                        if ((navail_bytes = get_byte()) < 0)
                                return (navail_bytes);
                        else if (navail_bytes)
                        {
                                for (i = 0 ; i < navail_bytes ; ++i)
                                {
                                        if ((x = get_byte()) < 0)
                                                return (x);
                                        byte_buff[i] = x;
                                }
                        }
#endif
                }
                b1 = *pbytes++;
                nbits_left = 8;
                --navail_bytes;
        }

        ret = b1 >> (8 - nbits_left);
        while (curr_size > nbits_left)
        {
                if (navail_bytes <= 0)
                {
                       /*
                        **      Out of bytes in current block, so read next block
                      */

                        pbytes = byte_buff;
#if     GET_BLOCK
                        if ((navail_bytes = get_block()) < 0)
                                return (navail_bytes);
#else
                        if ((navail_bytes = get_byte()) < 0)
                                return (navail_bytes);
                        else if (navail_bytes)
                        {
                                for (i = 0 ; i < navail_bytes ; ++i)
                                {
                                        if ((x = get_byte()) < 0)
                                                return (x);
            &nbs