home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
rexx
/
library2
/
gbmrexx
/
gbm
/
gbmgif.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-10
|
22KB
|
924 lines
/*
GBMGIF.C Graphics Interchange Format support
Input options: index=# to get a given image in the file
*/
/*...sincludes:0:*/
#include <stdio.h>
#include <ctype.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <malloc.h>
#ifdef AIX
#include <unistd.h>
#else
#include <io.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "standard.h"
#include "gbm.h"
/*...vgbm\46\h:0:*/
/*...e*/
/*...suseful:0:*/
#define low_byte(w) ((byte) ((w)&0x00ff) )
#define high_byte(w) ((byte) (((w)&0xff00)>>8))
#define make_word(a,b) (((word)a) + (((word)b) << 8))
/*...e*/
/*...ssame:0:*/
static BOOLEAN same(char *s1, char *s2, int n)
{
for ( ; n--; s1++, s2++ )
if ( tolower(*s1) != tolower(*s2) )
return ( FALSE );
return ( TRUE );
}
/*...e*/
/*...sfind_word:0:*/
static char *find_word(char *str, char *substr)
{
char buf [100+1], *s;
int len = strlen(substr);
for ( s = strtok(strcpy(buf, str), " \t,");
s != NULL;
s = strtok(NULL, " \t,") )
if ( same(s, substr, len) && s [len] == '\0' )
return ( str + (s - buf) );
return ( NULL );
}
/*...e*/
/*...sfind_word_prefix:0:*/
static char *find_word_prefix(char *str, char *substr)
{
char buf [100+1], *s;
int len = strlen(substr);
for ( s = strtok(strcpy(buf, str), " \t,");
s != NULL;
s = strtok(NULL, " \t,") )
if ( same(s, substr, len) )
return ( str + (s - buf) );
return ( NULL );
}
/*...e*/
static GBMFT gif_gbmft =
{
"GIF",
"CompuServe Graphics Interchange Format",
"GIF",
GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|
GBM_FT_W1|GBM_FT_W4|GBM_FT_W8,
};
#define GBM_ERR_GIF_BPP ((GBM_ERR) 1100)
#define GBM_ERR_GIF_TERM ((GBM_ERR) 1101)
#define GBM_ERR_GIF_CODE_SIZE ((GBM_ERR) 1102)
#define GBM_ERR_GIF_CORRUPT ((GBM_ERR) 1103)
typedef struct
{
BOOLEAN ilace, errok;
int bpp;
byte pal [0x100 * 3];
} GIF_PRIV;
/*...sgif_qft:0:*/
GBM_ERR gif_qft(GBMFT *gbmft)
{
*gbmft = gif_gbmft;
return ( GBM_ERR_OK );
}
/*...e*/
/*...sgif_rhdr:0:*/
GBM_ERR gif_rhdr(char *fn, int fd, GBM *gbm, char *opt)
{
GIF_PRIV *gif_priv = (GIF_PRIV *) gbm -> priv;
byte signiture [6], scn_desc [7], image_desc [10];
char *index;
int img = 0, img_want = 1;
int bits_gct;
fn=fn; /* Suppress 'unref arg' compiler warnings */
/* Discover which image in GIF file we want */
if ( (index = find_word_prefix(opt, "index=")) != NULL )
sscanf(index + 6, "%d", &img_want);
gif_priv -> errok = ( find_word(opt, "errok") != NULL );
/* Read and validate signiture block */
lseek(fd, 0L, SEEK_SET);
if ( read(fd, signiture, 6) != 6 )
return ( GBM_ERR_READ );
if ( memcmp(signiture, "GIF87a", 6) &&
memcmp(signiture, "GIF89a", 6) )
return ( GBM_ERR_BAD_MAGIC );
/* Read screen descriptor */
if ( read(fd, scn_desc, 7) != 7 )
return ( GBM_ERR_READ );
gif_priv -> bpp = bits_gct = (scn_desc [4] & 7) + 1;
if ( scn_desc [4] & 0x80 )
/* Global colour table follows screen descriptor */
{
if ( read(fd, gif_priv -> pal, 3 << bits_gct) != (3 << bits_gct) )
return ( GBM_ERR_READ );
}
else
/* Blank out palette, but make entry 1 white */
{
memset(gif_priv -> pal, 0, 3 << bits_gct);
gif_priv -> pal [3] =
gif_priv -> pal [4] =
gif_priv -> pal [5] = 0xff;
}
/* Expected image descriptors / extension blocks / terminator */
while ( img < img_want )
{
if ( read(fd, image_desc, 1) != 1 )
return ( GBM_ERR_READ );
switch ( image_desc [0] )
{
/*...s0x2c \45\ image descriptor:24:*/
case 0x2c:
if ( read(fd, image_desc + 1, 9) != 9 )
return ( GBM_ERR_READ );
gbm -> w = make_word(image_desc [5], image_desc [6]);
gbm -> h = make_word(image_desc [7], image_desc [8]);
gif_priv -> ilace = ( (image_desc [9] & 0x40) != 0 );
if ( image_desc [9] & 0x80 )
/* Local colour table follows */
{
gif_priv -> bpp = (scn_desc [9] & 7) + 1;
if ( read(fd, gif_priv -> pal, 3 << gif_priv -> bpp) != (3 << gif_priv -> bpp) )
return ( GBM_ERR_READ );
}
if ( ++img != img_want )
/* Skip the image data */
{
byte code_size, block_size;
if ( read(fd, &code_size, 1) != 1 )
return ( GBM_ERR_READ );
do
{
if ( read(fd, &block_size, 1) != 1 )
return ( GBM_ERR_READ );
lseek(fd, block_size, SEEK_SET);
}
while ( block_size );
}
break;
/*...e*/
/*...s0x21 \45\ extension block:24:*/
/* Ignore all extension blocks */
case 0x21:
{
byte func_code, byte_count;
if ( read(fd, &func_code, 1) != 1 )
return ( GBM_ERR_READ );
do
{
if ( read(fd, &byte_count, 1) != 1 )
return ( GBM_ERR_READ );
lseek(fd, byte_count, SEEK_CUR);
}
while ( byte_count );
}
break;
/*...e*/
/*...s0x3b \45\ terminator:24:*/
/* Oi, we were hoping to get an image descriptor! */
case 0x3b:
return ( GBM_ERR_GIF_TERM );
/*...e*/
}
}
switch ( gif_priv -> bpp )
{
case 1: gbm -> bpp = 1; break;
case 2:
case 3:
case 4: gbm -> bpp = 4; break;
case 5:
case 6:
case 7:
case 8: gbm -> bpp = 8; break;
default: return ( GBM_ERR_GIF_BPP );
}
return ( GBM_ERR_OK );
}
/*...e*/
/*...sgif_rpal:0:*/
GBM_ERR gif_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
{
GIF_PRIV *gif_priv = (GIF_PRIV *) gbm -> priv;
byte *pal = gif_priv -> pal;
int i;
fd=fd; /* Suppress 'unref arg' compiler warning */
memset(gbmrgb, 0x80, (sizeof(GBMRGB) << gbm -> bpp));
for ( i = 0; i < (1 << gif_priv -> bpp); i++ )
{
gbmrgb [i].r = *pal++;
gbmrgb [i].g = *pal++;
gbmrgb [i].b = *pal++;
}
return ( GBM_ERR_OK );
}
/*...e*/
/*...sgif_rdata:0:*/
/*...scword \45\ code word:0:*/
/*
For some 32 bit systems, eg: Intel 386 processor, it may be quicker to use
a 32 bit operation, rather than a 16 bit one. Hence the following :-
*/
#ifdef OS2
typedef dword cword;
#else
typedef word cword;
#endif
/*...e*/
/*...sread context:0:*/
typedef struct
{
int fd; /* File descriptor to read */
int inx, size; /* Index and size in bits */
byte buf [255+3]; /* Buffer holding bits */
int code_size; /* Number of bits to return at once */
cword read_mask; /* 2^code_size-1 */
} READ_CONTEXT;
static cword read_code(READ_CONTEXT *c)
{
int raw_code, byte_inx;
if ( c -> inx + c -> code_size > c -> size )
/*...snot enough bits in buffer\44\ refill it:16:*/
/* Not very efficient, but infrequently called */
{
int bytes_to_lose = (c -> inx >> 3);
byte bytes;
/* Note biggest code size is 12 bits */
/* And this can at worst span 3 bytes */
memcpy(c -> buf, c -> buf + bytes_to_lose, 3);
(c -> inx) &= 7;
(c -> size) -= (bytes_to_lose << 3);
if ( read(c -> fd, &bytes, 1) != 1 )
return ( 0xffff );
if ( read(c -> fd, c -> buf + (c -> size >> 3), bytes) != bytes )
return ( 0xffff );
(c -> size) += (bytes << 3);
}
/*...e*/
byte_inx = (c -> inx >> 3);
raw_code = c -> buf [byte_inx] + ((c -> buf [byte_inx + 1]) << 8);
if ( c -> code_size > 8 )
raw_code += ((c -> buf [byte_inx + 2]) << 16);
raw_code >>= ((c -> inx) & 7);
(c -> inx) += (byte) (c -> code_size);
return ( (cword) raw_code & c -> read_mask );
}
/*...e*/
/*...soutput context:0:*/
typedef struct
{
int x, y, w, h, bpp, pass;
BOOLEAN ilace;
int stride;
byte *data, *data_this_line;
} OUTPUT_CONTEXT;
static void output(byte value, OUTPUT_CONTEXT *o)
{
if ( o -> y >= o -> h )
return;
switch ( o -> bpp )
{
case 1:
if ( (o -> x) & 7 )
o -> data_this_line [(o -> x) >> 3] |= (value << (7 - ((o -> x) & 7)));
else
o -> data_this_line [(o -> x) >> 3] = (value << 7);
break;
case 4:
if ( (o -> x) & 1 )
o -> data_this_line [(o -> x) >> 1] |= value;
else
o -> data_this_line [(o -> x) >> 1] = (value << 4);
break;
case 8:
o -> data_this_line [o -> x] = value;
break;
}
if ( ++(o -> x) < o -> w )
return;
o -> x = 0;
if ( o -> ilace )
{
switch ( o -> pass )
{
case 0:
(o -> y) += 8;
if ( o -> y >= o -> h )
{
(o -> pass)++;
o -> y = 4;
}
break;
case 1:
(o -> y) += 8;
if ( o -> y >= o -> h )
{
(o -> pass)++;
o -> y = 2;
}
break;
case 2:
(o -> y) += 4;
if ( o -> y >= o -> h )
{
(o -> pass)++;
o -> y = 1;
}
break;
case 3:
(o -> y) += 2;
break;
}
o -> data_this_line = o -> data + (o -> h - 1 - o -> y) * o -> stride;
}
else
{
(o -> y)++;
o -> data_this_line -= (o -> stride);
}
}
/*...e*/
GBM_ERR gif_rdata(int fd, GBM *gbm, byte *data)
{
GIF_PRIV *gif_priv = (GIF_PRIV *) gbm -> priv;
byte min_code_size; /* As read from the file */
int init_code_size; /* Initial code size */
cword max_code; /* 1 << code_size */
cword clear_code; /* Code to clear table */
cword eoi_code; /* End of information code */
cword first_free_code; /* First free code */
cword free_code; /* Next available free code slot */
word bit_mask; /* Output pixel mask */
int i, out_count = 0;
cword code, cur_code, old_code, in_code, fin_char;
cword *prefix, *suffix, *outcode;
READ_CONTEXT c;
OUTPUT_CONTEXT o;
BOOLEAN table_full = FALSE; /* To help implement deferred clear */
if ( (prefix = (cword *) malloc(4096 * sizeof(cword))) == NULL )
return ( GBM_ERR_MEM );
if ( (suffix = (cword *) malloc(4096 * sizeof(cword))) == NULL )
{
free(prefix);
return ( GBM_ERR_MEM );
}
if ( (outcode = (cword *) malloc(4097 * sizeof(cword))) == NULL )
{
free(suffix);
free(prefix);
return ( GBM_ERR_MEM );
}
if ( read(fd, &min_code_size, 1) != 1 )
{
free(outcode);
free(suffix);
free(prefix);
return ( GBM_ERR_READ );
}
if ( min_code_size < 2 || min_code_size > 9 )
{
free(outcode);
free(suffix);
free(prefix);
return ( GBM_ERR_GIF_CODE_SIZE );
}
/* Initial read context */
c.inx = 0;
c.size = 0;
c.fd = fd;
c.code_size = min_code_size + 1;
c.read_mask = (cword) (( 1 << c.code_size ) - 1);
/* Initialise pixel-output context */
o.x = 0;
o.y = 0;
o.pass = 0;
o.w = gbm -> w;
o.h = gbm -> h;
o.bpp = gbm -> bpp;
o.ilace = gif_priv -> ilace;
o.stride = ( (gbm -> w * gbm -> bpp + 31) / 32 ) * 4;
o.data = data;
o.data_this_line = data + (gbm -> h - 1) * o.stride;
bit_mask = (word) ((1 << gif_priv -> bpp) - 1);
/* 2^min_code size accounts for all colours in file */
clear_code = (cword) ( 1 << min_code_size );
eoi_code = (cword) (clear_code + 1);
free_code = first_free_code = (cword) (clear_code + 2);
/* 2^(min_code_size+1) includes clear and eoi code and space too */
init_code_size = c.code_size;
max_code = (cword) ( 1 << c.code_size );
while ( (code = read_code(&c)) != eoi_code && code != 0xffff && o.y < o.h )
{
if ( code == clear_code )
{
c.code_size = init_code_size;
max_code = (cword) ( 1 << c.code_size );
c.read_mask = (cword) (max_code - 1);
free_code = first_free_code;
cur_code = old_code = code = read_code(&c);
if ( code == 0xffff )
break;
fin_char = (cur_code & bit_mask);
output(fin_char, &o);
table_full = FALSE;
}
else
{
cur_code = in_code = code;
if ( cur_code >= free_code )
{
cur_code = old_code;
outcode [out_count++] = fin_char;
}
while ( cur_code > bit_mask )
{
if ( out_count > 4096 )
{
free(outcode);
free(suffix);
free(prefix);
return ( gif_priv -> errok ? GBM_ERR_OK : GBM_ERR_GIF_CORRUPT );
}
outcode [out_count++] = suffix [cur_code];
cur_code = prefix [cur_code];
}
fin_char = (cur_code & bit_mask);
outcode [out_count++] = fin_char;
for ( i = out_count - 1; i >= 0; i-- )
output(outcode [i], &o);
out_count = 0;
/* Update dictionary */
if ( !table_full )
{
prefix [free_code] = old_code;
suffix [free_code] = fin_char;
/* Advance to next free slot */
if ( ++free_code >= max_code )
{
if ( c.code_size < 12 )
{
c.code_size++;
max_code <<= 1;
c.read_mask = (cword) (( 1 << c.code_size ) - 1);
}
else
table_full = TRUE;
}
}
old_code = in_code;
}
}
free(outcode);
free(suffix);
free(prefix);
if ( code == 0xffff )
return ( gif_priv -> errok ? GBM_ERR_OK : GBM_ERR_READ );
return ( GBM_ERR_OK );
}
/*...e*/
/*...sgif_w:0:*/
/*
We won't write any GIF89a or higher extensions into file.
Write palette as global colour table, not local.
strings holds code strings in the format
2 byte code number
1 byte length of string of pixels = N
N bytes of pixels
hashcode is calculated from a string of pixels cumulatively.
hashtable is searched starting at index hashcode for to find the entry.
hashtable is big enough so that 1/2 of size >= max num of strings.
*/
#define INIT_HASH(p) (((p)+3)*301)
/*...swrite context:0:*/
typedef struct
{
int fd; /* Open file descriptor to write to */
int inx; /* Bit index into buf */
int code_size; /* Code size in bits */
byte buf [255+2]; /* Biggest block + overflow space */
} WRITE_CONTEXT;
static BOOLEAN write_code(int code, WRITE_CONTEXT *w)
{
byte *buf = w -> buf + (w -> inx >> 3);
code <<= ((w -> inx) & 7);
*buf++ |= (byte) code ;
/*...scomment about IBM C\45\Set\47\2 optmiser bug:8:*/
/* C-Set/2 with CSD0044 optimiser bug shows itself in following code :-
LEA EDI,[EDX+01H]
MOV CL,AL
SAR CL,08H ; What!
MOV [EDI],CL
*/
/*...e*/
*buf++ = (byte) (code >> 8);
*buf = (byte) (code >> 16);
(w -> inx) += (w -> code_size);
if ( w -> inx >= 255 * 8 )
/* Flush out full buffer */
{
byte bytes = 255;
if ( write(w -> fd, &bytes, 1) != 1 )
return ( FALSE );
if ( write(w -> fd, w -> buf, 255) != 255 )
return ( FALSE );
memcpy(w -> buf, w -> buf + 255, 2);
memset(w -> buf + 2, 0, 255);
(w -> inx) -= (255 * 8);
}
return ( TRUE );
}
static BOOLEAN flush_code(WRITE_CONTEXT *w)
{
byte bytes = ((w -> inx + 7) >> 3);
if ( bytes )
{
if ( write(w -> fd, &bytes, 1) != 1 )
return ( FALSE );
if ( write(w -> fd, w -> buf, bytes) != bytes )
return ( FALSE );
}
/* Data block terminator - a block of zero size */
bytes = 0;
return ( write(w -> fd, &bytes, 1) == 1 );
}
/*...e*/
#define MAX_STRING 64 /* Just to prevent huge strings */
#define MAX_STRINGS 64000 /* Small enough for 16 bit */
#define MAX_HASH 8193 /* Prime, and much > 4096 */
GBM_ERR gif_w(char *fn, int fd, GBM *gbm, GBMRGB *gbmrgb, byte *data, char *opt)
{
int xpos = 0, ypos = 0, xscreen = gbm -> w, yscreen = gbm -> h;
int inx_background = 0;
byte scn_desc [7], image_desc [10], term;
int stride = ((gbm -> w * gbm -> bpp + 31) / 32) * 4;
WRITE_CONTEXT w;
int init_code_size, x, y, p;
word clear_code, eoi_code, lastentry;
int nextstring, numentries, numrealentries;
unsigned int hashcode, lenstring;
byte min_code_size;
byte string [MAX_STRING-2], *strings, **hashtable, *pdata;
char *s;
fn=fn; /* Suppress 'unref arg' compiler warnings */
if ( gbm -> bpp != 1 && gbm -> bpp != 4 && gbm -> bpp != 8 )
return ( GBM_ERR_NOT_SUPP );
if ( (s = find_word_prefix(opt, "xscreen=")) != NULL )
sscanf(s + 8, "%d", &xscreen);
if ( (s = find_word_prefix(opt, "yscreen=")) != NULL )
sscanf(s + 8, "%d", &yscreen);
if ( (s = find_word_prefix(opt, "background=")) != NULL )
sscanf(s + 11, "%d", &inx_background);
if ( (s = find_word_prefix(opt, "xpos=")) != NULL )
sscanf(s + 5, "%d", &xpos);
if ( (s = find_word_prefix(opt, "ypos=")) != NULL )
sscanf(s + 5, "%d", &ypos);
/* Write signiture */
if ( write(fd, "GIF87a", 6) != 6 )
return ( GBM_ERR_WRITE );
/* Write screen descriptor */
scn_desc [0] = low_byte(xscreen);
scn_desc [1] = high_byte(xscreen);
scn_desc [2] = low_byte(yscreen);
scn_desc [3] = high_byte(yscreen);
scn_desc [4] = (0x80 | ((gbm -> bpp - 1) * 0x11));
/* Global colour table follows */
/* Quality bpp == gct bpp == gbm -> bpp */
scn_desc [5] = (byte) inx_background;
scn_desc [6] = 0;
if ( write(fd, scn_desc, 7) != 7 )
return ( GBM_ERR_WRITE );
/* Write global colour table */
for ( p = 0; p < (1 << gbm -> bpp); p++ )
{
byte pal [3];
pal [0] = gbmrgb [p].r;
pal [1] = gbmrgb [p].g;
pal [2] = gbmrgb [p].b;
if ( write(fd, pal, 3) != 3 )
return ( GBM_ERR_WRITE );
}
/* Do image descriptor block */
image_desc [0] = (byte) 0x2c;
image_desc [1] = low_byte(xpos);
image_desc [2] = high_byte(xpos);
image_desc [3] = low_byte(ypos);
image_desc [4] = high_byte(ypos);
image_desc [5] = low_byte(gbm -> w);
image_desc [6] = high_byte(gbm -> w);
image_desc [7] = low_byte(gbm -> h);
image_desc [8] = high_byte(gbm -> h);
image_desc [9] = gbm -> bpp - 1;
/* Non-interlaced, no local colour map, no sorted palette */
if ( write(fd, image_desc, 10) != 10 )
return ( GBM_ERR_WRITE );
/* Now LZW encode data */
if ( (strings = (byte *) malloc(MAX_STRINGS)) == NULL )
return ( GBM_ERR_MEM );
if ( (hashtable = (byte **) malloc(MAX_HASH * sizeof(byte *))) == NULL )
{
free(strings);
return ( GBM_ERR_MEM );
}
/* Initialise encoder variables */
init_code_size = gbm -> bpp + 1;
if ( init_code_size == 2 )
/* Room for col0, col1, cc, eoi, but no others! */
init_code_size++;
min_code_size = init_code_size - 1;
if ( write(fd, &min_code_size, 1) != 1 )
{
free(hashtable);
free(strings);
return ( GBM_ERR_WRITE );
}
clear_code = ( 1 << min_code_size );
eoi_code = clear_code + 1;
/* Setup write context */
w.fd = fd;
w.inx = 0;
w.code_size = init_code_size;
memset(w.buf, 0, sizeof(w.buf));
if ( !write_code(clear_code, &w) )
{
free(hashtable);
free(strings);
return ( GBM_ERR_WRITE );
}
numentries = 0;
numrealentries = 0;
nextstring = 0;
lenstring = 0;
for ( hashcode = 0; hashcode < MAX_HASH; hashcode++ )
hashtable [hashcode] = NULL;
data += ( (gbm -> h - 1) * stride );
for ( y = gbm -> h - 1; y >= 0; y--, data -= stride )
for ( x = 0, pdata = data; x < gbm -> w; x++ )
{
byte col;
/*...sget col:24:*/
switch ( gbm -> bpp )
{
case 8:
col = *pdata++;
break;
case 4:
if ( x & 1 )
col = (*pdata++ & 0x0f);
else
col = (*pdata >> 4);
break;
default: /* must be 1 */
if ( (x & 7) == 7 )
col = (*pdata++ & 0x01);
else
col = ((*pdata >> (7-(x&7))) & 0x01);
break;
}
/*...e*/
/*...slzw encode:24:*/
string [0] = ++lenstring;
string [lenstring] = col;
if ( lenstring == 1 )
{
lastentry = col;
hashcode = INIT_HASH(col);
}
else
{
unsigned int i, j;
/* Find current string within strings, by generating hash of string,
and looking in strings for it starting at hashcode */
hashcode *= ( col + lenstring );
j = (hashcode % MAX_HASH);
for ( i = 0; i < MAX_HASH; i++ )
{
if ( ++j >= MAX_HASH )
j = 0;
if ( hashtable [j] == NULL )
break;
if ( !memcmp(hashtable [j]+2, string, 1 + lenstring) )
break;
}
if ( hashtable [j] != NULL && 2 + 1 + lenstring < MAX_STRING )
/* Found in the strings table */
{
byte *ptr = hashtable [j];
lastentry = (word) ptr [0] + ((word) ptr [1] << 8);
}
else
/* Not found, or length too long */
{
if ( !write_code(lastentry, &w) )
{
free(hashtable);
free(strings);
return ( GBM_ERR_WRITE );
}
numentries++;
if ( hashtable [j] == NULL )
/* Add string */
{
word entry = (word) (eoi_code + numentries);
byte *ptr = strings + nextstring;
hashtable [j] = ptr;
ptr [0] = (byte) entry;
ptr [1] = (byte) (entry >> 8);
memcpy(ptr + 2, string, 1 + lenstring);
nextstring += (2 + 1 + lenstring);
numrealentries++;
}
lenstring = string [0] = (byte) 1;
lastentry = string [1] = (byte) col;
hashcode = INIT_HASH(col);
if ( eoi_code + numentries == (1 << w.code_size) )
/* Next code will be written longer */
w.code_size++;
if ( eoi_code + numentries > 4093 ||
nextstring + MAX_STRING > MAX_STRINGS )
/* Reset tables */
{
if ( !write_code(lastentry, &w) )
{
free(hashtable);
free(strings);
return ( GBM_ERR_WRITE );
}
if ( !write_code(clear_code, &w) )
{
free(hashtable);
free(strings);
return ( GBM_ERR_WRITE );
}
numentries = 0;
numrealentries = 0;
nextstring = 0;
lenstring = 0;
w.code_size = init_code_size;
for ( j = 0; j < MAX_HASH; j++ )
hashtable [j] = NULL;
}
}
}
/*...e*/
}
free(hashtable);
free(strings);
if ( !write_code(lastentry, &w) )
return ( GBM_ERR_WRITE );
if ( !write_code(eoi_code, &w) )
return ( GBM_ERR_WRITE );
if ( !flush_code(&w) )
return ( GBM_ERR_WRITE );
/* Now write terminator */
term = (byte) 0x3b;
if ( write(fd, &term, 1) != 1 )
return ( GBM_ERR_WRITE );
return ( GBM_ERR_OK );
}
/*...e*/
/*...sgif_err:0:*/
char *gif_err(GBM_ERR rc)
{
switch ( (int) rc )
{
case GBM_ERR_GIF_BPP:
return ( "bad bits per pixel" );
case GBM_ERR_GIF_TERM:
return ( "terminator found before requested image descriptor" );
case GBM_ERR_GIF_CODE_SIZE:
return ( "code size not in range 2 to 9" );
case GBM_ERR_GIF_CORRUPT:
return ( "encoded data is corrupt" );
}
return ( NULL );
}
/*...e*/