aboutsummaryrefslogtreecommitdiff
path: root/pkg/dataio/import/bltins/ipgif.x
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /pkg/dataio/import/bltins/ipgif.x
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'pkg/dataio/import/bltins/ipgif.x')
-rw-r--r--pkg/dataio/import/bltins/ipgif.x883
1 files changed, 883 insertions, 0 deletions
diff --git a/pkg/dataio/import/bltins/ipgif.x b/pkg/dataio/import/bltins/ipgif.x
new file mode 100644
index 00000000..a7394e18
--- /dev/null
+++ b/pkg/dataio/import/bltins/ipgif.x
@@ -0,0 +1,883 @@
+include "../import.h"
+
+
+# IPGIF.X - Source file for the GIF builtin format converter.
+
+
+# Define the GIF data structure
+define MAX_CODE_ENTRIES 4096 # because LZW has 12 bit max
+define SZ_GIFSTRUCT 35
+define SZ_GIFCODE 280
+define SZ_GIFEXTN 256
+define SZ_GIFSTACK (2*MAX_CODE_ENTRIES+2)
+define SZ_GIFCTAB (2*MAX_CODE_ENTRIES+2)
+
+define GIF_FD Memi[$1] # GIF file descriptor
+define GIF_WIDTH Memi[$1+1] # Screen width
+define GIF_HEIGHT Memi[$1+2] # Screen height
+define GIF_CP Memi[$1+3] # Colormap pointer
+define GIF_BITPIX Memi[$1+4] # Bits per pixel
+define GIF_COLRES Memi[$1+5] # Color resolution
+define GIF_BACKGROUND Memi[$1+6] # background color (unused?)
+define GIF_ASPECT Memi[$1+7] # Aspect ratio
+define GIF_IMNUM Memi[$1+8] # Image number
+define GIF_CMAP Memi[$1+9] # Global colormap (ptr)
+
+define GIF_EXTBP Memi[$1+10] # Extension buffer (ptr)
+define GIF_CODEP Memi[$1+11] # Code table buffer (ptr)
+define GIF_CTABP Memi[$1+12] # Code table (ptr)
+define GIF_STACKP Memi[$1+13] # Stack (ptr)
+define GIF_CURBIT Memi[$1+14] # Decoder var
+define GIF_LASTBIT Memi[$1+15] # Decoder var
+define GIF_DONE Memi[$1+16] # Decoder var
+define GIF_LASTBYTE Memi[$1+17] # Decoder var
+define GIF_ZERO_DATABLOCK Memi[$1+18] # Decoder var
+define GIF_SP Memi[$1+19] # stack pointer
+
+define GIF_CLEAR_CODE Memi[$1+20] # LZW clear code
+define GIF_END_CODE Memi[$1+21] # LZW end code
+define GIF_FIRST_CODE Memi[$1+22] # LZW decoder var
+define GIF_OLD_CODE Memi[$1+23] # LZW decoder var
+define GIF_MAX_CODE Memi[$1+24] # LZW free code
+define GIF_MAX_CODE_SIZE Memi[$1+25] # LZW upper limit
+define GIF_CODE_SIZE Memi[$1+26] # LZW current code size
+define GIF_SET_CODE_SIZE Memi[$1+27] # LZW input code size
+define GIF_FRESH Memi[$1+28] # LZW init var
+
+# The following are used for GIF89a only.
+define GIF_TRANSPARENT Memi[$1+30] # Transparent Color Index
+define GIF_DELAYTIME Memi[$1+31] # Delay time
+define GIF_INPUTFLAG Memi[$1+32] # User input flag
+define GIF_DISPOSAL Memi[$1+33] # Disposal Method
+
+# Array macros.
+define CODEBUF Memc[GIF_CODEP($1)+$2]
+define EXTBUF Memc[GIF_EXTBP($1)+$2]
+define CODETAB Memc[GIF_CTABP($1)+($2*MAX_CODE_ENTRIES)+$3]
+define STACK Memc[GIF_STACKP($1)+$2]
+
+#---------------------------------------------------------------------------
+
+define INTERLACE 040X # Image descriptor flags
+define LOCAL_COLORMAP 080X
+
+# Define the flags for the GIF89a extension blocks.
+define GE_PLAINTEXT 001X # Plain Text Extension
+define GE_APPLICATION 0FFX # Application Extension
+define GE_COMMENT 0FEX # Comment Extension
+define GE_GCONTROL 0F9X # Graphics Control Extension
+
+define DEBUG false
+define VDEBUG false
+
+
+# IP_GIF - Read and process a GIF format file into an IRAF image.
+
+procedure ip_gif (ip, fname, info_only, verbose)
+
+pointer ip #i import struct pointer
+char fname[ARB] #i file name
+int info_only #i print out image info only?
+int verbose #i verbosity flag
+
+pointer gif
+int fd
+int bitpix, use_global_cmap, interlace
+int width, height, version
+char ch
+short sig[7], screen[12]
+
+pointer gif_open()
+int btoi(), strncmp(), gif_rdbyte(), gif_getbytes()
+int shifti()
+
+long filepos
+common /gifcom/ filepos
+
+begin
+ # Allocate the gif struct pointer.
+ gif = gif_open()
+ GIF_FD(gif) = IP_FD(ip)
+ fd = GIF_FD(gif)
+
+ # The GIF signature is verified in the database file but check it
+ # here anyway.
+ filepos = 1
+ call ip_lseek (fd, BOF)
+ if (gif_getbytes(fd, sig, 6) != OK)
+ call error (0, "Error reading GIF magic number.")
+ if (strncmp(sig[4],"87a",3) == 0)
+ version = 87
+ else if (strncmp(sig[4],"89a",3) == 0)
+ version = 89
+ else
+ call error (0, "Bad version: File is not a GIF 87a or 89A")
+
+ # Now read the screen descriptor.
+ if (gif_getbytes(fd, screen, 7) != OK)
+ call error (0, "Error reading screen descriptor.")
+
+ GIF_WIDTH(gif) = screen[1] + (256 * screen[2])
+ GIF_HEIGHT(gif) = screen[3] + (256 * screen[4])
+ GIF_BITPIX(gif) = shifti (2, and(int(screen[5]),07X))
+ GIF_COLRES(gif) = shifti (and(int(screen[5]), 070X), -3) + 1
+ GIF_BACKGROUND(gif) = screen[6]
+ GIF_ASPECT(gif) = screen[7]
+ if (DEBUG) {
+ call eprintf ("w:%d h:%d bpix:%d ncol:%d bkg:%d asp:%d\n")
+ call pargi(GIF_WIDTH(gif)); call pargi(GIF_HEIGHT(gif))
+ call pargi(GIF_BITPIX(gif)); call pargi(GIF_COLRES(gif))
+ call pargi(GIF_BACKGROUND(gif)); call pargi(GIF_ASPECT(gif))
+ call flush (STDERR)
+ }
+
+ # We'll set the buffer size to the full image to speed processing.
+ IP_SZBUF(ip) = GIF_HEIGHT(gif)
+
+ # See if we have a global colormap.
+ if (and (int(screen[5]), LOCAL_COLORMAP) > 0)
+ call gif_rdcmap (gif, GIF_BITPIX(gif), GIF_CMAP(gif))
+ IP_CMAP(ip) = GIF_CMAP(gif)
+
+ # Now process the rest of the image blocks.
+ GIF_IMNUM(gif) = 0
+ repeat {
+ if (gif_rdbyte(fd, ch) != OK) {
+ call error (0, "Bad data read.")
+ }
+
+ if (ch == ';') { # GIF terminator
+ break
+ }
+
+ if (ch == '!') { # Extension block
+ # Read the extension function code.
+ if (gif_rdbyte(fd, ch) != OK)
+ call error (0, "Bad data read.")
+ call gif_extension (gif, ch, IP_VERBOSE(ip))
+ next
+ }
+
+ if (ch != ',') { # not a valid start character
+ if (ch != '\0') { # quietly allow a NULL block
+ call eprintf ("Ignoring bogus start char 0x%02x.")
+ call pargc (ch)
+ }
+ next
+ }
+
+ # Read the current image descriptor block. There may be more
+ # than one image in a file so we'll just copy each image into
+ # a separate band of the output image (should be rare).
+ GIF_IMNUM(gif) = GIF_IMNUM(gif) + 1
+ if (gif_getbytes (fd, screen, 9) != OK)
+ call error (0, "Bad scene descriptor")
+
+ # See if this image has a local colormap. There supposedly aren't
+ # a lot of files that use this (GIF89a only) but we'll read it
+ # anyway so we don't get stung on file positioning.
+ if (and (int(screen[9]), LOCAL_COLORMAP) == LOCAL_COLORMAP)
+ use_global_cmap = NO
+ else
+ use_global_cmap = YES
+
+ # Unpack the image descriptor into useful things.
+ bitpix = shifti (1, (and (int(screen[9]), 07X) + 1))
+ interlace = btoi (and (int(screen[9]), INTERLACE) == INTERLACE)
+ width = screen[5] + (screen[6] * 256)
+ height = screen[7] + (screen[8] * 256)
+ if (DEBUG) {
+ call eprintf ("global_cmap:%d bitpix:%d ")
+ call pargi(use_global_cmap); call pargi(bitpix)
+ call eprintf ("interlace:%d w:%d h:%d\n")
+ call pargi(interlace); call pargi(width); call pargi(height)
+ }
+
+ if (info_only == NO) {
+ if (use_global_cmap == NO) {
+ # Process the image with a local colormap.
+ call gif_rdcmap (gif, bitpix, GIF_CMAP(gif))
+ call gif_read_image (ip, gif, width, height,
+ GIF_CMAP(gif), interlace)
+ } else {
+ # Process the image with the global colormap.
+ call gif_read_image (ip, gif, width, height,
+ GIF_CMAP(gif), interlace)
+ }
+ } else {
+ call ip_gif_info (ip, fname, version, width, height,
+ GIF_BITPIX(gif), use_global_cmap, interlace, verbose)
+ break
+ }
+ }
+
+ # Clean up.
+ call gif_close (gif)
+ IP_CMAP(ip) = NULL
+end
+
+
+# IP_GIF_INFO - Print information about the GIF file.
+
+procedure ip_gif_info (ip, fname, version, width, height, colres, global,
+ interlace, verbose)
+
+pointer ip #i task struct pointer
+char fname[ARB] #i file name
+int version #i GIF version
+int width, height #i image dimensions
+int colres #i number of colormap entries
+int global #i image has global colormap
+int interlace #i image is interlaced
+int verbose #i verbosity flag
+
+begin
+ # If not verbose print a one-liner.
+ if (verbose == NO) {
+# call printf ("Input file:\n\t")
+ call printf ("%s: %20t%d x %d \t\tCompuServe GIF %da format file\n")
+ call pargstr (fname)
+ call pargi (width)
+ call pargi (height)
+ call pargi (version)
+
+ # Print out the format comment if any.
+# if (IP_COMPTR(ip) != NULL) {
+# if (COMMENT(ip) != '\0') {
+# call printf ("%s\n")
+# call pargstr (COMMENT(ip))
+# }
+# call strcpy ("\0", COMMENT(ip), SZ_LINE)
+# }
+ return
+ }
+
+ # Print a more verbose description.
+ call printf ("%s: %20tCompuServe GIF %da Format File\n")
+ call pargstr (fname)
+ call pargi (version)
+
+ # Print out the format comment if any.
+ if (IP_COMPTR(ip) != NULL) {
+ if (COMMENT(ip) != '\0') {
+ call printf ("%s\n")
+ call pargstr (COMMENT(ip))
+ }
+ call strcpy ("\0", COMMENT(ip), SZ_LINE)
+ }
+
+ call printf ("%20tResolution:%38t%d x %d\n")
+ call pargi (width)
+ call pargi (height)
+
+ call printf ("%20tPixel storage: %38t%s\n")
+ if (interlace == YES)
+ call pargstr ("Interlaced order")
+ else
+ call pargstr ("Sequential order")
+
+ call printf ("%20tByte Order: %38t%s\n")
+ call pargstr ("LSB first")
+
+ call printf ("%20tType: %38t%s\n")
+ call pargstr ("8-bit Color indexed")
+
+ call printf ("%20t%s Colormap: %38t%d entries\n")
+ if (global == YES)
+ call pargstr ("Global")
+ else
+ call pargstr ("Local")
+ call pargi (colres)
+
+ call printf ("%20tCompression: %38t%s\n")
+ call pargstr ("Lempel-Ziv and Welch (LZW)")
+end
+
+
+# GIF_OPEN - Open the GIF structure descriptor.
+
+pointer procedure gif_open ()
+
+pointer gif
+
+begin
+ iferr (call calloc (gif, SZ_GIFSTRUCT, TY_STRUCT))
+ call error (0, "Error allocating GIF structure.")
+
+ # Allocate the extension and code buffers.
+ iferr (call calloc (GIF_CODEP(gif), SZ_GIFCODE, TY_CHAR))
+ call error (0, "Error allocating GIF code buffer pointer.")
+ iferr (call calloc (GIF_EXTBP(gif), SZ_GIFEXTN, TY_CHAR))
+ call error (0, "Error allocating GIF extension pointer.")
+ iferr (call calloc (GIF_CTABP(gif), SZ_GIFCTAB, TY_CHAR))
+ call error (0, "Error allocating code table pointer.")
+ iferr (call calloc (GIF_STACKP(gif), SZ_GIFSTACK, TY_CHAR))
+ call error (0, "Error allocating GIF stack pointer.")
+
+ # Initialize some of the variables to non-zero values.
+ GIF_ZERO_DATABLOCK(gif) = NO
+ GIF_TRANSPARENT(gif) = -1
+ GIF_DELAYTIME(gif) = -1
+ GIF_INPUTFLAG(gif) = -1
+
+ return (gif)
+end
+
+
+# GIF_CLOSE - Close the GIF structure descriptor.
+
+procedure gif_close (gif)
+
+pointer gif #i GIF struct pointer
+
+begin
+ call mfree (GIF_STACKP(gif), TY_CHAR)
+ call mfree (GIF_CTABP(gif), TY_CHAR)
+ call mfree (GIF_EXTBP(gif), TY_CHAR)
+ call mfree (GIF_CODEP(gif), TY_CHAR)
+
+ if (GIF_CMAP(gif) != NULL)
+ call mfree (GIF_CMAP(gif), TY_CHAR)
+ call mfree (gif, TY_STRUCT)
+end
+
+
+# GIF_READ_IMAGE - Read the image raster from the file. Decompress the
+# LZW compressed data stream into 8-bit pixels.
+
+procedure gif_read_image (ip, gif, width, height, cmap, interlace)
+
+pointer ip #i task struct pointer
+pointer gif #i GIF struct pointer
+int width, height #i image dimensions
+pointer cmap #i colormap pointer
+int interlace #i interlace flag
+
+pointer im, op, out, data
+char csize, pix, val
+int i, v, xpos, ypos, pass
+int nlines, line, percent
+
+pointer ip_evaluate()
+int gif_rdbyte(), gif_lzw_rdbyte()
+short ip_gcmap_val()
+
+begin
+ # Get the initial code_size for the compression routines.
+ if (gif_rdbyte(GIF_FD(gif), csize) != OK)
+ call error (0, "EOF or read error on image data.")
+ call gif_lzw_init (gif, csize)
+
+ # Patch up the pixtype param if needed.
+ call ip_fix_pixtype (ip)
+
+ # See if we need to create any outbands operands if the user didn't.
+ if (IP_NBANDS(ip) == ERR)
+ call ip_fix_outbands (ip)
+
+ im = IP_IM(ip)
+ op = PTYPE(ip,GIF_IMNUM(gif))
+ call malloc (data, width, TY_CHAR)
+ IO_DATA(op) = data
+ IO_NPIX(op) = width
+
+ # Get the pixels.
+ xpos = 0
+ ypos = 0
+ pass = 0
+ nlines = 0
+ percent = 0
+ repeat {
+ v = gif_lzw_rdbyte (gif)
+ if (v < 0)
+ break # at the EOF
+ else {
+ if (cmap != NULL && IP_USE_CMAP(ip) == YES) {
+ # Apply the colormap since this is just an index.
+ val = v + 1
+ pix = ip_gcmap_val (val, cmap)
+ } else
+ pix = char (v)
+ Memc[data+xpos] = pix # assign the pixel
+ }
+
+ xpos = xpos + 1
+ if (xpos == width) {
+ xpos = 0
+ nlines = nlines + 1
+
+ # Evaluate outbands expression.
+ do i = 1, IP_NBANDS(ip) {
+ out = ip_evaluate (ip, O_EXPR(ip,i))
+
+ # Write bands to output image
+ if (IP_OUTPUT(ip) != IP_NONE) {
+ line = ypos + 1
+ call ip_wrline (ip, im, out, GIF_WIDTH(gif), line,
+ (GIF_IMNUM(gif)-1)*IP_NBANDS(ip)+i)
+ }
+ call evvfree (out)
+ }
+
+ # Print percent done if being verbose
+ if (IP_VERBOSE(ip) == YES) {
+ if (nlines * 100 / height >= percent + 10) {
+ percent = percent + 10
+ call printf (" Status: %2d%% complete\r")
+ call pargi (percent)
+ call flush (STDOUT)
+ }
+ }
+
+ # if the image is interlaced adjust the line number accordingly,
+ # otherwise just increment it.
+ if (interlace == YES) {
+ switch (pass) {
+ case 0, 1:
+ ypos = ypos + 8
+ case 2:
+ ypos = ypos + 4
+ case 3:
+ ypos = ypos + 2
+ }
+
+ if (ypos >= height) {
+ pass = pass + 1
+ switch (pass) {
+ case 1:
+ ypos = 4
+ case 2:
+ ypos = 2
+ case 3:
+ ypos = 1
+ }
+ }
+ } else {
+ # Non-interlaced GIF so just increment the line number.
+ ypos = ypos + 1
+ }
+ }
+ }
+
+ if (IP_VERBOSE(ip) == YES) {
+ call printf (" Status: Done \n")
+ call flush (STDOUT)
+ }
+
+ # Clean up the data pointer.
+ call mfree (data, TY_CHAR)
+end
+
+
+# GIF_RDCMAP - Read a colormap (local or global) from the GIF file.
+
+procedure gif_rdcmap (gif, ncolors, cmap)
+
+pointer gif #i GIF struct pointer
+int ncolors #i number of colors to read
+pointer cmap #u local or global colormap ptr
+
+int i
+char rgb[3]
+int gif_getbytes()
+
+begin
+ if (cmap == NULL)
+ iferr (call calloc (cmap, 3*CMAP_SIZE, TY_CHAR))
+ call error (0, "Error allocating color map.")
+
+ do i = 1, ncolors {
+ # Read RGB colors.
+ if (gif_getbytes (GIF_FD(gif), rgb, 3) != OK)
+ call error (0, "Bad GIF colormap - not enough colors.")
+
+ # Load the colormap.
+ CMAP(cmap,IP_RED,i) = rgb[1]
+ CMAP(cmap,IP_GREEN,i) = rgb[2]
+ CMAP(cmap,IP_BLUE,i) = rgb[3]
+ }
+end
+
+
+# GIF_EXTENSION - Process a GIF extension block. For now we'll just ignore
+# these when converting the image but read the data blocks anyway. We should
+# still be able to read the image but won't take advantage of the GIF89a
+# extensions.
+
+procedure gif_extension (gif, label, verbose)
+
+pointer gif #i Gif struct pointer
+char label #i GIF extension label
+int verbose #i print verbose info?
+
+pointer sp, buf
+int val
+int and(), gif_get_data_block()
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_GIFCODE, TY_CHAR)
+
+ switch (label) {
+ case GE_PLAINTEXT: # Plain Text Extension
+ if (verbose == YES) {
+ call eprintf ("Warning: Ignoring a Plain Text Extension.\n")
+ call flush (STDERR)
+ }
+ case GE_APPLICATION: # Application Extension
+ if (verbose == YES) {
+ call eprintf ("Warning: Ignoring an Application Extension.\n")
+ call flush (STDERR)
+ }
+ case GE_COMMENT: # Comment Extension
+ # Simply print out the comment.
+ while (gif_get_data_block (gif, Memc[buf]) != 0) {
+ if (verbose == YES) {
+ call printf ("Comment: %s\n")
+ call pargstr (Memc[buf])
+ }
+ }
+ call sfree (sp)
+ return
+ case GE_GCONTROL: # Graphic Control Extension
+ # Process the graphic control block.
+ val = gif_get_data_block (gif, Memc[buf])
+ GIF_DISPOSAL(gif) = and (int(Memc[buf]/4), 07X)
+ GIF_INPUTFLAG(gif) = and (int(Memc[buf]/2), 01X)
+ GIF_DELAYTIME(gif) = Memc[buf+1] + (256 * Memc[buf+2])
+ if (and(int(Memc[buf]),01X) == 1)
+ GIF_TRANSPARENT(gif) = Memc[buf+3]
+
+ while (gif_get_data_block (gif, Memc[buf]) != 0)
+ ;
+
+ call sfree (sp)
+ return
+ default:
+ call eprintf ("Warning: Unknown extension label (0x%02x).\n")
+ call pargc (label)
+ call flush (STDERR)
+ }
+
+ # If we get here then we've ignored an extension but still need to
+ # eat the data blocks.
+ while (gif_get_data_block (gif, Memc[buf]) != 0)
+ ;
+
+ call sfree (sp)
+end
+
+
+# GIF_LZW_INIT - Initialize the LZW decompression variables.
+
+procedure gif_lzw_init (gif, input_code_size)
+
+pointer gif #i GIF struct pointer
+char input_code_size #i input code size
+
+int i, shifti()
+
+begin
+ GIF_SET_CODE_SIZE(gif) = input_code_size
+ GIF_CODE_SIZE(gif) = GIF_SET_CODE_SIZE(gif) + 1
+ GIF_CLEAR_CODE(gif) = shifti (1, GIF_SET_CODE_SIZE(gif))
+ GIF_END_CODE(gif) = GIF_CLEAR_CODE(gif) + 1
+ GIF_MAX_CODE_SIZE(gif) = 2 * GIF_CLEAR_CODE(gif)
+ GIF_MAX_CODE(gif) = GIF_CLEAR_CODE(gif) + 2
+
+ GIF_CURBIT(gif) = 0 # initialize the code vars
+ GIF_LASTBIT(gif) = 0
+ GIF_DONE(gif) = NO
+
+ GIF_FRESH(gif) = YES
+
+ # Initialize the code table.
+ for (i = 0; i < GIF_CLEAR_CODE(gif); i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,i) = i
+ }
+ for (; i < MAX_CODE_ENTRIES; i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,0) = 0
+ }
+
+ GIF_SP(gif) = 0
+end
+
+
+
+# GIF_LZW_RDBYTE -
+
+int procedure gif_lzw_rdbyte (gif)
+
+pointer gif #i GIF struct pointer
+
+pointer sp, buf
+int i, count
+int code, incode
+
+int gif_get_code(), gif_get_data_block()
+
+begin
+ if (GIF_FRESH(gif) == YES) {
+ GIF_FRESH(gif) = NO
+ repeat {
+ GIF_OLD_CODE(gif) = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ GIF_FIRST_CODE(gif) = GIF_OLD_CODE(gif)
+ } until (GIF_FIRST_CODE(gif) != GIF_CLEAR_CODE(gif))
+ return (GIF_FIRST_CODE(gif))
+ }
+
+ if (GIF_SP(gif) > 0) {
+ GIF_SP(gif) = GIF_SP(gif) - 1
+ return (STACK(gif,GIF_SP(gif)))
+ }
+
+ code = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ while (code >= 0) {
+
+ # The Clear Code sets everything back to its initial value, then
+ # reads the immediately subsequent code as uncompressed data.
+ if (code == GIF_CLEAR_CODE(gif)) {
+ for (i = 0; i < GIF_CLEAR_CODE(gif); i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,i) = i
+ }
+ for ( ; i < MAX_CODE_ENTRIES; i=i+1) {
+ CODETAB(gif,0,i) = 0
+ CODETAB(gif,1,i) = 0
+ }
+ GIF_CODE_SIZE(gif) = GIF_SET_CODE_SIZE(gif) + 1
+ GIF_MAX_CODE_SIZE(gif) = 2 * GIF_CLEAR_CODE(gif)
+ GIF_MAX_CODE(gif) = GIF_CLEAR_CODE(gif) + 2
+ GIF_SP(gif) = 0
+ GIF_OLD_CODE(gif) = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ GIF_FIRST_CODE(gif) = GIF_OLD_CODE(gif)
+ return (GIF_FIRST_CODE(gif))
+
+ # If this is the End Code we'll clean up a little before returning.
+ } else if (code == GIF_END_CODE(gif)) {
+ if (GIF_ZERO_DATABLOCK(gif) == YES)
+ return (ERR)
+
+ call smark (sp)
+ call salloc (buf, 260, TY_CHAR)
+
+ repeat {
+ count = gif_get_data_block (gif, Memc[buf])
+ } until (count <= 0)
+
+ if (count != 0) {
+ call eprintf (
+ "Missing EOD in data stream (common occurance)")
+ }
+ call sfree (sp)
+ return (ERR)
+ }
+
+ # Must be data so save it in incode.
+ incode = code
+
+ # If it's greater or equal than the Free Code it's not in the hash
+ # table yet, repeat the last character decoded.
+ if (code >= GIF_MAX_CODE(gif)) {
+ STACK(gif, GIF_SP(gif)) = GIF_FIRST_CODE(gif)
+ GIF_SP(gif) = GIF_SP(gif) + 1
+ code = GIF_OLD_CODE(gif)
+ }
+
+ while (code >= GIF_CLEAR_CODE(gif)) {
+ STACK(gif, GIF_SP(gif)) = CODETAB(gif,1,code)
+ GIF_SP(gif) = GIF_SP(gif) + 1
+ if (code == CODETAB(gif,0,code))
+ call error (0, "Circular GIF code table entry.")
+ code = CODETAB(gif,0,code)
+ }
+
+ GIF_FIRST_CODE(gif) = CODETAB(gif,1,code)
+ STACK(gif, GIF_SP(gif)) = GIF_FIRST_CODE(gif)
+ GIF_SP(gif) = GIF_SP(gif) + 1
+
+ if (VDEBUG) {
+ call eprintf("code=%d gmax=%d gmaxsz=%d 4096 old:%d frst:%d\n")
+ call pargi(code) ; call pargi(GIF_MAX_CODE(gif))
+ call pargi(GIF_MAX_CODE_SIZE(gif))
+ call pargi(GIF_OLD_CODE(gif))
+ call pargi(GIF_FIRST_CODE(gif))
+ }
+
+ # Point to the next slot in the table. If we exceed the current
+ # MaxCode value, increment the code size unless it's already 12.
+ # If it is, do nothing: the next code decompressed better be CLEAR
+
+ code = GIF_MAX_CODE(gif)
+ if (code < MAX_CODE_ENTRIES) {
+ CODETAB(gif,0,code) = GIF_OLD_CODE(gif)
+ CODETAB(gif,1,code) = GIF_FIRST_CODE(gif)
+ GIF_MAX_CODE(gif) = GIF_MAX_CODE(gif) + 1
+ if ((GIF_MAX_CODE(gif) >= GIF_MAX_CODE_SIZE(gif)) &&
+ (GIF_MAX_CODE_SIZE(gif) < MAX_CODE_ENTRIES)) {
+ GIF_MAX_CODE_SIZE(gif) = GIF_MAX_CODE_SIZE(gif) * 2
+ GIF_CODE_SIZE(gif) = GIF_CODE_SIZE(gif) + 1
+ }
+ }
+
+ GIF_OLD_CODE(gif) = incode
+
+ if (GIF_SP(gif) > 0) {
+ GIF_SP(gif) = GIF_SP(gif) - 1
+ return (STACK(gif,GIF_SP(gif)))
+ }
+
+ code = gif_get_code (gif, GIF_CODE_SIZE(gif))
+ }
+ return code
+end
+
+
+# GIF_GET_CODE - Fetch the next code from the raster data stream. The codes
+# can be any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
+# maintain our location in the Raster array as a BIT Offset. We compute the
+# byte Offset into the raster array by dividing this by 8, pick up three
+# bytes, compute the bit Offset into our 24-bit chunk, shift to bring the
+# desired code to the bottom, then mask it off and return it. Simple.
+
+int procedure gif_get_code (gif, code_size)
+
+pointer gif #i GIF struct pointer
+int code_size #i op code size
+
+int i, j, count, ret
+int val1, val2
+int btoi(), and(), shifti(), ori ()
+int gif_get_data_block()
+
+begin
+ # See if processing the next code will overflow our buffer. If so
+ # we get the next control block from the stream.
+ if ( (GIF_CURBIT(gif) + code_size) >= GIF_LASTBIT(gif)) {
+ if (GIF_DONE(gif) == YES) {
+ if (GIF_CURBIT(gif) >= GIF_LASTBIT(gif)) {
+ call error (0, "GIF_GET_CODE: Ran out of bits.\n")
+ return (ERR)
+ }
+ }
+
+ CODEBUF(gif,0) = CODEBUF(gif,GIF_LASTBYTE(gif)-2)
+ CODEBUF(gif,1) = CODEBUF(gif,GIF_LASTBYTE(gif)-1)
+
+ count = gif_get_data_block (gif, CODEBUF(gif,2))
+ if (count == 0)
+ GIF_DONE(gif) = YES
+
+ GIF_LASTBYTE(gif) = 2 + count
+ GIF_CURBIT(gif) = (GIF_CURBIT(gif) - GIF_LASTBIT(gif)) + 16
+ GIF_LASTBIT(gif) = (2 + count) * 8
+ }
+
+ # for (i = GIF_CURBIT(gif), j = 0; j < code_size; ++i, ++j)
+ # ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
+
+ i = GIF_CURBIT(gif)
+ j = 0
+ ret = 0
+ while (j < code_size) {
+ val1 = btoi ( and (int(CODEBUF(gif,i/8)), shifti(1,mod(i,8))) != 0 )
+ val2 = shifti (val1, j)
+ ret = ori (ret, val2)
+ i = i + 1
+ j = j + 1
+ }
+
+ GIF_CURBIT(gif) = GIF_CURBIT(gif) + code_size
+ if (VDEBUG) {
+ call eprintf (": returning %d\n");call pargi(ret);call flush(STDERR)
+ }
+
+ return (ret)
+end
+
+
+# GIF_GET_DATA_BLOCK - Get the next block of GIF data from the data stream so
+# it can be converted to raster data.
+
+int procedure gif_get_data_block (gif, buf)
+
+pointer gif #i GIF struct pointer
+char buf[ARB] #o data block
+
+char count
+int nb, btoi()
+int gif_rdbyte(), gif_getbytes()
+
+begin
+ if (gif_rdbyte (GIF_FD(gif), count) != OK) {
+ call error (0, "error in getting DataBlock size")
+ return (ERR)
+ }
+
+ GIF_ZERO_DATABLOCK(gif) = btoi (count == 0)
+ if (VDEBUG) {
+ call eprintf ("getDataBlock: count = %d "); call pargs(count) }
+ nb = count
+ if ((count != 0) && (gif_getbytes(GIF_FD(gif), buf, nb) != OK)) {
+ call error (0, "error in reading DataBlock")
+ return (ERR)
+ }
+ return count
+end
+
+
+
+# Byte I/O routines. We use the normal IMPORT procedures but localize the code
+# here to make it easier to keep track of the current file position (in bytes).
+
+# GIF_RDBYTE - Read a single byte at the current offset from the file.
+
+int procedure gif_rdbyte (fd, val)
+
+int fd #i file descriptor
+char val #o byte read
+
+short ip_getb()
+
+long filepos
+common /gifcom/ filepos
+
+begin
+ iferr (val = ip_getb (fd, filepos))
+ return (ERR)
+
+ filepos = filepos + 1
+ call ip_lseek (fd, filepos)
+
+ return (OK)
+end
+
+
+# GIF_GETBYTES - Read an array of bytes from the file at the current offset.
+
+int procedure gif_getbytes (fd, buffer, len)
+
+int fd #i file descriptor
+char buffer[ARB] #o output buffer
+int len #i no. of bytes to read
+
+pointer sp, bp
+
+long filepos
+common /gifcom/ filepos
+
+begin
+ call smark (sp)
+ call salloc (bp, len+1, TY_CHAR)
+ call aclrc (Memc[bp], len+1)
+
+ call ip_agetb (fd, bp, len) # read the bytes
+ call amovc (Memc[bp], buffer, len) # copy to output buffer
+ filepos = filepos + len
+ call ip_lseek (fd, filepos)
+
+ call sfree (sp)
+ return (OK)
+end