home *** CD-ROM | disk | FTP | other *** search
- /*
- * tkImgGIF.c --
- *
- * A photo image file handler for GIF files. Reads 87a and 89a GIF
- * files. At present there is no write function. GIF images may be
- * read using the -data option of the photo image by representing
- * the data as BASE64 encoded ascii. Derived from the giftoppm code
- * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2
- * distribution.
- *
- * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee
- * Copyright (c) 1995-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * This file also contains code from the giftoppm program, which is
- * copyrighted as follows:
- *
- * +-------------------------------------------------------------------+
- * | Copyright 1990, David Koblas. |
- * | Permission to use, copy, modify, and distribute this software |
- * | and its documentation for any purpose and without fee is hereby |
- * | granted, provided that the above copyright notice appear in all |
- * | copies and that both that copyright notice and this permission |
- * | notice appear in supporting documentation. This software is |
- * | provided "as is" without express or implied warranty. |
- * +-------------------------------------------------------------------+
- *
- * SCCS: @(#) tkImgGIF.c 1.19 97/08/13 15:23:45
- */
-
- /*
- * GIF's are represented as data in base64 format.
- * base64 strings consist of 4 6-bit characters -> 3 8 bit bytes.
- * A-Z, a-z, 0-9, + and / represent the 64 values (in order).
- * '=' is a trailing padding char when the un-encoded data is not a
- * multiple of 3 bytes. We'll ignore white space when encountered.
- * Any other invalid character is treated as an EOF
- */
-
- #define GIF_SPECIAL (256)
- #define GIF_PAD (GIF_SPECIAL+1)
- #define GIF_SPACE (GIF_SPECIAL+2)
- #define GIF_BAD (GIF_SPECIAL+3)
- #define GIF_DONE (GIF_SPECIAL+4)
-
- /*
- * structure to "mimic" FILE for Mread, so we can look like fread.
- * The decoder state keeps track of which byte we are about to read,
- * or EOF.
- */
-
- typedef struct mFile {
- unsigned char *data; /* mmencoded source string */
- int c; /* bits left over from previous character */
- int state; /* decoder state (0-4 or GIF_DONE) */
- } MFile;
-
- #include "tkInt.h"
- #include "tkPort.h"
-
- /*
- * The format record for the GIF file format:
- */
-
- static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, char *fileName,
- char *formatString, int *widthPtr, int *heightPtr));
- static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Channel chan, char *fileName, char *formatString,
- Tk_PhotoHandle imageHandle, int destX, int destY,
- int width, int height, int srcX, int srcY));
- static int StringMatchGIF _ANSI_ARGS_(( char *string,
- char *formatString, int *widthPtr, int *heightPtr));
- static int StringReadGIF _ANSI_ARGS_((Tcl_Interp *interp, char *string,
- char *formatString, Tk_PhotoHandle imageHandle,
- int destX, int destY, int width, int height,
- int srcX, int srcY));
-
- Tk_PhotoImageFormat tkImgFmtGIF = {
- "GIF", /* name */
- FileMatchGIF, /* fileMatchProc */
- StringMatchGIF, /* stringMatchProc */
- FileReadGIF, /* fileReadProc */
- StringReadGIF, /* stringReadProc */
- NULL, /* fileWriteProc */
- NULL, /* stringWriteProc */
- };
-
- #define INTERLACE 0x40
- #define LOCALCOLORMAP 0x80
- #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
- #define MAXCOLORMAPSIZE 256
- #define CM_RED 0
- #define CM_GREEN 1
- #define CM_BLUE 2
- #define CM_ALPHA 3
- #define MAX_LWZ_BITS 12
- #define LM_to_uint(a,b) (((b)<<8)|(a))
- #define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0)
-
- /*
- * HACK ALERT!! HACK ALERT!! HACK ALERT!!
- * This code is hard-wired for reading from files. In order to read
- * from a data stream, we'll trick fread so we can reuse the same code
- */
-
- static int fromData=0;
-
- /*
- * Prototypes for local procedures defined in this file:
- */
-
- static int DoExtension _ANSI_ARGS_((Tcl_Channel chan, int label,
- int *transparent));
- static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size,
- int flag));
- static int GetDataBlock _ANSI_ARGS_((Tcl_Channel chan,
- unsigned char *buf));
- static int LWZReadByte _ANSI_ARGS_((Tcl_Channel chan, int flag,
- int input_code_size));
- static int ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number,
- unsigned char buffer[MAXCOLORMAPSIZE][4]));
- static int ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan,
- int *widthPtr, int *heightPtr));
- static int ReadImage _ANSI_ARGS_((Tcl_Interp *interp,
- char *imagePtr, Tcl_Channel chan,
- int len, int rows,
- unsigned char cmap[MAXCOLORMAPSIZE][4],
- int width, int height, int srcX, int srcY,
- int interlace, int transparent));
-
- /*
- * these are for the BASE64 image reader code only
- */
-
- static int Fread _ANSI_ARGS_((unsigned char *dst, size_t size,
- size_t count, Tcl_Channel chan));
- static int Mread _ANSI_ARGS_((unsigned char *dst, size_t size,
- size_t count, MFile *handle));
- static int Mgetc _ANSI_ARGS_((MFile *handle));
- static int char64 _ANSI_ARGS_((int c));
- static void mInit _ANSI_ARGS_((unsigned char *string,
- MFile *handle));
-
- /*
- *----------------------------------------------------------------------
- *
- * FileMatchGIF --
- *
- * This procedure is invoked by the photo image type to see if
- * a file contains image data in GIF format.
- *
- * Results:
- * The return value is 1 if the first characters in file f look
- * like GIF data, and 0 otherwise.
- *
- * Side effects:
- * The access position in f may change.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- FileMatchGIF(chan, fileName, formatString, widthPtr, heightPtr)
- Tcl_Channel chan; /* The image file, open for reading. */
- char *fileName; /* The name of the image file. */
- char *formatString; /* User-specified format string, or NULL. */
- int *widthPtr, *heightPtr; /* The dimensions of the image are
- * returned here if the file is a valid
- * raw GIF file. */
- {
- return ReadGIFHeader(chan, widthPtr, heightPtr);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * FileReadGIF --
- *
- * This procedure is called by the photo image type to read
- * GIF format data from a file and write it into a given
- * photo image.
- *
- * Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in interp->result.
- *
- * Side effects:
- * The access position in file f is changed, and new data is
- * added to the image given by imageHandle.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY,
- width, height, srcX, srcY)
- Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
- Tcl_Channel chan; /* The image file, open for reading. */
- char *fileName; /* The name of the image file. */
- char *formatString; /* User-specified format string, or NULL. */
- Tk_PhotoHandle imageHandle; /* The photo image to write into. */
- int destX, destY; /* Coordinates of top-left pixel in
- * photo image to be written to. */
- int width, height; /* Dimensions of block of photo image to
- * be written to. */
- int srcX, srcY; /* Coordinates of top-left pixel to be used
- * in image being read. */
- {
- int fileWidth, fileHeight;
- int nBytes;
- Tk_PhotoImageBlock block;
- unsigned char buf[100];
- int bitPixel;
- unsigned char colorMap[MAXCOLORMAPSIZE][4];
- int transparent = -1;
-
- if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) {
- Tcl_AppendResult(interp, "couldn't read GIF header from file \"",
- fileName, "\"", NULL);
- return TCL_ERROR;
- }
- if ((fileWidth <= 0) || (fileHeight <= 0)) {
- Tcl_AppendResult(interp, "GIF image file \"", fileName,
- "\" has dimension(s) <= 0", (char *) NULL);
- return TCL_ERROR;
- }
-
- if (Fread(buf, 1, 3, chan) != 3) {
- return TCL_OK;
- }
- bitPixel = 2<<(buf[0]&0x07);
-
- if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */
- if (!ReadColorMap(chan, bitPixel, colorMap)) {
- Tcl_AppendResult(interp, "error reading color map",
- (char *) NULL);
- return TCL_ERROR;
- }
- }
-
- if ((srcX + width) > fileWidth) {
- width = fileWidth - srcX;
- }
- if ((srcY + height) > fileHeight) {
- height = fileHeight - srcY;
- }
- if ((width <= 0) || (height <= 0)
- || (srcX >= fileWidth) || (srcY >= fileHeight)) {
- return TCL_OK;
- }
-
- Tk_PhotoExpand(imageHandle, destX + width, destY + height);
-
- block.width = width;
- block.height = height;
- block.pixelSize = 4;
- block.pitch = block.pixelSize * block.width;
- block.offset[0] = 0;
- block.offset[1] = 1;
- block.offset[2] = 2;
- nBytes = height * block.pitch;
- block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
-
- while (1) {
- if (Fread(buf, 1, 1, chan) != 1) {
- /*
- * Premature end of image. We should really notify
- * the user, but for now just show garbage.
- */
-
- break;
- }
-
- if (buf[0] == ';') {
- /*
- * GIF terminator.
- */
-
- break;
- }
-
- if (buf[0] == '!') {
- /*
- * This is a GIF extension.
- */
-
- if (Fread(buf, 1, 1, chan) != 1) {
- interp->result =
- "error reading extension function code in GIF image";
- goto error;
- }
- if (DoExtension(chan, buf[0], &transparent) < 0) {
- interp->result = "error reading extension in GIF image";
- goto error;
- }
- continue;
- }
-
- if (buf[0] != ',') {
- /*
- * Not a valid start character; ignore it.
- */
- continue;
- }
-
- if (Fread(buf, 1, 9, chan) != 9) {
- interp->result = "couldn't read left/top/width/height in GIF image";
- goto error;
- }
-
- bitPixel = 1<<((buf[8]&0x07)+1);
-
- if (BitSet(buf[8], LOCALCOLORMAP)) {
- if (!ReadColorMap(chan, bitPixel, colorMap)) {
- Tcl_AppendResult(interp, "error reading color map",
- (char *) NULL);
- goto error;
- }
- }
- if (ReadImage(interp, (char *) block.pixelPtr, chan, width,
- height, colorMap, fileWidth, fileHeight, srcX, srcY,
- BitSet(buf[8], INTERLACE), transparent) != TCL_OK) {
- goto error;
- }
- break;
- }
-
- if (transparent == -1) {
- Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height);
- } else {
- int x, y, end;
- unsigned char *imagePtr, *rowPtr, *pixelPtr;
-
- imagePtr = rowPtr = block.pixelPtr;
- for (y = 0; y < height; y++) {
- x = 0;
- pixelPtr = rowPtr;
- while(x < width) {
- /* search for first non-transparent pixel */
- while ((x < width) && !(pixelPtr[CM_ALPHA])) {
- x++; pixelPtr += 4;
- }
- end = x;
- /* search for first transparent pixel */
- while ((end < width) && pixelPtr[CM_ALPHA]) {
- end++; pixelPtr += 4;
- }
- if (end > x) {
- block.pixelPtr = rowPtr + 4 * x;
- Tk_PhotoPutBlock(imageHandle, &block, destX+x,
- destY+y, end-x, 1);
- }
- x = end;
- }
- rowPtr += block.pitch;
- }
- block.pixelPtr = imagePtr;
- }
- ckfree((char *) block.pixelPtr);
- return TCL_OK;
-
- error:
- ckfree((char *) block.pixelPtr);
- return TCL_ERROR;
-
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * StringMatchGIF --
- *
- * This procedure is invoked by the photo image type to see if
- * a string contains image data in GIF format.
- *
- * Results:
- * The return value is 1 if the first characters in the string
- * like GIF data, and 0 otherwise.
- *
- * Side effects:
- * the size of the image is placed in widthPre and heightPtr.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- StringMatchGIF(string, formatString, widthPtr, heightPtr)
- char *string; /* the string containing the image data */
- char *formatString; /* the image format string */
- int *widthPtr; /* where to put the string width */
- int *heightPtr; /* where to put the string height */
- {
- unsigned char header[10];
- int got;
- MFile handle;
- mInit((unsigned char *) string, &handle);
- got = Mread(header, 10, 1, &handle);
- if (got != 10
- || ((strncmp("GIF87a", (char *) header, 6) != 0)
- && (strncmp("GIF89a", (char *) header, 6) != 0))) {
- return 0;
- }
- *widthPtr = LM_to_uint(header[6],header[7]);
- *heightPtr = LM_to_uint(header[8],header[9]);
- return 1;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * StringReadGif -- --
- *
- * This procedure is called by the photo image type to read
- * GIF format data from a base64 encoded string, and give it to
- * the photo image.
- *
- * Results:
- * A standard TCL completion code. If TCL_ERROR is returned
- * then an error message is left in interp->result.
- *
- * Side effects:
- * new data is added to the image given by imageHandle. This
- * procedure calls FileReadGif by redefining the operation of
- * fprintf temporarily.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- StringReadGIF(interp,string,formatString,imageHandle,
- destX, destY, width, height, srcX, srcY)
- Tcl_Interp *interp; /* interpreter for reporting errors in */
- char *string; /* string containing the image */
- char *formatString; /* format string if any */
- Tk_PhotoHandle imageHandle; /* the image to write this data into */
- int destX, destY; /* The rectangular region of the */
- int width, height; /* image to copy */
- int srcX, srcY;
- {
- int result;
- MFile handle;
- mInit((unsigned char *)string,&handle);
- fromData = 1;
- result = FileReadGIF(interp, (Tcl_Channel) &handle, "inline data",
- formatString, imageHandle, destX, destY, width, height,
- srcX, srcY);
- fromData = 0;
- return(result);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * ReadGIFHeader --
- *
- * This procedure reads the GIF header from the beginning of a
- * GIF file and returns the dimensions of the image.
- *
- * Results:
- * The return value is 1 if file "f" appears to start with
- * a valid GIF header, 0 otherwise. If the header is valid,
- * then *widthPtr and *heightPtr are modified to hold the
- * dimensions of the image.
- *
- * Side effects:
- * The access position in f advances.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- ReadGIFHeader(chan, widthPtr, heightPtr)
- Tcl_Channel chan; /* Image file to read the header from */
- int *widthPtr, *heightPtr; /* The dimensions of the image are
- * returned here. */
- {
- unsigned char buf[7];
-
- if ((Fread(buf, 1, 6, chan) != 6)
- || ((strncmp("GIF87a", (char *) buf, 6) != 0)
- && (strncmp("GIF89a", (char *) buf, 6) != 0))) {
- return 0;
- }
-
- if (Fread(buf, 1, 4, chan) != 4) {
- return 0;
- }
-
- *widthPtr = LM_to_uint(buf[0],buf[1]);
- *heightPtr = LM_to_uint(buf[2],buf[3]);
- return 1;
- }
-
- /*
- *-----------------------------------------------------------------
- * The code below is copied from the giftoppm program and modified
- * just slightly.
- *-----------------------------------------------------------------
- */
-
- static int
- ReadColorMap(chan, number, buffer)
- Tcl_Channel chan;
- int number;
- unsigned char buffer[MAXCOLORMAPSIZE][4];
- {
- int i;
- unsigned char rgb[3];
-
- for (i = 0; i < number; ++i) {
- if (! ReadOK(chan, rgb, sizeof(rgb))) {
- return 0;
- }
-
- buffer[i][CM_RED] = rgb[0] ;
- buffer[i][CM_GREEN] = rgb[1] ;
- buffer[i][CM_BLUE] = rgb[2] ;
- buffer[i][CM_ALPHA] = 255 ;
- }
- return 1;
- }
-
-
-
- static int
- DoExtension(chan, label, transparent)
- Tcl_Channel chan;
- int label;
- int *transparent;
- {
- static unsigned char buf[256];
- int count;
-
- switch (label) {
- case 0x01: /* Plain Text Extension */
- break;
-
- case 0xff: /* Application Extension */
- break;
-
- case 0xfe: /* Comment Extension */
- do {
- count = GetDataBlock(chan, (unsigned char*) buf);
- } while (count > 0);
- return count;
-
- case 0xf9: /* Graphic Control Extension */
- count = GetDataBlock(chan, (unsigned char*) buf);
- if (count < 0) {
- return 1;
- }
- if ((buf[0] & 0x1) != 0) {
- *transparent = buf[3];
- }
-
- do {
- count = GetDataBlock(chan, (unsigned char*) buf);
- } while (count > 0);
- return count;
- }
-
- do {
- count = GetDataBlock(chan, (unsigned char*) buf);
- } while (count > 0);
- return count;
- }
-
- static int ZeroDataBlock = 0;
-
- static int
- GetDataBlock(chan, buf)
- Tcl_Channel chan;
- unsigned char *buf;
- {
- unsigned char count;
-
- if (! ReadOK(chan, &count,1)) {
- return -1;
- }
-
- ZeroDataBlock = count == 0;
-
- if ((count != 0) && (! ReadOK(chan, buf, count))) {
- return -1;
- }
-
- return count;
- }
-
-
- static int
- ReadImage(interp, imagePtr, chan, len, rows, cmap,
- width, height, srcX, srcY, interlace, transparent)
- Tcl_Interp *interp;
- char *imagePtr;
- Tcl_Channel chan;
- int len, rows;
- unsigned char cmap[MAXCOLORMAPSIZE][4];
- int width, height;
- int srcX, srcY;
- int interlace;
- int transparent;
- {
- unsigned char c;
- int v;
- int xpos = 0, ypos = 0, pass = 0;
- char *pixelPtr;
-
-
- /*
- * Initialize the Compression routines
- */
- if (! ReadOK(chan, &c, 1)) {
- Tcl_AppendResult(interp, "error reading GIF image: ",
- Tcl_PosixError(interp), (char *) NULL);
- return TCL_ERROR;
- }
-
- if (LWZReadByte(chan, 1, c) < 0) {
- interp->result = "format error in GIF image";
- return TCL_ERROR;
- }
-
- if (transparent!=-1) {
- cmap[transparent][CM_RED] = 0;
- cmap[transparent][CM_GREEN] = 0;
- cmap[transparent][CM_BLUE] = 0;
- cmap[transparent][CM_ALPHA] = 0;
- }
-
- pixelPtr = imagePtr;
- while ((v = LWZReadByte(chan, 0, c)) >= 0 ) {
-
- if ((xpos>=srcX) && (xpos<srcX+len) &&
- (ypos>=srcY) && (ypos<srcY+rows)) {
- *pixelPtr++ = cmap[v][CM_RED];
- *pixelPtr++ = cmap[v][CM_GREEN];
- *pixelPtr++ = cmap[v][CM_BLUE];
- *pixelPtr++ = cmap[v][CM_ALPHA];
- }
-
- ++xpos;
- if (xpos == width) {
- xpos = 0;
- if (interlace) {
- switch (pass) {
- case 0:
- case 1:
- ypos += 8; break;
- case 2:
- ypos += 4; break;
- case 3:
- ypos += 2; break;
- }
-
- while (ypos >= height) {
- ++pass;
- switch (pass) {
- case 1:
- ypos = 4; break;
- case 2:
- ypos = 2; break;
- case 3:
- ypos = 1; break;
- default:
- return TCL_OK;
- }
- }
- } else {
- ++ypos;
- }
- pixelPtr = imagePtr + (ypos-srcY) * len * 4;
- }
- if (ypos >= height)
- break;
- }
- return TCL_OK;
- }
-
- static int
- LWZReadByte(chan, flag, input_code_size)
- Tcl_Channel chan;
- int flag;
- int input_code_size;
- {
- static int fresh = 0;
- int code, incode;
- static int code_size, set_code_size;
- static int max_code, max_code_size;
- static int firstcode, oldcode;
- static int clear_code, end_code;
- static int table[2][(1<< MAX_LWZ_BITS)];
- static int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
- register int i;
-
- if (flag) {
- set_code_size = input_code_size;
- code_size = set_code_size+1;
- clear_code = 1 << set_code_size ;
- end_code = clear_code + 1;
- max_code_size = 2*clear_code;
- max_code = clear_code+2;
-
- GetCode(chan, 0, 1);
-
- fresh = 1;
-
- for (i = 0; i < clear_code; ++i) {
- table[0][i] = 0;
- table[1][i] = i;
- }
- for (; i < (1<<MAX_LWZ_BITS); ++i) {
- table[0][i] = table[1][0] = 0;
- }
-
- sp = stack;
-
- return 0;
- } else if (fresh) {
- fresh = 0;
- do {
- firstcode = oldcode = GetCode(chan, code_size, 0);
- } while (firstcode == clear_code);
- return firstcode;
- }
-
- if (sp > stack) {
- return *--sp;
- }
-
- while ((code = GetCode(chan, code_size, 0)) >= 0) {
- if (code == clear_code) {
- for (i = 0; i < clear_code; ++i) {
- table[0][i] = 0;
- table[1][i] = i;
- }
-
- for (; i < (1<<MAX_LWZ_BITS); ++i) {
- table[0][i] = table[1][i] = 0;
- }
-
- code_size = set_code_size+1;
- max_code_size = 2*clear_code;
- max_code = clear_code+2;
- sp = stack;
- firstcode = oldcode = GetCode(chan, code_size, 0);
- return firstcode;
-
- } else if (code == end_code) {
- int count;
- unsigned char buf[260];
-
- if (ZeroDataBlock) {
- return -2;
- }
-
- while ((count = GetDataBlock(chan, buf)) > 0)
- /* Empty body */;
-
- if (count != 0) {
- return -2;
- }
- }
-
- incode = code;
-
- if (code >= max_code) {
- *sp++ = firstcode;
- code = oldcode;
- }
-
- while (code >= clear_code) {
- *sp++ = table[1][code];
- if (code == table[0][code]) {
- return -2;
-
- /*
- * Used to be this instead, Steve Ball suggested
- * the change to just return.
- printf("circular table entry BIG ERROR\n");
- */
- }
- code = table[0][code];
- }
-
- *sp++ = firstcode = table[1][code];
-
- if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
- table[0][code] = oldcode;
- table[1][code] = firstcode;
- ++max_code;
- if ((max_code>=max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS))) {
- max_code_size *= 2;
- ++code_size;
- }
- }
-
- oldcode = incode;
-
- if (sp > stack)
- return *--sp;
- }
- return code;
- }
-
-
- static int
- GetCode(chan, code_size, flag)
- Tcl_Channel chan;
- int code_size;
- int flag;
- {
- static unsigned char buf[280];
- static int curbit, lastbit, done, last_byte;
- int i, j, ret;
- unsigned char count;
-
- if (flag) {
- curbit = 0;
- lastbit = 0;
- done = 0;
- return 0;
- }
-
-
- if ( (curbit+code_size) >= lastbit) {
- if (done) {
- /* ran off the end of my bits */
- return -1;
- }
- if (last_byte >= 2) {
- buf[0] = buf[last_byte-2];
- }
- if (last_byte >= 1) {
- buf[1] = buf[last_byte-1];
- }
-
- if ((count = GetDataBlock(chan, &buf[2])) == 0) {
- done = 1;
- }
-
- last_byte = 2 + count;
- curbit = (curbit - lastbit) + 16;
- lastbit = (2+count)*8 ;
- }
-
- ret = 0;
- for (i = curbit, j = 0; j < code_size; ++i, ++j) {
- ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
- }
-
- curbit += code_size;
-
- return ret;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Minit -- --
- *
- * This procedure initializes a base64 decoder handle
- *
- * Results:
- * none
- *
- * Side effects:
- * the base64 handle is initialized
- *
- *----------------------------------------------------------------------
- */
-
- static void
- mInit(string, handle)
- unsigned char *string; /* string containing initial mmencoded data */
- MFile *handle; /* mmdecode "file" handle */
- {
- handle->data = string;
- handle->state = 0;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Mread --
- *
- * This procedure is invoked by the GIF file reader as a
- * temporary replacement for "fread", to get GIF data out
- * of a string (using Mgetc).
- *
- * Results:
- * The return value is the number of characters "read"
- *
- * Side effects:
- * The base64 handle will change state.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- Mread(dst, chunkSize, numChunks, handle)
- unsigned char *dst; /* where to put the result */
- size_t chunkSize; /* size of each transfer */
- size_t numChunks; /* number of chunks */
- MFile *handle; /* mmdecode "file" handle */
- {
- register int i, c;
- int count = chunkSize * numChunks;
-
- for(i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) {
- *dst++ = c;
- }
- return i;
- }
-
- /*
- * get the next decoded character from an mmencode handle
- * This causes at least 1 character to be "read" from the encoded string
- */
-
- /*
- *----------------------------------------------------------------------
- *
- * Mgetc --
- *
- * This procedure decodes and returns the next byte from a base64
- * encoded string.
- *
- * Results:
- * The next byte (or GIF_DONE) is returned.
- *
- * Side effects:
- * The base64 handle will change state.
- *
- *----------------------------------------------------------------------
- */
-
- static int
- Mgetc(handle)
- MFile *handle; /* Handle containing decoder data and state. */
- {
- int c;
- int result = 0; /* Initialization needed only to prevent
- * gcc compiler warning. */
-
- if (handle->state == GIF_DONE) {
- return(GIF_DONE);
- }
-
- do {
- c = char64(*handle->data);
- handle->data++;
- } while (c==GIF_SPACE);
-
- if (c>GIF_SPECIAL) {
- handle->state = GIF_DONE;
- return(handle->state ? handle->c : GIF_DONE);
- }
-
- switch (handle->state++) {
- case 0:
- handle->c = c<<2;
- result = Mgetc(handle);
- break;
- case 1:
- result = handle->c | (c>>4);
- handle->c = (c&0xF)<<4;
- break;
- case 2:
- result = handle->c | (c>>2);
- handle->c = (c&0x3) << 6;
- break;
- case 3:
- result = handle->c | c;
- handle->state = 0;
- break;
- }
- return(result);
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * char64 --
- *
- * This procedure converts a base64 ascii character into its binary
- * equivalent. This code is a slightly modified version of the
- * char64 proc in N. Borenstein's metamail decoder.
- *
- * Results:
- * The binary value, or an error code.
- *
- * Side effects:
- * None.
- *----------------------------------------------------------------------
- */
-
- static int
- char64(c)
- int c;
- {
- switch(c) {
- case 'A': return(0); case 'B': return(1); case 'C': return(2);
- case 'D': return(3); case 'E': return(4); case 'F': return(5);
- case 'G': return(6); case 'H': return(7); case 'I': return(8);
- case 'J': return(9); case 'K': return(10); case 'L': return(11);
- case 'M': return(12); case 'N': return(13); case 'O': return(14);
- case 'P': return(15); case 'Q': return(16); case 'R': return(17);
- case 'S': return(18); case 'T': return(19); case 'U': return(20);
- case 'V': return(21); case 'W': return(22); case 'X': return(23);
- case 'Y': return(24); case 'Z': return(25); case 'a': return(26);
- case 'b': return(27); case 'c': return(28); case 'd': return(29);
- case 'e': return(30); case 'f': return(31); case 'g': return(32);
- case 'h': return(33); case 'i': return(34); case 'j': return(35);
- case 'k': return(36); case 'l': return(37); case 'm': return(38);
- case 'n': return(39); case 'o': return(40); case 'p': return(41);
- case 'q': return(42); case 'r': return(43); case 's': return(44);
- case 't': return(45); case 'u': return(46); case 'v': return(47);
- case 'w': return(48); case 'x': return(49); case 'y': return(50);
- case 'z': return(51); case '0': return(52); case '1': return(53);
- case '2': return(54); case '3': return(55); case '4': return(56);
- case '5': return(57); case '6': return(58); case '7': return(59);
- case '8': return(60); case '9': return(61); case '+': return(62);
- case '/': return(63);
-
- case ' ': case '\t': case '\n': case '\r': case '\f': return(GIF_SPACE);
- case '=': return(GIF_PAD);
- case '\0': return(GIF_DONE);
- default: return(GIF_BAD);
- }
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * Fread --
- *
- * This procedure calls either fread or Mread to read data
- * from a file or a base64 encoded string.
- *
- * Results: - same as fread
- *
- *----------------------------------------------------------------------
- */
-
- static int
- Fread(dst, hunk, count, chan)
- unsigned char *dst; /* where to put the result */
- size_t hunk,count; /* how many */
- Tcl_Channel chan;
- {
- if (fromData) {
- return(Mread(dst, hunk, count, (MFile *) chan));
- } else {
- return Tcl_Read(chan, (char *) dst, (int) (hunk * count));
- }
- }
-