/***************************************************************************** * * THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND. THE AUTHOR * SHALL HAVE NO LIABILITY WITH RESPECT TO THE INFRINGEMENT OF COPYRIGHTS, * TRADE SECRETS OR ANY PATENTS BY THIS FILE OR ANY PART THEREOF. IN NO * EVENT WILL THE AUTHOR BE LIABLE FOR ANY LOST REVENUE OR PROFITS OR * OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL DAMAGES. * * IF YOU DECIDE TO USE THE INFORMATION CONTAINED IN THIS FILE TO CONSTRUCT * AND USE THE LZW ALGORITHM YOU AGREE TO ACCEPT FULL RESPONSIBILITY WITH * RESPECT TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRECTS OR ANY PATENTS. * IN NO EVENT WILL THE AUTHOR BE LIABLE FOR ANY LOST REVENUE OR PROFITS OR * OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL DAMAGES, INCLUDING BUT NOT * LIMITED TO ANY DAMAGES RESULTING FROM ANY ACTIONS IN A COURT OF LAW. * * YOU ARE HEREBY WARNED THAT USE OF THE LZW ALGORITHM WITHOUT HAVING * OBTAINED A PROPER LICENSE FROM UNISYS CONSTITUTES A VIOLATION OF * APPLICABLE PATENT LAW. AS SUCH YOU WILL BE HELD LEGALLY RESPONSIBLE FOR * ANY INFRINGEMENT OF THE UNISYS LZW PATENT. * * UNISYS REQUIRES YOU TO HAVE A LZW LICENSE FOR *EVERY* TASK IN WHICH THE * LZW ALGORITHM IS BEING USED (WHICH INCLUDES DECODING THE LZW COMPRESSED * RASTER DATA AS FOUND IN GIF IMAGES). THE FACT THAT YOUR APPLICATION MAY * OR MAY NOT BE DISTRIBUTED AS FREEWARE IS OF NO CONCERN TO UNISYS. * * IF YOU RESIDE IN A COUNTRY OR STATE WHERE SOFTWARE PATENT LAWS DO NOT APPLY, * PLEASE BE WARNED THAT EXPORTING SOFTWARE CONTAINING THE LZW ALGORITHM TO * COUNTRIES WHERE SOFTWARE PATENT LAW *DOES* APPLY WITHOUT A VALID LICENSE * ALSO CONSTITUTES A VIOLATION OF PATENT LAW IN THE COUNTRY OF DESTINATION. * * INFORMATION ON HOW TO OBTAIN A LZW LICENSE FROM UNISYS CAN BE OBTAINED * BY CONTACTING UNISYS AT lzw_info@unisys.com * *****************************************************************************/ /* * External gif decoder for a XmHTML widget. * * NOT copyrighted, may 1997. * Provided by an anonymous contributor. * * You are totally free to do everything you want with it. * * Used as follows: * XtVaSetValues(html, XmNdecodeGIFProc, decodeGIFImage, NULL); */ #define HAVE_GIF_CODEC /* ** Pulled out of nextCode */ #define MAX_LWZ_BITS 12 typedef struct _LZW{ int curbit; int lastbit; int get_done; int last_byte; int return_clear; int stack[(1<<(MAX_LWZ_BITS))*2]; int *sp; int code_size; int set_code_size; int max_code; int max_code_size; int clear_code; int end_code; unsigned char buf[280]; int table[2][(1<< MAX_LWZ_BITS)]; int firstcode; int oldcode; }LZW; static LZW *initLWZ(int input_code_size) { static LZW *lzw; lzw = (LZW *) malloc(sizeof(LZW)); memset(lzw, 0, sizeof(LZW)); lzw->set_code_size = input_code_size; lzw->code_size = lzw->set_code_size + 1; lzw->clear_code = 1 << lzw->set_code_size ; lzw->end_code = lzw->clear_code + 1; lzw->max_code_size = 2 * lzw->clear_code; lzw->max_code = lzw->clear_code + 2; lzw->curbit = lzw->lastbit = 0; lzw->last_byte = 2; lzw->get_done = False; lzw->return_clear = True; lzw->sp = lzw->stack; return lzw; } static int nextCode(LZW *lzw) { static int maskTbl[16] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, }; int i, j, ret, end; if ( lzw->return_clear ) { lzw->return_clear = False; return lzw->clear_code; } end = lzw->curbit + lzw->code_size; /* out of data for this call */ if ( end >= lzw->lastbit ) return -1; j = end / 8; i = lzw->curbit / 8; if ( i == j ) ret = (int)lzw->buf[i]; else if ( i + 1 == j ) ret = (int)lzw->buf[i] | ((int)lzw->buf[i+1] << 8); else ret = (int)lzw->buf[i] | ((int)lzw->buf[i+1] << 8) | ((int)lzw->buf[i+2] << 16); ret = ( ret >> ( lzw->curbit % 8 ) ) & maskTbl[lzw->code_size]; lzw->curbit += lzw->code_size; return ret; } #define readLWZ(lzw) ((lzw->sp > lzw->stack) ? *--lzw->sp : nextLWZ(lzw)) static int nextLWZ(LZW *lzw) { int code, incode; register int i; while( ( code = nextCode(lzw) ) >= 0) { if ( code == lzw->clear_code ) { /* corrupt GIFs can make this happen */ if ( lzw->clear_code >= ( 1 << MAX_LWZ_BITS ) ) return -2; for ( i = 0 ; i < lzw->clear_code ; ++i ) { lzw->table[0][i] = 0; lzw->table[1][i] = i; } for ( ; i < ( 1 << MAX_LWZ_BITS ) ; ++i ) lzw->table[0][i] = lzw->table[1][i] = 0; lzw->code_size = lzw->set_code_size+1; lzw->max_code_size = 2*lzw->clear_code; lzw->max_code = lzw->clear_code+2; lzw->sp = lzw->stack; do { lzw->firstcode = lzw->oldcode = nextCode(lzw); }while ( lzw->firstcode == lzw->clear_code ); return lzw->firstcode; } if ( code == lzw->end_code ) return -2; incode = code; if ( code >= lzw->max_code ) { *lzw->sp++ = lzw->firstcode; code = lzw->oldcode; } while ( code >= lzw->clear_code ) { *lzw->sp++ = lzw->table[1][code]; /* circular table entry BIG ERROR */ if ( code == lzw->table[0][code] ) return code; /* circular table STACK OVERFLOW! */ if ( (int) lzw->sp >= ( (int) lzw->stack + sizeof(lzw->stack) ) ) return code; code = lzw->table[0][code]; } *lzw->sp++ = lzw->firstcode = lzw->table[1][code]; if ( ( code = lzw->max_code ) < ( 1 << MAX_LWZ_BITS ) ) { lzw->table[0][code] = lzw->oldcode; lzw->table[1][code] = lzw->firstcode; ++lzw->max_code; if ( ( lzw->max_code >= lzw->max_code_size ) && ( lzw->max_code_size < ( 1 << MAX_LWZ_BITS ) ) ) { lzw->max_code_size *= 2; ++lzw->code_size; } } lzw->oldcode = incode; if ( lzw->sp > lzw->stack ) return *--lzw->sp; } return code; } /* * gstream contains the incoming data and should contain the decoded data * upon return. The number of bytes offered for decoding will never exceed * 256 (value of the avail_in field in the gstream structure) as this is the * maximum value a block of GIF data can possibly have. */ static int decodeGIFImage(XmHTMLGIFStream *gstream) { LZW *lzw; register int v; register unsigned char *dp; /* we are being told to initialize ourselves */ if ( gstream->state == GIF_STREAM_INIT ) { /* Initialize the decompression routines */ lzw = initLWZ(gstream->codesize); /* store it */ gstream->external_state = (XtPointer)lzw; /* and return OK */ return GIF_STREAM_OK; } /* pick up our LZW state */ lzw = (LZW *)gstream->external_state; /* * We are being told to destruct ourselves. * Note that for GIF_STREAM_END gstream->next_in will contain the value * \000\001; (zero-length data block and the GIF terminator code) and * gstream->avail_in will be equal to 3 */ if ( gstream->state == GIF_STREAM_FINAL || gstream->state == GIF_STREAM_END ) { /* free everything and return */ if ( lzw ) { free(lzw); gstream->external_state = (XtPointer)NULL; } return GIF_STREAM_END; } /* store new data */ lzw->buf[0] = lzw->buf[lzw->last_byte-2]; lzw->buf[1] = lzw->buf[lzw->last_byte-1]; memcpy(&lzw->buf[2], gstream->next_in, gstream->avail_in); lzw->last_byte = 2 + gstream->avail_in; lzw->curbit = (lzw->curbit - lzw->lastbit) + 16; lzw->lastbit = (2+gstream->avail_in)*8 ; /* current position in decoded output buffer */ dp = gstream->next_out; for( ; gstream->avail_out ; gstream->total_out++, gstream->avail_out-- ) { if ( ( v = readLWZ(lzw) ) < 0 ) { /* saw end_code */ if ( v == -2 ) return GIF_STREAM_END; /* processed all current data */ return GIF_STREAM_OK; } *dp++ = v; } /* end if we have processed all data (no more room in output buf) */ return( gstream->avail_out ? GIF_STREAM_OK : GIF_STREAM_END ); }