[comp.sources.misc] v15i088: G3 and G4 utilities - part 3/3

davidsen@crdos1.crd.ge.com (12/17/90)

Posting-number: Volume 15, Issue 88
Submitted-by: davidsen@crdos1.crd.ge.com
Archive-name: g3g4/part03

#!/bin/sh
# this is part 3 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file g4sdecod.c continued
#
CurArch=3
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
sed 's/^X//' << 'SHAR_EOF' >> g4sdecod.c
X		  else /* 011010010 */ return (832);
X		}
X		else /* 01101000 */ return (576);
X	      }
X	    }
X	  }
X	  else /* 01100... */
X	  {
X	    if (next_bit ()) /* 011001... */
X	    {
X	      if (next_bit ()) /* 0110011... */
X	      {
X		if (next_bit ()) /* 01100111 */ return (640);
X		else /* 01100110 */
X		{
X		  if (next_bit ()) /* 011001101 */ return (768);
X		  else /* 011001100 */ return (704);
X		}
X	      }
X	      else /* 0110010 */
X	      {
X		if (next_bit ()) /* 01100101 */ return (512);
X		else /* 01100100 */ return (448);
X	      }
X	    }
X	    else /* 011000 */ return (1664);
X	  }
X	}
X      }
X      else /* 010... */
X      {
X	if (next_bit ()) /* 0101... */
X	{
X	  if (next_bit ()) /* 01011... */
X	  {
X	    if (next_bit ()) /* 010111 */ return (192);
X	    else /* 010110... */
X	    {
X	      if (next_bit ()) /* 0101101... */
X	      {
X		if (next_bit ()) /* 01011011 */ return (58);
X		else /* 01011010 */ return (57);
X	      }
X	      else /* 0101100... */
X	      {
X		if (next_bit ()) /* 01011001 */ return (56);
X		else /* 01011000 */ return (55);
X	      }
X	    }
X	  }
X	  else /* 01010... */
X	  {
X	    if (next_bit ()) /* 010101... */
X	    {
X	      if (next_bit ()) /* 0101011 */ return (25);
X	      else /* 0101010... */
X	      {
X		if (next_bit ()) /* 01010101 */ return (52);
X		else /* 01010100 */ return (51);
X	      }
X	    }
X	    else /* 010100... */
X	    {
X	      if (next_bit ()) /* 0101001... */
X	      {
X		if (next_bit ()) /* 01010011 */ return (50);
X		else /* 01010010 */ return (49);
X	      }
X	      else /* 0101000 */ return (24);
X	    }
X	  }
X	}
X	else /* 0100... */
X	{
X	  if (next_bit ()) /* 01001... */
X	  {
X	    if (next_bit ()) /* 010011... */
X	    {
X	      if (next_bit ()) /* 0100111 */ return (18);
X	      else /* 0100110... */
X	      {
X		if (next_bit ()) /* 01001101... */
X		{
X		  if (next_bit ()) /* 010011011 */ return (1728);
X		  else /* 010011010 */ return (1600);
X		}
X		else /* 01001100... */
X		{
X		  if (next_bit ()) /* 010011001 */ return (1536);
X		  else /* 010011000 */ return (1472);
X		}
X	      }
X	    }
X	    else /* 010010... */
X	    {
X	      if (next_bit ()) /* 0100101... */
X	      {
X		if (next_bit ()) /* 01001011 */ return (60);
X		else /* 01001010 */ return (59);
X	      }
X	      else /* 0100100 */ return (27);
X	    }
X	  }
X	  else /* 01000 */ return (11);
X	}
X      }
X    }
X    else /* 00... */
X    {
X      if (next_bit ()) /* 001... */
X      {
X	if (next_bit ()) /* 0011... */
X	{
X	  if (next_bit ()) /* 00111 */ return (10);
X	  else /* 00110... */
X	  {
X	    if (next_bit ()) /* 001101... */
X	    {
X	      if (next_bit ()) /* 0011011... */
X	      {
X		if (next_bit ()) /* 00110111 */ return (384);
X		else /* 00110110 */ return (320);
X	      }
X	      else /* 0011010... */
X	      {
X		if (next_bit ()) /* 00110101 */ return (0);
X		else /* 00110100 */ return (63);
X	      }
X	    }
X	    else /* 001100... */
X	    {
X	      if (next_bit ()) /* 0011001... */
X	      {
X		if (next_bit ()) /* 00110011 */ return (62);
X		else /* 00110010 */ return (61);
X	      }
X	      else /* 0011000 */ return (28);
X	    }
X	  }
X	}
X	else /* 0010... */
X	{
X	  if (next_bit ()) /* 00101... */
X	  {
X	    if (next_bit ()) /* 001011... */
X	    {
X	      if (next_bit ()) /* 0010111 */ return (21);
X	      else /* 0010110... */
X	      {
X		if (next_bit ()) /* 00101101 */ return (44);
X		else /* 00101100 */ return (43);
X	      }
X	    }
X	    else /* 001010... */
X	    {
X	      if (next_bit ()) /* 0010101... */
X	      {
X		if (next_bit ()) /* 00101011 */ return (42);
X		else /* 00101010 */ return (41);
X	      }
X	      else /* 0010100... */
X	      {
X		if (next_bit ()) /* 00101001 */ return (40);
X		else /* 00101000 */ return (39);
X	      }
X	    }
X	  }
X	  else /* 00100... */
X	  {
X	    if (next_bit ()) /* 001001... */
X	    {
X	      if (next_bit ()) /* 0010011 */ return (26);
X	      else /* 0010010... */
X	      {
X		if (next_bit ()) /* 00100101 */ return (54);
X		else /* 00100100 */ return (53);
X	      }
X	    }
X	    else /* 001000 */ return (12);
X	  }
X	}
X      }
X      else /* 000... */
X      {
X	if (next_bit ()) /* 0001... */
X	{
X	  if (next_bit ()) /* 00011... */
X	  {
X	    if (next_bit ()) /* 000111 */ return (1);
X	    else /* 000110... */
X	    {
X	      if (next_bit ()) /* 0001101... */
X	      {
X		if (next_bit ()) /* 00011011 */ return (32);
X		else /* 00011010 */ return (31);
X	      }
X	      else /* 0001100 */ return (19);
X	    }
X	  }
X	  else /* 00010... */
X	  {
X	    if (next_bit ()) /* 000101... */
X	    {
X	      if (next_bit ()) /* 0001011... */
X	      {
X		if (next_bit ()) /* 00010111 */ return (38);
X		else /* 00010110 */ return (37);
X	      }
X	      else /* 0001010... */
X	      {
X		if (next_bit ()) /* 00010101 */ return (36);
X		else /* 00010100 */ return (35);
X	      }
X	    }
X	    else /* 000100... */
X	    {
X	      if (next_bit ()) /* 0001001... */
X	      {
X		if (next_bit ()) /* 00010011 */ return (34);
X		else /* 00010010 */ return (33);
X	      }
X	      else /* 0001000 */ return (20);
X	    }
X	  }
X	}
X	else /* 0000... */
X	{
X	  if (next_bit ()) /* 00001... */
X	  {
X	    if (next_bit ()) /* 000011 */ return (13);
X	    else /* 000010... */
X	    {
X	      if (next_bit ()) /* 0000101... */
X	      {
X		if (next_bit ()) /* 00001011 */ return (48);
X		else /* 00001010 */ return (47);
X	      }
X	      else /* 0000100 */ return (23);
X	    }
X	  }
X	  else /* 00000... */
X	  {
X	    if (next_bit ()) /* 000001... */
X	    {
X	      if (next_bit ()) /* 0000011 */ return (22);
X	      else /* 0000010... */
X	      {
X		if (next_bit ()) /* 00000101 */ return (46);
X		else /* 00000100 */ return (45);
X	      }
X	    }
X	    else /* 000000... */
X	    {
X	      if (next_bit ()) /* 0000001... */
X	      {
X		if (next_bit ()) /* 00000011 */ return (30);
X		else /* 00000010 */ return (29);
X	      }
X	      else /* 0000 000... */
X	      {
X		if (next_bit ()) /* 0000 0001... */
X		{
X		  if (next_bit ()) /* 0000 0001 1... */
X		  {
X		    if (next_bit ()) /* 0000 0001 11... */
X		    {
X		      if (next_bit ()) /* 0000 0001 111... */
X		      {
X			if (next_bit ()) /* 0000 0001 1111 */ return (2560);
X			else /* 0000 0001 1110 */ return (2496);
X		      }
X		      else /* 0000 0001 110... */
X		      {
X			if (next_bit ()) /* 0000 0001 1101 */ return (2432);
X			else /* 0000 0001 1100 */ return (2368);
X		      }
X		    }
X		    else /* 0000 0001 10... */
X		    {
X		      if (next_bit ()) /* 0000 0001 101 */ return (1920);
X		      else /* 0000 0001 100 */ return (1856);
X		    }
X		  }
X		  else /* 0000 0001 0... */
X		  {
X		    if (next_bit ()) /* 0000 0001 01... */
X		    {
X		      if (next_bit ()) /* 0000 0001 011... */
X		      {
X			if (next_bit ()) /* 0000 0001 0111 */ return (2304);
X			else /* 0000 0001 0110 */ return (2240);
X		      }
X		      else /* 0000 0001 010... */
X		      {
X			if (next_bit ()) /* 0000 0001 0101 */ return (2176);
X			else /* 0000 0001 0100 */ return (2112);
X		      }
X		    }
X		    else /* 0000 0001 00... */
X		    {
X		      if (next_bit ()) /* 0000 0001 001... */
X		      {
X			if (next_bit ()) /* 0000 0001 0011 */ return (2048);
X			else /* 0000 0001 0010 */ return (1984);
X		      }
X		      else /* 0000 0001 000 */ return (1792);
X		    }
X		  }
X		}
X		else /* 0000 0000... */
X		{
X		  if (next_bit ()) /* 0000 0000 1 */ return (INVALID_CODE);
X		  else /* 0000 0000 0... */
X		  {
X		    if (next_bit ()) /* 0000 0000 01 */ return (INVALID_CODE);
X		    else /* 0000 0000 00... */
X		    {
X		      if (next_bit ()) /* 0000 0000 001 */
X							return (INVALID_CODE);
X		      else /* 0000 0000 000... */
X		      {
X			if (next_bit ()) /* 0000 0000 0001 */ return (EOL_CODE);
X			else /* 0000 0000 0000 */ return (INVALID_CODE);
X		      }
X		    }
X		  }
X		}
X	      }
X	    }
X	  }
X	}
X      }
X    }
X  }
X}
X
X/*	end $RCSfile: g4sdecod.c $ */
SHAR_EOF
chmod 0644 g4sdecod.c || echo "restore of g4sdecod.c fails"
sed 's/^X//' << 'SHAR_EOF' > g4sencod.c &&
X/*	$Id: g4sencod.c 1.2 90/06/09 18:24:10 marking Exp $
X *
X NAME
X *	g4sencod.c -- encode group 4 data using nested if statements
X *
X TYPE
X *	C procedures
X *
X SYNOPSIS
X *	char	g4j_encode_black (short runlength);
X *	char	g4j_encode_white (short runlength);
X *	char	g4j_encode_EOFB (void);
X *	char	g4j_encode_new_row (void);
X *	char	g4j_initialize (short image_width, short image_length);
X *
X DESCRIPTION
X *	Routines to encode group 4 images. Consecutive calls to encode
X *	black or white runs will be combined.
X *
X RETURNS
X *
X LEGAL
X *	Copyright 1989, 1990 Michael P. Marking, Post Office Box 8039,
X *	Scottsdale, Arizona 85252-8039. All rights reserved.
X *
X *	License is granted by the copyright holder to distribute and use this
X *	code without payment of royalties or the necessity of notification as
X *	long as this notice (all the text under "LEGAL") is included.
X *
X *	Reference: $Id: g4sencod.c 1.2 90/06/09 18:24:10 marking Exp $
X *
X *	This program is offered without any warranty of any kind. It includes
X *	no warranty of merchantability or fitness for any purpose. Testing and
X *	suitability for any use are the sole responsibility of the user.
X * 
X HISTORY
X *	$Log:	g4sencod.c $
X * Revision 1.2  90/06/09  18:24:10  marking
X * clean up comments for release
X * 
X * Revision 1.1  90/05/01  02:00:00  marking
X * Initial revision
X * 
X *
X NOTES
X *
X PORTABILITY
X *	Tested using Microsoft C 5.1. Some memory models may not work due to
X *	the large encoding arrays.
X *
X *	There is a non-portable use of "global" variables in the file g3g4.h,
X *	about which a minority of compilers will justifiably complain. Certain
X *	variables are declared in g3g4.h without extern keywords. Strictly
X *	speaking, they should be declared extern in all but one module, but
X *	that would require complication of g3g4.h. If it gets past your
X *	compiler and linker, you can probably ignore it.
X *
X SEE ALSO
X *
X INFORMATION
X *	Although there is no support offered with this program, the author will
X *	endeavor to correct errors. Updates will also be made available from
X *	time to time.
X *
X *	Contact: Michael P. Marking, Post Office Box 8039, Scottsdale, Arizona
X *	85252-8039 USA. Replies are not guaranteed to be swift. Beginning
X *	July 1990, e-mail may be sent to uunet!ipel!marking.
X *
X *	Also beginning in July 1990, this code will be archived at the
X *	ipel!phoenix BBS in file g3g4.zoo. The 24-hour telephone number
X *	for 300/1200/2400 is (602)274-0462. When logging in, specify user
X *	"public", system "bbs", and password "public".
X *
X *	This code is also available from the C Users Group in volume 317.
X */
X
X#include "g3g4.h"
X
X/* #define TRACE 1 */
X
X/* implementation limits: Due to the sizes of arrays and variables, and not
X   due to any restrictions in the algorithm, the following limits exist:
X     maximum number of pixels per row: 65533
X     maximum number of rows per image: none
X     maximum or minimum k-factor: none
X     maximum number of runs per row: 16382 white, 16382 black
X   To increase (or decrease) these limits, it will be necessary to play with
X   array and variable sizes.  On segmented machines (such as the 8086), a
X   different memory model may be necessary.  The algorithm itself has no
X   limits on image size or complexity, and the stack requirements are in-
X   sensitive to changes in these limits or to image complexity. */
X
X#define EVEN 0
X#define ODD 1
X
Xstatic short a0, a1, a2, b0, b1, b2, length_of_current_run;
Xstatic unsigned char color, current_row, mode;
Xstatic short even_runs [32768], odd_runs [32768];
Xstatic unsigned short reference_index, coding_index;
Xstatic short *reference_line, *coding_line;
Xstatic short column_limit;
X  /* Depending as current_row == EVEN or current_row == ODD, the runs of the
X     current row are represented in even_runs [] or odd_runs [].  The white
X     runs have even subscripts and the black runs have odd subscripts.  The
X     values of the array elements are the offsets of the beginnings of the
X     corresponding runs from the beginning of the row.  As defined by the
X     specification,
X	a0 is the reference or starting changing element on the coding line.
X		It may be considered the "current position".
X	a1 is the next changing element to the right of a0 on the coding line.
X	a2 is the next changing element to the right of a1 on the coding line.
X	b1 is the first changing element on the reference line to the right of
X		a0 and of opposite color to a0.
X	b2 is the next changing element to the right of b1 on the reference
X		line.
X     Furthermore,
X	b0 is the "previous" value of b1. 
X     */
X
Xchar g4j_initialize (short image_width, short image_length)
X{
X  initialize_encode ();
X  color = WHITE;
X  current_row = ODD;
X  coding_line = odd_runs;
X  reference_line = even_runs;
X  coding_index = 0;
X  coding_line [0] = 0;
X  length_of_current_run = 0;
X  column_limit = image_width;
X  reference_line [0] = 0;
X  reference_line [1] = column_limit;
X  reference_line [2] = column_limit;
X  reference_line [3] = column_limit;
X  return (0);
X}
X
Xchar g4j_encode_EOFB ()
X{
X  encode_word (EOL_code, EOL_length);
X  encode_word (EOL_code, EOL_length);
X  return (0);
X}
X
Xchar g4j_encode_new_row ()
X{
X  short last_point;
X  last_point  = coding_line [coding_index] + length_of_current_run;
X  coding_index++;
X  coding_line [coding_index] = last_point;
X  coding_line [coding_index + 1] = last_point;
X  coding_line [coding_index + 2] = last_point;
X  coding_line [coding_index + 3] = last_point;
X  /* encode the current row */
X  #if defined (TRACE)
X    if (trace_flag)
X    {
X      short j = 0, a;
X      printf (" coding_line = < ");
X      while ((a = coding_line [j]) < column_limit)
X      {
X        printf ("%hd@%hd ", (short) (coding_line [j + 1] - a), a);
X        j++;
X      }
X      printf ("> ");
X      j = 0;
X      printf ("\nreference_line = < ");
X      while ((a = reference_line [j]) < column_limit)
X      {
X        printf ("%hd@%hd ", (short) (reference_line [j + 1] - a), a);
X        j++;
X      }
X      printf ("> ");
X    };
X  #endif
X  reference_index = 0;
X  coding_index = 0;
X  a1 = coding_line [0];
X  a2 = coding_line [1];
X  if (a2 == 0 && reference_line [1] == 0)
X    /* if the first (white) run is null as was in previous row */
X  {
X    encode_word (VERTICAL_V0_CODEWORD, VERTICAL_V0_CODELEN);
X    coding_index++;
X    a1 = coding_line [1];
X    a2 = coding_line [2];
X    #if defined (TRACE)
X      if (trace_flag) printf ("V0 ");
X    #endif
X  }
X  while (a1 < column_limit)
X  {
X    short effective_a0;
X    a0 = a1;
X    a1 = a2;
X    a2 = coding_line [coding_index + 2];
X    if (reference_index > 3) reference_index -= 3;
X    else reference_index = 0;
X    if (coding_index) effective_a0 = a0;
X    else effective_a0 = -1;
X    while (effective_a0 >= (b1 = reference_line [reference_index]))
X      reference_index++;
X      /* now the reference index points to the first changing point beyond a0,
X	 but it may or may not be the same color as a0 */
X    if (! ((coding_index ^ reference_index) & 1)) /* if same colors */
X    {
X      reference_index++; /* now different color */
X      b1 = reference_line [reference_index];
X    }
X    b2 = reference_line [reference_index + 1];
X    #if defined (TRACE)
X      if (trace_flag)
X        printf ("\na0=%hd a1=%hd a2=%hd b1=%hd b2=%hd rx=%hd cx=%hd ",
X	  a0, a1, a2, b1, b2, reference_index, coding_index);
X    #endif
X    while (b2 < a1) /* PASS */
X    {
X      #if defined (TRACE)
X	short old_a0 = a0;
X      #endif
X      encode_word (PASS_CODEWORD, PASS_CODELEN);
X      a0 = b2;
X      reference_index += 2;
X      b1 = reference_line [reference_index];
X      b2 = reference_line [reference_index + 1];
X      #if defined (TRACE)
X        if (trace_flag) printf ("PASS k%hd ", (short) (a0 - old_a0));
X      #endif
X    }
X    if (a1 == b1) /* V0 */
X    {
X      encode_word (VERTICAL_V0_CODEWORD, VERTICAL_V0_CODELEN);
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("V0 ");
X      #endif
X    }
X    else if (a1 == b1 + 1) /* VR1 */
X    {
X      encode_word (VERTICAL_VR1_CODEWORD, VERTICAL_VR1_CODELEN);
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("VR1 ");
X      #endif
X    }
X    else if (a1 == b1 + 2) /* VR2 */
X    {
X      encode_word (VERTICAL_VR2_CODEWORD, VERTICAL_VR2_CODELEN);
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("VR2 ");
X      #endif
X    }
X    else if (a1 == b1 + 3) /* VR3 */
X    {
X      encode_word (VERTICAL_VR3_CODEWORD, VERTICAL_VR3_CODELEN);
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("VR3 ");
X      #endif
X    }
X    else if (a1 == b1 - 1) /* VL1 */
X    {
X      encode_word (VERTICAL_VL1_CODEWORD, VERTICAL_VL1_CODELEN);
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("VL1 ");
X      #endif
X    }
X    else if (a1 == b1 - 2) /* VL2 */
X    {
X      encode_word (VERTICAL_VL2_CODEWORD, VERTICAL_VL2_CODELEN);
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("VL2 ");
X      #endif
X    }
X    else if (a1 == b1 - 3) /* VL3 */
X    {
X      encode_word (VERTICAL_VL3_CODEWORD, VERTICAL_VL3_CODELEN);
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("VL3 ");
X      #endif
X    }
X    else /* HORIZONTAL */
X    {
X      short first_run, second_run;
X      encode_word (HORIZONTAL_CODEWORD, HORIZONTAL_CODELEN);
X      first_run = a1 - a0;
X      second_run = a2 - a1;
X      if (coding_index & 1) /* if BLACK, WHITE */
X      {
X	g3j_encode_black (first_run);
X	g3j_encode_white (second_run);
X	#if defined (TRACE)
X	  if (trace_flag) printf ("B%hd W%hd ", first_run, second_run);
X	#endif
X      }
X      else /* WHITE, BLACK */
X      {
X	g3j_encode_white (first_run);
X	g3j_encode_black (second_run);
X	#if defined (TRACE)
X	  if (trace_flag) printf ("W%hd B%hd ", first_run, second_run);
X	#endif
X      }
X      coding_index++;
X      a0 = a1;
X      a1 = a2;
X      a2 = coding_line [coding_index + 2];
X      coding_index++;
X      #if defined (TRACE)
X        if (trace_flag) printf ("HORIZ ");
X      #endif
X    }
X  }
X  /* now swap rows */
X  if (current_row == EVEN)
X  {
X    current_row = ODD;
X    coding_line = odd_runs;
X    reference_line = even_runs;
X  }
X  else /* current_row == ODD */
X  {
X    current_row = EVEN;
X    coding_line = even_runs;
X    reference_line = odd_runs;
X  }
X  coding_index = 0;
X  coding_line [coding_index] = 0;
X  length_of_current_run = 0;
X  return (0);
X}
X
Xchar g4j_encode_black (short runlength)
X{
X  if (!(coding_index & 1)) /* if even number, is white */
X  {
X    coding_index++; /* move on to black */
X    coding_line [coding_index]
X      = coding_line [coding_index - 1] + length_of_current_run;
X    length_of_current_run = 0;
X  }
X  length_of_current_run += runlength;
X  return (0);
X}
X
Xchar g4j_encode_white (short runlength)
X{
X  if (coding_index & 1) /* if odd number, is black */
X  {
X    coding_index++; /* move on to white */
X    coding_line [coding_index]
X      = coding_line [coding_index - 1] + length_of_current_run;
X    length_of_current_run = 0;
X  }
X  length_of_current_run += runlength;
X  return (0);
X}
X
X/*	end $RCSfile: g4sencod.c $ */
SHAR_EOF
chmod 0644 g4sencod.c || echo "restore of g4sencod.c fails"
sed 's/^X//' << 'SHAR_EOF' > g4tdecod.c &&
X/*	$Id: g4tdecod.c 1.2 90/06/09 18:24:25 marking Exp $
X *
X NAME
X *	g4tdecod.c -- decode group 4 data using tables
X *
X TYPE
X *	C procedures
X *
X SYNOPSIS
X *	char	g4i_initialize (short image_width, short image_length);
X *	char	g4i_decode (void);
X *
X DESCRIPTION
X *	In order to acquire data from the image and to return run lengths and
X *	new line information, these routines invoke procedures provided by the
X *	caller. These caller-provided procedures are invoked throught pointers
X *	which have been stuffed by the caller with the procedure addresses.
X *	To acquire a new data byte, g4i_decode () calls (*p_g41_next_byte) ().
X *	To report the decoding of a black or white run, the routines
X *	(*p_decode_black) () or (*p_decode_white) () are called.
X *
X RETURNS
X *	Initialization always returns zero.
X *
X *	For decoding,
X *		0	end of image reached
X *		-1	on error (bad data)
X *	The decode loop will be prematurely terminated if decode_return is
X *	set to not zero, and the value of decode_return will be returned.
X *	No code here does this, but it might be useful under certain
X *	circumstances.
X *
X LEGAL
X *	Copyright 1989, 1990 Michael P. Marking, Post Office Box 8039,
X *	Scottsdale, Arizona 85252-8039. All rights reserved.
X *
X *	License is granted by the copyright holder to distribute and use this
X *	code without payment of royalties or the necessity of notification as
X *	long as this notice (all the text under "LEGAL") is included.
X *
X *	Reference: $Id: g4tdecod.c 1.2 90/06/09 18:24:25 marking Exp $
X *
X *	This program is offered without any warranty of any kind. It includes
X *	no warranty of merchantability or fitness for any purpose. Testing and
X *	suitability for any use are the sole responsibility of the user.
X * 
X HISTORY
X *	$Log:	g4tdecod.c $
X * Revision 1.2  90/06/09  18:24:25  marking
X * clean up comments for release
X * 
X * Revision 1.1  89/06/30  17:00:00  marking
X * Initial revision
X * 
X *
X NOTES
X *
X PORTABILITY
X *	Tested using Microsoft C 5.1. Some memory models may not work due to
X *	the large decoding arrays.
X *
X *	There is a non-portable use of "global" variables in the file g3g4.h,
X *	about which a minority of compilers will justifiably complain. Certain
X *	variables are declared in g3g4.h without extern keywords. Strictly
X *	speaking, they should be declared extern in all but one module, but
X *	that would require complication of g3g4.h. If it gets past your
X *	compiler and linker, you can probably ignore it.
X *
X SEE ALSO
X *	g3tdecod.c -- decode group 3 image using tables
X *	builddec.c -- build image decoding tables
X *
X INFORMATION
X *	Although there is no support offered with this program, the author will
X *	endeavor to correct errors. Updates will also be made available from
X *	time to time.
X *
X *	Contact: Michael P. Marking, Post Office Box 8039, Scottsdale, Arizona
X *	85252-8039 USA. Replies are not guaranteed to be swift. Beginning
X *	July 1990, e-mail may be sent to uunet!ipel!marking.
X *
X *	Also beginning in July 1990, this code will be archived at the
X *	ipel!phoenix BBS in file g3g4.zoo. The 24-hour telephone number
X *	for 300/1200/2400 is (602)274-0462. When logging in, specify user
X *	"public", system "bbs", and password "public".
X *
X *	This code is also available from the C Users Group in volume 317.
X */
X
X#include "g3g4.h"
X
X/* #define TRACE 1 */
X#define TRACE_BEGIN 0
X#define TRACE_END 30000
X
X/* implementation limits: Due to the sizes of arrays and variables, and not
X   due to any restrictions in the algorithm, the following limits exist:
X     maximum number of pixels per row: 65533
X     maximum number of rows per image: none
X     maximum or minimum k-factor: none
X     maximum number of runs per row: 16382 white, 16382 black
X   To increase (or decrease) these limits, it will be necessary to play with
X   array and variable sizes.  On segmented machines (such as the 8086), a
X   different memory model may be necessary.  The algorithm itself has no
X   limits on image size or complexity, and the stack requirements are in-
X   sensitive to changes in these limits or to image complexity. */
X
X#define EVEN 0
X#define ODD 1
X
Xstatic short a0, a1, a2, b0, b1, b2, bit_number, code_byte;
Xstatic unsigned char color, current_row, mode, next_state;
Xstatic unsigned short even_runs [32768], odd_runs [32768];
Xstatic unsigned short even_index, odd_index;
Xstatic short column_limit;
Xstatic short row_number = 0;
X  /* Depending as current_row == EVEN or current_row == ODD, the runs of the
X     current row are represented in even_runs [] or odd_runs [].  The white
X     runs have even subscripts and the black runs have odd subscripts.  The
X     values of the array elements are the offsets of the beginnings of the
X     corresponding runs from the beginning of the row.  As defined by the
X     specification,
X	a0 is the reference or starting changing element on the coding line.
X		It may be considered the "current position".
X	a1 is the next changing element to the right of a0 on the coding line.
X	a2 is the next changing element to the right of a1 on the coding line.
X	b1 is the first changing element on the reference line to the right of
X		a0 and of opposite color to a0.
X	b2 is the next changing element to the right of b1 on the reference
X		line.
X     Furthermore,
X	b0 is the "previous" value of b1. 
X     Depending as current_row == EVEN or == ODD, even_index or odd_index is
X     the subscript of the entry in even_runs [] or odd_runs [] corresponding
X     to the run containing the current value of a0, and its counterpart cor-
X     responds to the run containing b1. */
X
Xextern unsigned char huge null_mode [] [256];
X  /* One of the entries PASS_MODE, HORIZONTAL_MODE, etc, or zero.  If the entry
X     is zero, then the bit string is indigestible and null_mode_next_state [][]
X     is consulted to decode the subsequent byte.  The row number (first sub-
X     script) corresponds to the assumption about the state of the machine after
X     decoding the previous codeword.  If < 8, then it refers to the starting
X     bit number for this codeword.  If > 7, it implies a bit string to be pre-
X     fixed to the first bit of the current byte.  The column number (second
X     subscript) refers to the value of the current byte. */
X
Xextern unsigned char huge null_mode_next_state [] [256];
Xextern unsigned char huge horiz_mode [] [256];
Xextern unsigned char huge horiz_mode_next_state [] [256];
X
Xstatic void new_row (void);
Xstatic short decode_white_run (void);
Xstatic short decode_black_run (void);
X
Xstatic char decode_return;
X
X/* g4i_decode () successively invokes (*p_decode_next_byte) () for each byte of the
X   encoded image, and calls (*p_decode_white) () or (*p_decode_black) () as
X   required to return the image contents on a run-by-run basis. */
Xchar g4i_decode ()
X{
X  /* At the beginning of this routine, we are in the NULL mode, which is to
X     to say that no codewords are currently understood or digested.  The
X     variable bit_number has been initialized to zero, to indicate that the
X     next (first) codeword is to begin with bit zero of the next code byte.
X     This betrays an assumption that all images begin on byte boundaries, a
X     condition that can be changed by arranging for bit_number to be set
X     otherwise by g4i_initialize () or elsewhere. */
X  while (!decode_return)
X  {
X    /* No codewords have been digested, so no mode is currently understood.
X       It is possible, however, that bits have been left over from the last
X       code byte, and that these must be conceptually prefixed to the next
X       bits at the beginning of the next code byte to establish which code
X       word is next.  The decision is made based on bit_number, which is
X       zero if the codeword begins on a byte boundary; 1, 2, ... 7 if the
X       codeword begins with bit 1, 2, ... 7; or > 7 if the codeword begins
X       with bit zero but is assumed to have a non-null bits string prefix.
X       In any case, the bit_number corresponds to a row in the decoding
X       tables. */
X    if (bit_number == 0 || bit_number > 7) /* the code word will begin on
X      the first bit of the next code byte, possibly with a bit string
X      implicitly prefixed */
X    {
X      code_byte = (*p_decode_next_byte) (); /* invoke a user-supplied routine
X        to provide the next byte of the encoded image */
X      if (code_byte < 0) /* implying end-of-file or some error in
X        reading the next code byte */
X        return (ERROR_NEXT_BYTE);
X    }
X    /* else 0 < bit_number < 8, implying that the next code word begins within
X      the current code byte; that is, a new byte need not be fetched */
X    mode = null_mode [bit_number] [code_byte];
X    next_state = null_mode_next_state [bit_number] [code_byte];
X      /* The above two index operations involve muliplication (by the compiler)
X         of the first subscript by 256, a procedure obviously a candidate for
X	 optimization in many architectures.  It may be worthwhile to hand-code
X	 this calculation, since this is a fairly tight loop.  Check also that
X	 the compiler does the calculation but once and saves the result in a
X	 temporary, since the two arrays are of identical size. */
X    if (mode == NULL_MODE) /* the codeword (or partial codeword) is
X      indigestible */
X    {
X      bit_number = next_state; /* to be continued... */
X    }
X    else
X    {
X      if (current_row == EVEN)
X      {
X	b0 = b1;
X	b1 = odd_runs [odd_index];
X	if ((b1 <= a0) && a0)
X	{
X	  odd_index += 2;
X	  b0 = odd_runs [odd_index - 1];
X	  b1 = odd_runs [odd_index];
X	}
X	b2 = odd_runs [odd_index + 1];
X      }
X      else /* current_row == ODD */
X      {
X	b0 = b1;
X	b1 = even_runs [even_index];
X	if ((b1 <= a0) && a0)
X	{
X	  even_index += 2;
X	  b0 = even_runs [even_index - 1];
X	  b1 = even_runs [even_index];
X	}
X	b2 = even_runs [even_index + 1];
X      }
X      #if defined (TRACE)
X	if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X	{
X	  if (current_row == EVEN)
X	  {
X	    printf ("\n ref_index=%hd b1=%hd b2=%hd a0=%hd curr[%hd]=%hd "
X	      "color=%hd ",
X	      odd_index, b1, b2, a0, even_index, even_runs [even_index],
X	      (short) color);
X	  }
X	  else /* current_row == ODD */
X	  {
X	    printf ("\n ref_index=%hd b1=%hd b2=%hd a0=%hd curr[%hd]=%hd "
X	      "color=%hd ",
X	      even_index, b1, b2, a0, odd_index, odd_runs [odd_index],
X	      (short) color);
X	  }
X	}
X      #endif
X      switch (mode)
X      {
X        case PASS_MODE: /* skip (pass) two color changes on the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" P ");
X	  #endif
X          if (color == WHITE) (*p_decode_white) ((short) (b2 - a0));
X          else /* color == BLACK */ (*p_decode_black) ((short) (b2 - a0));
X	  a0 = b2;
X	  if (current_row == EVEN)
X	  {
X	    odd_index += 2;
X	    b1 = odd_runs [odd_index];
X	  }
X	  else /* current_row == ODD */
X	  {
X	    even_index += 2;
X	    b1 = even_runs [even_index];
X	  }
X          bit_number = next_state;
X          break;
X        case HORIZONTAL_MODE: /* revert to 1-dimensional modified Huffman
X          encoding for a pair of runs */
X          bit_number = next_state;
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" H ");
X          #endif
X          if (color == WHITE)
X          {
X	    short black_runlength, white_runlength;
X            white_runlength = decode_white_run ();
X            (*p_decode_white) ((short) white_runlength);
X	    a1 = (a0 += white_runlength);
X            black_runlength = decode_black_run ();
X            (*p_decode_black) ((short) black_runlength);
X	    a2 = (a0 += black_runlength);
X          }
X          else /* color == BLACK */
X          {
X	    short black_runlength, white_runlength;
X	    black_runlength = decode_black_run ();
X	    (*p_decode_black) ((short) black_runlength);
X	    a1 = (a0 += black_runlength);
X	    white_runlength = decode_white_run ();
X	    (*p_decode_white) ((short) white_runlength);
X	    a2 = (a0 += white_runlength);
X          }
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a1;
X	    even_runs [++even_index] = a2;
X	    while (a0 > odd_runs [odd_index]) odd_index += 2;
X	    b1 = odd_runs [odd_index];
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a1;
X	    odd_runs [++odd_index] = a2;
X	    while (a0 > even_runs [even_index]) even_index += 2;
X	    b1 = even_runs [even_index];
X          }
X          break;
X        case VERTICAL_V0_MODE: /* the next color change begins at the same
X          location as in the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" V0 ");
X	  #endif
X	  if (color == WHITE)
X	  {
X	    (*p_decode_white) ((short) (b1 - a0));
X	    color = BLACK;
X	  }
X	  else /* color == BLACK */
X	  {
X	    (*p_decode_black) ((short) (b1 - a0));
X	    color = WHITE;
X	  }
X	  a0 = b1; 
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a0;
X	    odd_index++;
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a0;
X	    even_index++;
X          }
X          bit_number = next_state;
X          break;
X        case VERTICAL_VR1_MODE: /* the next color change begins one pixel to the
X          right of its location on the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" VR1 ");
X	  #endif
X	  if (color == WHITE)
X	  {
X	    (*p_decode_white) ((short) (b1 - a0 + 1));
X	    color = BLACK;
X	  }
X	  else /* color == BLACK */
X	  {
X	    (*p_decode_black) ((short) (b1 - a0 + 1));
X	    color = WHITE;
X	  }
X	  a0 = b1 + 1; 
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a0;
X	    odd_index++;
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a0;
X	    even_index++;
X          }
X          bit_number = next_state;
X          break;
X        case VERTICAL_VR2_MODE: /* the next color change begins two pixels to
X          the right of its location on the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" VR2 ");
X	  #endif
X	  if (color == WHITE)
X	  {
X	    (*p_decode_white) ((short) (b1 - a0 + 2));
X	    color = BLACK;
X	  }
X	  else /* color == BLACK */
X	  {
X	    (*p_decode_black) ((short) (b1 - a0 + 2));
X	    color = WHITE;
X	  }
X	  a0 = b1 + 2; 
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a0;
X	    odd_index++;
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a0;
X	    even_index++;
X          }
X          bit_number = next_state;
X          break;
X        case VERTICAL_VR3_MODE: /* the next color change begins three pixels to
X          the right of its location on the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" VR3 ");
X	  #endif
X	  if (color == WHITE)
X	  {
X	    (*p_decode_white) ((short) (b1 - a0 + 3));
X	    color = BLACK;
X	  }
X	  else /* color == BLACK */
X	  {
X	    (*p_decode_black) ((short) (b1 - a0 + 3));
X	    color = WHITE;
X	  }
X	  a0 = b1 + 3; 
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a0;
X	    odd_index++;
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a0;
X	    even_index++;
X          }
X          bit_number = next_state;
X          break;
X        case VERTICAL_VL1_MODE: /* the next color change begins one pixel to the
X          left of its location on the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" VL1 ");
X	  #endif
X	  if (color == WHITE)
X	  {
X	    (*p_decode_white) ((short) (b1 - a0 - 1));
X	    color = BLACK;
X	  }
X	  else /* color == BLACK */
X	  {
X	    (*p_decode_black) ((short) (b1 - a0 - 1));
X	    color = WHITE;
X	  }
X	  a0 = b1 - 1; 
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a0;
X	    odd_index++;
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a0;
X	    even_index++;
X          }
X          bit_number = next_state;
X          break;
X        case VERTICAL_VL2_MODE: /* the next color change begins two pixels to
X          the left of its location on the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" VL2 ");
X	  #endif
X	  if (color == WHITE)
X	  {
X	    (*p_decode_white) ((short) (b1 - a0 - 2));
X	    color = BLACK;
X	  }
X	  else /* color == BLACK */
X	  {
X	    (*p_decode_black) ((short) (b1 - a0 - 2));
X	    color = WHITE;
X	  }
X	  a0 = b1 - 2; 
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a0;
X	    if (a0 < b0) odd_index--;
X	    else odd_index++;
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a0;
X	    if (a0 < b0) even_index--;
X	    else even_index++;
X          }
X          bit_number = next_state;
X          break;
X        case VERTICAL_VL3_MODE: /* the next color change begins three pixels to
X          the left of its location on the previous row */
X	  #if defined (TRACE)
X            if (row_number >= TRACE_BEGIN && row_number <= TRACE_END)
X              printf (" VL3 ");
X	  #endif
X	  if (color == WHITE)
X	  {
X	    (*p_decode_white) ((short) (b1 - a0 - 3));
X	    color = BLACK;
X	  }
X	  else /* color == BLACK */
X	  {
X	    (*p_decode_black) ((short) (b1 - a0 - 3));
X	    color = WHITE;
X	  }
X	  a0 = b1 - 3; 
X          if (current_row == EVEN)
X          {
X	    even_runs [++even_index] = a0;
X	    if (a0 < b0) odd_index--;
X	    else odd_index++;
X          }
X          else /* current_row == ODD */
X          {
X	    odd_runs [++odd_index] = a0;
X	    if (a0 < b0) even_index--;
X	    else even_index++;
X          }
X          bit_number = next_state;
X          break;
X        case EXT_MODE_UNCOMPRESSED: /* enter extension type 7 ("111"), an
X          uncompressed encoding scheme */
X          return (ERROR_UNSUPPORTED_EXTENSION);
X          break;
X        case ERROR_MODE: /* The bit pattern found corresponds to an unknown or
X          invalid codeword.  This MAY be one of the seven possible extensions
X          not defined by the specification. */
X          return (ERROR_INVALID_CODEWORD);
X          break;
X        case ERROR_MODE_1: /* assumed in this implementation to be equivalent
X          to EOFB (end-of-facsimile-block) */
X          return (RETURN_OK);
X          break;
X        default: /* we should never get here; if we do, the tables are bad */
X          return (ERROR_PROGRAM_LOGIC);
X          break;
X      }
X    }
X    if (a0 >= column_limit) new_row ();
X  }
X  return (decode_return);
X}
X
X/* g4i_initialize () is called to set up to decode a new image.  All of the
X   static data (flags, etc) for g4i_decode () are initialized, allowing the
X   decoding of multiple images in a run as long as g4i_initialize () is
X   called before each one. */
Xchar g4i_initialize (short image_width, short image_length)
X{
X  color = WHITE;
X  bit_number= 0;
X  current_row = ODD;
X  even_runs [0] = 0;
X  even_runs [1] = image_width; /* initial b1 */
X  even_runs [2] = image_width; /* initial b2 */
X  odd_runs [0] = 0;
X  a0 = 0;
X  even_index = 1; odd_index = 0;
X  column_limit = image_width;
X  row_number = 0;
X  b1 = -1;
X  decode_return = 0;
X  return (0);
X}
X
Xstatic void new_row ()
X{
X  (*p_decode_new_row) ();
X  color = WHITE;
X  if (current_row == ODD)
X  {
X    current_row = EVEN;
X    odd_runs [++odd_index] = a0;
X    odd_runs [++odd_index] = a0;
X    odd_index = 1;
X    even_index = 0;
X  }
X  else /* current_row == EVEN */
X  {
X    current_row = ODD;
X    even_runs [++even_index] = a0;
X    even_runs [++even_index] = a0;
X    even_index = 1;
X    odd_index = 0;
X  }
X  a0 = 0;
X  b1 = -1;
X  #if defined (TRACE)
X    row_number++;
X  #endif
X}
X
Xstatic short run_length_table [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
X  13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
X  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
X  51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 128, 192, 256, 320,
X  384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 1088, 1152, 1216,
X  1280, 1344, 1408, 1472, 1536, 1600, 1664, 1728, 1792, 1856, 1920, 1984,
X  2048, 2112, 2176, 2240, 2304, 2368, 2432, 2496, 2560};
X
Xstatic short decode_black_run ()
X{
X  short runlength, accum_runlength = 0;
X  next_state = (unsigned char) (bit_number + 8);
X  for (;;) /* exit with "return" */
X  {
X    if (!bit_number) code_byte = (*p_decode_next_byte) ();
X	 /* this will fetch a new byte
X	    if the previous codeword ended on a byte boundary */
X    mode = horiz_mode [next_state] [code_byte];
X    next_state = horiz_mode_next_state [next_state] [code_byte];
X    if (mode) /* if digestible */
X    {
X      bit_number = next_state;
X      runlength = run_length_table [mode - 106];
X      accum_runlength += runlength;
X      if (runlength < 64) return (accum_runlength);
X      next_state += 8;
X    }
X    else bit_number = 0;
X  }
X}
X
Xstatic short decode_white_run ()
X{
X  short runlength, accum_runlength = 0;
X  next_state = (unsigned char) bit_number;
X  for (;;) /* exit with "return" */
X  {
X    if (!bit_number) code_byte = (*p_decode_next_byte) ();
X	 /* this will fetch a new byte
X	    if the previous codeword ended on a byte boundary */
X    mode = horiz_mode [next_state] [code_byte];
X    next_state = horiz_mode_next_state [next_state] [code_byte];
X    if (mode) /* if digestible */
X    {
X      bit_number = next_state;
X      runlength = run_length_table [mode - 2];
X      accum_runlength += runlength;
X      if (runlength < 64) return (accum_runlength);
X    }
X    else bit_number = 0;
X  }
X}
X
X/*	end $RCSfile: g4tdecod.c $ */
SHAR_EOF
chmod 0644 g4tdecod.c || echo "restore of g4tdecod.c fails"
sed 's/^X//' << 'SHAR_EOF' > gnencode.c &&
X/*	$Id: gnencode.c 1.2 90/06/09 18:24:51 marking Exp $
X *
X NAME
X *	gnencode.c -- routines for bit and byte encoding
X *
X TYPE
X *	C procedures
X *
X SYNOPSIS
X *	void initialize_encode ();
X *	void encode_word (unsigned short codeword, short length);
X *
X DESCRIPTION
X *	Support routines used in encoding group 3 and group 4 images.
X *
X RETURNS
X *
X LEGAL
X *	Copyright 1989, 1990 Michael P. Marking, Post Office Box 8039,
X *	Scottsdale, Arizona 85252-8039. All rights reserved.
X *
X *	License is granted by the copyright holder to distribute and use this
X *	code without payment of royalties or the necessity of notification as
X *	long as this notice (all the text under "LEGAL") is included.
X *
X *	Reference: $Id: gnencode.c 1.2 90/06/09 18:24:51 marking Exp $
X *
X *	This program is offered without any warranty of any kind. It includes
X *	no warranty of merchantability or fitness for any purpose. Testing and
X *	suitability for any use are the sole responsibility of the user.
X * 
X HISTORY
X *	$Log:	gnencode.c $
X * Revision 1.2  90/06/09  18:24:51  marking
X * clean up comments for release
X * 
X * Revision 1.1  89/06/30  17:00:00  marking
X * Initial revision
X * 
X *
X NOTES
X *	1.	There are two versions of encode_word (). Refer to the remark
X *		below and comment-out one or the other.
X *
X PORTABILITY
X *	Tested using Microsoft C 5.1. Some memory models may not work due to
X *	the large encoding arrays.
X *
X *	There is a non-portable use of "global" variables in the file g3g4.h,
X *	about which a minority of compilers will justifiably complain. Certain
X *	variables are declared in g3g4.h without extern keywords. Strictly
X *	speaking, they should be declared extern in all but one module, but
X *	that would require complication of g3g4.h. If it gets past your
X *	compiler and linker, you can probably ignore it.
X *
X SEE ALSO
X *	g3sencod.c, g4sencod.c
X *
X INFORMATION
X *	Although there is no support offered with this program, the author will
X *	endeavor to correct errors. Updates will also be made available from
X *	time to time.
X *
X *	Contact: Michael P. Marking, Post Office Box 8039, Scottsdale, Arizona
X *	85252-8039 USA. Replies are not guaranteed to be swift. Beginning
X *	July 1990, e-mail may be sent to uunet!ipel!marking.
X *
X *	Also beginning in July 1990, this code will be archived at the
X *	ipel!phoenix BBS in file g3g4.zoo. The 24-hour telephone number
X *	for 300/1200/2400 is (602)274-0462. When logging in, specify user
X *	"public", system "bbs", and password "public".
X *
X *	This code is also available from the C Users Group in volume 317.
X */
X
X#include "g3g4.h"
X
X/*
X *	initialize the bit-encoding routines
X */
X
Xvoid initialize_encode ()
X{
X  static unsigned char msb_mask [8] =
X    { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
X  static unsigned char lsb_mask [8] =
X    { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
X  static unsigned char msb_head_mask [8] =
X    { 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
X  static unsigned char lsb_head_mask [8] =
X    { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
X  static unsigned char msb_tail_mask [8] =
X    { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 };
X  static unsigned char lsb_tail_mask [8] =
X    { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 };
X  output_fill_order = MSB_FIRST;	/* some implementations might
X						want to change this */
X  encode_buffer = 0;
X  encode_position = 0;
X  if (output_fill_order == MSB_FIRST)
X  {
X    encode_mask = msb_mask;
X    encode_head_mask = msb_head_mask;
X    encode_tail_mask = msb_tail_mask;
X  }
X  else /* output_fill_order == LSB_FIRST */
X  {
X    encode_mask = lsb_mask;
X    encode_head_mask = lsb_head_mask;
X    encode_tail_mask = lsb_tail_mask;
X  }
X  pending_black = 0;
X  pending_white = 0;
X}
X
X/*
X *	append a codeword of the specified length in bits to the end
X *	of the current output file
X */
X
Xvoid encode_word (unsigned short codeword, short length)
X{
X/*********
X	There are two versions of this procedure.  One or the other
X	is to be commented out.  The first is somewhat faster,
X	especially on a 386 because it makes use of the barrel
X	shifter.  Its limitation is the assumption that the output
X	file is filled most-significant-bit first.  The second is
X	a little slower, but doesn't make the assumption.
X********/
X
X/* the faster routine, with the assumption . . . */
X  short first_count, second_count, remaining, new_encode_position;
X  static char limit_8 [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 8,
X	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
X  if (length)
X  {
X    new_encode_position = limit_8 [encode_position + length];
X    first_count = new_encode_position - encode_position;
X    encode_buffer |= (codeword >> (encode_position + 8));
X    encode_position = new_encode_position;
X    remaining = length - first_count;
X    if (encode_position > 7)
X    {
X      (*p_encode_next_byte) (encode_buffer);
X      if (remaining)
X      {
X	encode_position = limit_8 [remaining];
X	second_count = encode_position;
X	remaining -= second_count;
X	encode_buffer = ((unsigned char) (codeword >> (8 - first_count)))
X		& encode_head_mask [second_count - 1];
X	if (encode_position > 7)
X	{
X	  (*p_encode_next_byte) (encode_buffer);
X	  if (remaining)
X	  {
X	    encode_buffer
X	      = ((unsigned char) (codeword << first_count))
X		& encode_head_mask [remaining - 1];
X	    encode_position = remaining;
X	  }
X	  else { encode_buffer = 0; encode_position = 0; }
X	}
X      }
X      else { encode_buffer = 0; encode_position = 0; }
X    }
X  }
X
X/* the slower routine, with no assumption about output file bit order . . . */
X/*
X  static short read_mask [16] = {0x8000, 0x4000, 0x2000, 0x1000, 0x0800,
X    0x0400, 0x0200, 0x0100, 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004,
X    0x0002, 0x0001};
X  short j1;
X  for (j1 = 0; j1 < length; j1 ++)
X  {
X    if (read_mask [j1] & codeword)
X      encode_buffer |= encode_mask [encode_position];
X    encode_position++;
X    if (encode_position > 7)
X    {
X      (*p_encode_next_byte) (encode_buffer);
X      encode_position = 0;
X      encode_buffer = 0;
X    }
X  }
X*/
X}
X/*	end $RCSfile: gnencode.c $ */
SHAR_EOF
chmod 0644 gnencode.c || echo "restore of gnencode.c fails"
sed 's/^X//' << 'SHAR_EOF' > read.me &&
X$Id: read.me 1.2 90/06/09 18:28:33 marking Exp $
X
XFiles
X
X	builddec.c	build group 3 and group 4 decoding tables
X	g3g4.h		definitions for groups 3 and 4 decoding
X	g3sdecod.c	routines to decode group 3 images using if statements
X	g3sencod.c	routines to encode group 3 images using if statements
X	g3tdecod.c	routines using tables to decode group 3 images
X	g4sencod.c	routines to encode group 4 images using if statements
X	g4sdecod.c	routines to decode group 4 images using if statements
X	g4tdecod.c	routines using tables to decode group 4 images
X	gnencode.c	utilities for the encode routines
X	read.me		this file
X
XRemarks
X
X	This is the first release of the g3g4 utilities. Work in progress
X	to enhance the capabilities of the toolkit includes table encoding
X	of group 3 and group 4 images, and some optimization.
X
X	A tiff toolkit is also being prepared. Although the routines in this
X	collection can be used with g3 and g4 images in tiff files, they
X	have no provision for handling the structure of the files themselves.
X	The future tiff toolkit will add those features.
X
X	Note that the calling sequence of the user-provided support routines
X	differs slightly from that indicated in the C Users Journal article.
X	The versions here make indirect calls using pointers, so that at
X	one time one input routine might be used, and at other times another.
X	This allows considerably more flexible usage, since the source of
X	the file can be changed without relinking. The names have been
X	changed a little to prevent inadvertent use of the old method.
X
XLegal
X	Copyright 1989, 1990 Michael P. Marking, Post Office Box 8039,
X	Scottsdale, Arizona 85252-8039. All rights reserved.
X
X	License is granted by the copyright holder to distribute and use this
X	code without payment of royalties or the necessity of notification as
X	long as this notice (all the text under "LEGAL") is included.
X
X	Reference: $Id: read.me 1.2 90/06/09 18:28:33 marking Exp $
X
X	This program is offered without any warranty of any kind. It includes
X	no warranty of merchantability or fitness for any purpose. Testing and
X	suitability for any use are the sole responsibility of the user.
X
XInformation
X	Although there is no support offered with these programs, the author
X	will endeavor to correct errors. Updates will also be made available
X	from time to time.
X
X	Contact: Michael P. Marking, Post Office Box 8039, Scottsdale, Arizona
X	85252-8039 USA. Replies are not guaranteed to be swift. Beginning
X	July 1990, e-mail may be sent to uunet!ipel!marking.
X
X	Also beginning in July 1990, this code will be archived at the
X	ipel!phoenix BBS in file g3g4.zoo. The 24-hour telephone number
X	for 300/1200/2400 is (602)274-0462. When logging in, specify user
X	"public", system "bbs", and password "public".
X
X	This code is also available from the C Users Group in volume 317.
X
XHistory
X
X$Log:	read.me $
X\" Revision 1.2  90/06/09  18:28:33  marking
X\" update for release
X\" 
X\" Revision 1.1  89/06/09  17:56:42  marking
X\" Initial revision
X\" 
X
X-- end read.me
SHAR_EOF
chmod 0644 read.me || echo "restore of read.me fails"
sed 's/^X//' << 'SHAR_EOF' > submit.dsk &&
XThe C Users' Group welcomes submissions for inclusion in the
XC public domain library. Please sign and return the following information
Xwith your submission. Thank you.
X
X
XAUTHOR'S RELEASE
X
XFor CUG Library Contribution
X	
XWe can not distribute your submission without this release.
XPlease fill out, sign and return this form.  Don't hesitate to
Xcall if you have questions.
X
XNAME______________________________DATE________________________
X
XADDRESS_______________________________________________________
X
XCITY___________________________STATE_______ZIP________________
X
XCOUNTRY_______________________________________________________
X
XPHONE__________________________AFFILIATION____________________
X
XDESCRIPTION OF SUBMITTED MATERIALS:
X
X
X
X
X
X
X
X
X
XThe submitted materials are:
X
X____Of unknown origin or status.
X
X____(Someone else's Public Domain or Shareware)
X    To the best of my knowledge currently in the public domain
X    or authorized for distribution as shareware.
X
X____(My Public Domain)
X    Written by me and hereby placed into the public domain.
X    Permission is hereby granted to The C Users' Group to distribute
X    the submitted materials freely for non-commercial personal use.
X
X____(My Shareware)
X    Written by me and protected by certain copyright restrictions
X    clearly specified in the files constituting the submission.
X    Permission is hereby granted to The C Users' Group to
X    distribute the submitted materials, without royalty or
X    other compensation, and to charge their normal distribution
X    fee for such distribution, provided that my copyright restrictions
X    are included unchanged in each copy distributed. 
X
XSigned:_____________________________________Date:____________
X
X
XSUBMISSION GUIDELINES
X
XPlease avoid sub-directories, squeezed files, library files or other
Xcompacted formats. CUG appreciates and prefers submissions with
Xcataloging headers on all text files (See the sample below and our directory
Xfor the additional information.)
X
X
XSAMPLE HEADER
X/*
XHEADER:		;
XTITLE:		Diskette sector editor;
XVERSION:	1.4;
X
XDESCRIPTION:	"Lets you view, edit and write back a diskette sector.
X
X		It needs a 24*80 cursor-addressable terminal, and requires
X		your custom CLRSCREEN() and GOTOXY() functions.  The
X		definitions of these functions appear early in SE.C.
X
X		Compiling requires SENTER.C, included on the diskette.
X		Also included are SE.DOC and SE.SUB.";
X
XKEYWORDS:	Disk, utility, editor, sector;
XSYSTEM:		CP/M-80, V2.2;
XFILENAME:	SE.C;
XWARNINGS:	"Requires Version 2.x of CP/M.
X		SE is not designed to work with systems using the DEBLOCK
X		routine in the BIOS to handle physical sectors larger than
X		128 bytes, so if you have such a system, and want to use SE,
X		you must modify the routines in SE which write back the edited
X		sector.  The BitMap command is not implemented.";
X
XSEE-ALSO:	SE.DOC, SENTER.C;
XAUTHORS:	Jan Larsson;
XCOMPILERS:	BDS C, v1.43 and 1.5a;
X*/
X
XThe C Users' Group (CUG) collects, maintains and distributes
Xpublic domain C source code, publishes a magazine, The C Users' Journal
Xand serves as a resource for C users. Several vendors have named
XCUG as the official users group for their implementation of C.
XFor membership and subscription information contact
X
X	The C Users' Group
X	2601 Iowa
X	Lawrence, KS 66046
X	(913) 841-1631
X
SHAR_EOF
chmod 0644 submit.dsk || echo "restore of submit.dsk fails"
rm -f s2_seq_.tmp
echo "You have unpacked the last part"
exit 0