Net2/usr/src/contrib/isode/others/quipu/photo/decode.c

Compare this file to the similar file:
Show the results in this format:

/* decode.c - the generic decoder */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/others/quipu/photo/RCS/decode.c,v 7.6 91/02/22 09:29:08 mrose Interim $";
#endif

/* 
 * $Header: /f/osi/others/quipu/photo/RCS/decode.c,v 7.6 91/02/22 09:29:08 mrose Interim $
 *
 *
 * $Log:	decode.c,v $
 * Revision 7.6  91/02/22  09:29:08  mrose
 * Interim 6.8
 * 
 * Revision 1.3  91/01/07  23:50:17  kej
 * Support fax images encoded as a SEQUENCE which contains a SET followed by
 * a SEQUENCE of BIT STRING.
 * 
 * Revision 1.2  91/01/05  00:31:29  kej
 * ISODE claimed to be creating fax images as ASN.1-encoded BIT STRING's.
 * However, the encoding was incorrect.  This revision corrects the
 * problem, implements 1-d and 2-d encoding of fax images, and it provides
 * a backward compatible mechanism for reading the old, broken images.
 * 
 * Revision 1.1  91/01/02  21:35:13  kej
 * Initial revision
 * 
 * Revision 7.1  90/07/09  14:40:20  mrose
 * sync
 * 
 * Revision 7.0  89/11/23  22:01:37  mrose
 * Release 6.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */

#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include "quipu/photo.h"
#include "psap.h"

#define UNCOMPRESSED_1D	0x0e
#define ERR_RUN		0x0f

/* this file contains the main routines for decoding X400 */

extern int PIC_LINESIZE, STOP, NUMLINES;

/* variables for top of the code word trees */

node * bl_tree_top;
node * wt_tree_top;
node * two_tree_top;

unsigned int position;

static char ref_colour;
static char colour;
char * malloc ();
char *bitmap;

static void  resync ();
static int seqerrs = 0;

int decode_t4 (data, name, size)
char *data;
char *name;
int   size;
{
    PE    member;
    PE    pe;
    PS    ps;
    PE    seq;
    PE    set;
    int   twoDimensional = 0;
    int   res;

    /*
     *  If the first byte does not indicate that the data is an ASN.1-encoded
     *  SET or BIT STRING, attempt to convert the data as a non-ASN.1 image.
     */

    if ((unsigned char)*data != 0xa3 && *data != 0x03) 
	return decode_t4_aux (data, name, (int)size, twoDimensional);

    /* attempt to decode the source */

    if ((ps = ps_alloc (str_open)) == NULLPS) {
	fprintf (stderr, "ps_alloc: unable to allocate presentation stream\n");
	return (-1);
    }
    if (str_setup (ps, data, (int)size, 0) == NOTOK) {
	ps_free (ps);
	return -1;
    }
    if ((pe = ps2pe (ps)) == NULLPE) { /* maybe it's a non-ASN.1 image */
	ps_free (ps);
	return decode_t4_aux (data, name, (int)size, 1);
    }

    if (pe->pe_class == PE_CLASS_UNIV && pe->pe_form == PE_FORM_PRIM &&
	pe->pe_id == PE_PRIM_BITS) { /* old  BIT STRING-like form */
	if (pe_pullup (pe) == NOTOK) {
	    pe_free (pe);
	    ps_free (ps);
	    return -1;
        }
	res = decode_t4_aux (pe -> pe_prim, name, ps_get_abs (pe), 1);
    }
    else if (pe->pe_class == PE_CLASS_CONT && pe->pe_form == PE_FORM_CONS &&
	     pe->pe_id == 3) {

	/* first member must be SET which describes G3-Fax options */

	set = first_member (pe);
	if (!set || set->pe_class != PE_CLASS_UNIV ||
	    set->pe_form != PE_FORM_CONS || set->pe_id != PE_CONS_SET) {
	    fprintf (stderr, "decode_fax: %s is not a fax image\n", name);
	    pe_free (pe);
	    ps_free (ps);
	    return -1;
	}

	for (member = first_member (set); member; member = next_member (set, member)) {
	    if (member->pe_class == PE_CLASS_CONT &&
		member->pe_form == PE_FORM_PRIM && member->pe_id == 1) {
	        twoDimensional = bit_test (prim2bit (member), 8);
		if (twoDimensional == -1) {
		    pe_free (pe);
		    ps_free (ps);
		    return -1;
	        }
	    }
	}

	/* SEQUENCE of BIT STRING should follow SET */

	seq = next_member (pe, set);
	if (!seq || seq->pe_class != PE_CLASS_UNIV ||
	    seq->pe_form != PE_FORM_CONS || seq->pe_id != PE_CONS_SEQ) {
	    fprintf (stderr, "%s: is not a fax image\n", name);
	    pe_free (pe);
	    ps_free (ps);
	    return -1;
	}

	for (member = first_member (seq); member; member = next_member (seq, member)) {
	    if (member->pe_class != PE_CLASS_UNIV ||
		member->pe_form != PE_FORM_PRIM ||
		member->pe_id != PE_PRIM_BITS) {
		fprintf (stderr, "%s: is not a fax image\n", name);
		pe_free (pe);
		ps_free (ps);
		return -1;
	    }
	    res = decode_t4_aux ((member->pe_prim) + 1, name,
			   ps_get_abs (member) - 1, twoDimensional);
	}
    }
    else  /* maybe its a non-ASN.1 image */
	res = decode_t4_aux (data, name, (int)size, 1);

    pe_free (pe);
    ps_free (ps);

    return res;


}

/*
 *  Uncompressed mode black and white pel count tables.  These tables
 *  are indexed by the count of leading zeros in the uncompressed mode
 *  code word.
 */

#define UC_EXIT 6

static int uc_white_pels [] = {
	/* image pattern     code word   */
    0,	/*     1             1           */
    1,	/*     01            01          */
    2,	/*     001           001         */
    3,	/*     0001          0001        */
    4,	/*     00001         00001       */
    5,	/*     00000         000001      */
    0,	/*                   0000001     */
    1,	/*     0             00000001    */
    2,	/*     00            000000001   */
    3,	/*     000           0000000001  */
    4,	/*     0000          00000000001 */
};

static int uc_black_pels [] = {
	/* image pattern     code word    */
    1,	/*     1              1           */
    1,	/*     01             01          */
    1,	/*     001            001         */
    1,	/*     0001           0001        */
    1,	/*     00001          00001       */
    0,	/*     00000          000001      */
    0,	/*                    0000001     */
    0,	/*     0              00000001    */
    0,	/*     00             000000001   */
    0,	/*     000            0000000001  */
    0,	/*     0000           00000000001 */
};

/* ROUTINE:     Decode_t4
/*
/* SYNOPSIS:    Decodes a bit map stored in format T4 as recommended
/*              by CCITT.
/*
/* DESCRIPTION: After setting up the buffers, a line at a time is dealt with.
/* Each line is recognised as being one or two dimensionally coded, depending
/* upon the tag bit.
/* The run change buffers for each line are kept incase the next line is two
/* dimensionally, when it will be used as a reference.
/*
*/


int decode_t4_aux (inbuf, winname, length, twoDimensional)
char *inbuf;
char *winname;
int   length;
int   twoDimensional;
{
   bit_string code_line,      /* output line */
              ref_line,       /* reference line */
              t4_line;        /* input line  */

   int       done;
   run_type  run;
   int	    *buffer1, *buffer2;
   int      *run_buf1, *run_buf2;
   char      oneDtag, tag;

   seqerrs = 0;

   if (photo_start (winname) == -1)
	return (-1);

   if (build_trees () == -1)
	return (-1);

   buffer1      = (int *) malloc (LINEBUF * sizeof(int));
   buffer2      = (int *) malloc (LINEBUF * sizeof(int));
   buffer1[0]   = 0;   /* to halt backtracting if needed at start of line */
   buffer2[0]   = 0;
   run_buf1     = buffer1;
   run_buf2     = buffer2;
   ref_line.run_top  = ++run_buf1;
   code_line.run_top = ++run_buf2;

   code_line.dbuf_top = malloc (BUFSIZ);
   t4_line.dbuf_top = inbuf;

   if (set_dinput (&t4_line, length) == -1)
	return (-1);
   set_doutput (&code_line);

   /* images must always start with a 1-d encoded line */

   position = 1;
   NUMLINES = 1;
   done = decode_one (&code_line, &t4_line);
   if (done < 0) return (-1);
   if ( !done ) { /* no leading EOL */
       flush_doutput (&code_line);
       set_doutput (&code_line);
       photo_line_end (&code_line);
   }
   else { /* leading EOL */
       NUMLINES = 0;
       done = 0;
   }

   if (twoDimensional)
       oneDtag = tag = get_bit(&t4_line);

   while ( done != 1 ) {
      ++NUMLINES;
      position = 1;

      if ( twoDimensional && tag != oneDtag ) {
	  if (code_line.run_top  == run_buf1) {
	      ref_line.run_top  = run_buf1;
	      code_line.run_top = run_buf2;
	  }
	  else {
	      ref_line.run_top  = run_buf2;
	      code_line.run_top = run_buf1;
	  }
	  done = decode_two (&ref_line, &code_line, &t4_line);
      }
      else {
	  done = decode_one (&code_line, &t4_line);
      }

      if (done == -1) return (-1);

      flush_doutput (&code_line);
      set_doutput (&code_line);
      photo_line_end (&code_line);

      if ( twoDimensional && done != 1 )
	  tag = get_bit (&t4_line);

      if ( done == -2 && twoDimensional ) {
	  while ( tag != oneDtag ) {
	      resync (&t4_line);
	      tag = get_bit (&t4_line);
	  }
      }

   }

   bitmap = code_line.dbuf_top;

   (void) free ((char *)buffer1);
   (void) free ((char *)buffer2);
	
   return (photo_end (winname));

}



/* ROUTINE:     find_node
 *
 * SYNOPSIS:    Reads a sequence of bits from a source line and traverses
 *              a code word tree to find a matching code word.
 */

static node *
find_node (lineptr, tree_top)
bit_string * lineptr;
node * tree_top;
{
   node * ptr;

   ptr = tree_top;

   do {

      if (get_bit (lineptr) == 0) {
	  ptr = ptr->zero;
      }
      else {
	  ptr = ptr->one;
      }

      if (ptr == NULL) {
	  (void) fprintf (stderr,
			  "decode_fax: WARNING - sequencing error in line %d\n",
			  NUMLINES);
	  return (NULL);
      }

   } while (ptr->n_type == INTERNAL);

   return (ptr);
}



/* ROUTINE:     next_run
 *
 * SYNOPSIS:    Reads the next run length from the input file.
 *
 * DESCRIPTION: As each bit is read, it is used to move down the decode tree,
 * when a node is found that contains a value, the value is returned.
 * The code is assumed to be one dimensional.
*/

run_type
next_run (lineptr,xcolour)
bit_string * lineptr;
char    xcolour;
{

   node *   ptr;
   run_type result;

   result.run_length = 0;

   if (xcolour == BLACK)
      ptr = find_node (lineptr, bl_tree_top);
   else
      ptr = find_node (lineptr, wt_tree_top);
      
   if (ptr == NULL) {
       result.r_type = ERR_RUN;
       return (result);
   }

   /* if the above value was a make up code, now read the terminal code */

   if (ptr->n_type == MAKE) {
        if (ptr->value == -1) {
	    result.r_type = UNCOMPRESSED_1D;
	    return (result);
	}
	result.run_length = ptr->value;
	if (xcolour == BLACK)
	    ptr = find_node (lineptr, bl_tree_top);
	else
	    ptr = find_node (lineptr, wt_tree_top);

	if (ptr == NULL) {
	    result.r_type = ERR_RUN;
	    return (result);
        }
    }

    result.run_length += ptr->value;
    result.r_type = ptr->n_type;
    return (result);
}



/* ROUTINE:     decode_one
/*
/* SYNOPSIS:    decodes one line of t4.
/*
/* DESCRIPTION: reads a run, then writes that many bits of the appropiate
/* colour to the output.
/*
/* RETURNS:     0 if successful
/*              1 if successful and end of page detected
/*             -1 if line could not be decoded
/*             -2 if error detected and resync succeeded
*/

decode_one (lineptr, t4_lineptr)
bit_string * lineptr;
bit_string * t4_lineptr;

{
   run_type run;
   char xcolour = WHITE;
   int  done;
   int  i;
   int  savelinesize;

   lineptr->run_pos = lineptr->run_top;

   savelinesize = PIC_LINESIZE;
   PIC_LINESIZE = 0;

   for (;;) {
       run = next_run (t4_lineptr, xcolour);
       if (run.r_type == ERR_RUN) {
	   if (++seqerrs < 10) {
	       resync (t4_lineptr);
	       return (-2);
           }
	   else {
	       fputs ("decode_fax: too many sequencing errors\n", stderr);
	       return (-1);
           }
       }
       else if (run.r_type == UNCOMPRESSED_1D) {
	   xcolour = undo_uncompressed_mode (lineptr, t4_lineptr, xcolour, 0);
	   if (xcolour == -1) return (-1);
       }
       else if (run.r_type == EOLN) {
	   break;
       }
       else {
	   PIC_LINESIZE += run.run_length;
	   put_run (lineptr, run.run_length, xcolour);
	   xcolour = 1 - xcolour;
       }
   }

   while (get_bit(t4_lineptr) != 01)
       ; /* skip fill characters */

   if (lineptr->run_pos == lineptr->run_top){
	done = 1;
	PIC_LINESIZE = savelinesize;
   }
   else
	done = 0;

   STOP = PIC_LINESIZE + 1;
   *lineptr->run_pos++ = STOP;
   *lineptr->run_pos   = STOP;

   return (done);
}



/* ROUTINE:     decode_two
/*
/* SYNOPSIS:    decodes a two dim line.
/*
/* DESCRIPTION: The binary codes read in are looked up in the decode tree,
/* and the appropiate routine called to decode that mode.
/*
/* RETURNS:     0 if successful
/*             -1 if too many sequencing errors
/*             -2 if resynch performed
*/

decode_two (ref_lineptr, code_lineptr, t4_lineptr)

bit_string * ref_lineptr;
bit_string * code_lineptr;
bit_string * t4_lineptr;

{
   int length;
   node * ptr;
   int status;

   ref_lineptr->run_pos = ref_lineptr->run_top;
   code_lineptr->run_pos = code_lineptr->run_top;

   colour = WHITE;
   ref_colour = BLACK;

   do {
       ptr = find_node (t4_lineptr, two_tree_top);
       if (ptr == NULL) {
	   if (++seqerrs < 10) {
	       resync (t4_lineptr);
	       return (-2);
           }
	   else {
	       fputs ("decode_fax: too many sequencing errors\n", stderr);
	       return (-1);
	   }
       }

       switch (ptr->value) {

       case -1:
	       colour = undo_uncompressed_mode (code_lineptr, t4_lineptr,
						colour, 1);
	       if (colour < 0) return (colour);
	       break;

       case P:
	       undo_pass_mode (ref_lineptr, code_lineptr);
	       break;

       case H:
	       status = undo_horiz_mode (t4_lineptr, code_lineptr);
	       if (status < 0) return (status);
	       break;

       case EOLN:
	       break;

       default:
	       undo_vert_mode (ref_lineptr, code_lineptr, ptr->value);
	       break;
       }
   } while (ptr->n_type != EOLN);

   /* fill to end of line with current colour */

   length = (int)(PIC_LINESIZE - position + 1);
   if (length != 0)
       put_run (code_lineptr, length, colour);

   while (get_bit (t4_lineptr) != 1)
	;               /* skip fill characters */

   *code_lineptr->run_pos++ = STOP;
   *code_lineptr->run_pos   = STOP;

   return (0);
}


/* ROUTINE:     undo_uncompressed_mode
/*
/* SYNOPSIS:    decodes a section recognised as uncompressed mode.
/*
/* DESCRIPTION: Process uncompressed code words until a terminating
/*              code word is found.
/*
/* RETURNS:     -1 if too many sequencing errors
/*              -2 if resynch performed
/*              else next colour
*/

undo_uncompressed_mode (lineptr, t4_lineptr, colour, twoD)
bit_string * lineptr;
bit_string * t4_lineptr;
int colour;
int twoD;

{
    int black_length;
    int next_colour;
    int white_length;
    int zeros;

    for (;;) {
	zeros = 0;
	while (get_bit(t4_lineptr) != 01) ++zeros;
	if (zeros > 10) {
	    fputs ("decode_fax: bad code word in uncompressed mode string\n",
		   stderr);
	    if (++seqerrs < 10) {
		resync (t4_lineptr);
		return (-2);
	    }
	    else {
		fputs ("decode_fax: too many sequencing errors\n", stderr);
		return (-1);
	    }
        }
	white_length = uc_white_pels[zeros];
	black_length = uc_black_pels[zeros];
	if (white_length > 0) {
	    if (colour == BLACK)
	        --lineptr->run_pos;
	    put_run (lineptr, white_length, WHITE);
	    colour = BLACK;
        }
	if (black_length > 0) {
	    if (colour == WHITE)
	        --lineptr->run_pos;
	    put_run (lineptr, black_length, BLACK);
	    colour = WHITE;
        }
	if (!twoD)
	    PIC_LINESIZE += white_length + black_length;

	if (zeros >= UC_EXIT) {
	    next_colour = (get_bit(t4_lineptr) == 01) ? BLACK : WHITE;
	    if (next_colour != colour)
	        --lineptr->run_pos;
	    return (next_colour);
	}
    }
}

/* ROUTINE:     undo_pass_mode
/*
/* SYNOPSIS:    decodes a section recognised as pass mode.
/*
/* DESCRIPTION: find b2, then write to output the same colour as before
/* up until position b2.
*/

undo_pass_mode (ref_lineptr, code_lineptr)
bit_string * ref_lineptr;
bit_string * code_lineptr;

{
   int length;

   goto_b1 (ref_lineptr);

   if (*ref_lineptr->run_pos < STOP) {
       ++ref_lineptr->run_pos;
       ref_colour = 1 - ref_colour;
    }

   length = (int)(*ref_lineptr->run_pos - position);
   put_run (code_lineptr, length, colour);
   --code_lineptr->run_pos;     /* don't count this as a change */
}




/* ROUTINE:     undo_horiz_mode
/*
/* SYNOPSIS:    decodes a section recognised as horizontal mode.
/*
/* DESCRIPTION: Read two run lengths for the input, and write the appropiate
/* number of 1's or 0's to the output.
/*
/* RETURNS:     0 if successful
/*             -1 if too many sequencing errors
/*             -2 if resynch performed
*/

undo_horiz_mode (t4_lineptr, code_lineptr)

bit_string * t4_lineptr;
bit_string * code_lineptr;

{
    run_type run;

    run = next_run (t4_lineptr, colour);
    if (run.r_type == ERR_RUN) {
	if (++seqerrs < 10) {
	    resync (t4_lineptr);
	    return (-2);
        }
	else {
	    fputs ("decode_fax: too many sequencing errors\n", stderr);
	    return (-1);
        }
    }

    put_run (code_lineptr, run.run_length, colour);

    run = next_run (t4_lineptr, 1 - colour);
    if (run.r_type == ERR_RUN) {
	if (++seqerrs < 10) {
	    resync (t4_lineptr);
	    return (-2);
        }
	else {
	    fputs ("decode_fax: too many sequencing errors\n", stderr);
	    return (-1);
        }
    }

    put_run (code_lineptr, run.run_length, 1 - colour);
    
    return (0);
}


/* ROUTINE:     undo_vert_mode
/*
/* SYNOPSIS:    decodes vertical mode
/*
/* DESCRIPTION: Find b1, the write 1's or 0's upto it allowing for the offset.
*/

undo_vert_mode (ref_lineptr, code_lineptr, offset)

bit_string * ref_lineptr;
bit_string * code_lineptr;
char         offset;

{
   int   length;

   goto_b1 (ref_lineptr);

   length = (*ref_lineptr->run_pos - position) + offset - FIXED_OFFSET;
   put_run (code_lineptr, length , colour);
   colour = 1 - colour;
}



/* ROUTINE:     goto_b1
 *
 * SYNOPSIS:    move the pointer in the reference line to b1
 *
 * DESCRIPTION: b1 is the first changing bit in the reference line
 * of a different colour to a0.  May need to move backwards or forwards
 *
 */

goto_b1 (lineptr)
bit_string * lineptr;

{
   while (*lineptr->run_pos > position) {
       --lineptr->run_pos;
       ref_colour = 1 - ref_colour;
   }

   while (*lineptr->run_pos < position) {
       ++lineptr->run_pos;
       ref_colour = 1 - ref_colour;
   }

   if (ref_colour == colour) {
	++lineptr->run_pos;
	ref_colour = 1 - ref_colour;
   }
   else if (*lineptr->run_pos < STOP)

	/* special case when b1 = a0, and the colours are different,
	   move b1 to the next change of same colour,
	   this must be allowed at the beginning of a line to get a run of
	   zero, as every line must start with a white element */

	if ((*lineptr->run_pos == position) && (*lineptr->run_pos > 1))
	    lineptr->run_pos += 2;
}



/* ROUTINE:     resync
/*
/* SYNOPSIS:    resynchronizes sequencing by locating the next EOL
/*
*/

static void
resync (lineptr)
bit_string * lineptr;

{
    int i;

    for (;;) {
	while (get_bit (lineptr) == 1)
	    ;
	i = 1;
	while (get_bit (lineptr) == 0)
	    ++i;
	if (i > 10) return;
    }
}



/* ROUTINE:     put_run                                                 */
/*                                                                      */
/* SYNOPSIS:    writes a run_length to the indicated bit_string.        */
/*                                                                      */

put_run (lineptr, length, xcolour)
bit_string * lineptr;
int  length;
char xcolour;
{
    register i;
    register l;

/*
    if ( length < 0 ) {
	(void) fprintf (stderr,
			"decode_fax: WARNING - negative run length (%d) detected in line %d\n",
			length, NUMLINES);
    }
*/

    if ( xcolour == WHITE)
	photo_white (length);
    else
	photo_black (length);

    /* now fill line buffer for purpose of decoding 2-d lines */

    if (length > 16) {
	l = length;
	if (lineptr->mask != BIT_MASK) {        /* fill current byte */
	   if (xcolour == WHITE)
	      do {
		 clr_bit (lineptr);
		 --l;
	      } while (lineptr->mask != BIT_MASK);

	   else
	      do {
		 set_bit (lineptr);
		 --l;
	      } while (lineptr->mask != BIT_MASK);
	  }

	/* write out the bytes */

	if (xcolour == WHITE)
	    for (i = 0; i < l / 8; i++)
		*lineptr->dbuf++ = 0;
	else
	    for (i = 0; i < l / 8; i++)
		*lineptr->dbuf++ = 0xff;


	/* put the last few bits into the next byte */

	if (xcolour == WHITE)
	     for (i = 0; i < l % 8; i++)
		clr_bit (lineptr);
	 else
	     for (i = 0; i < l % 8; i++)
		set_bit (lineptr);
    }

    /* length < 16 - can't optimise, so deal with bits */

    else {
	if (xcolour == WHITE) {
	    for (i = 0; i < length; i++) clr_bit (lineptr);
	}
	else {
	    for (i = 0; i < length; i++)
	       set_bit (lineptr);
	}
    }

    position += length;
    *lineptr->run_pos++ = position;
}




/* ROUTINE:     set_doutput;
/*
/* SYNOPSIS:    Initialises the output buffers
*/

set_doutput (lineptr)
bit_string * lineptr;
{
	lineptr->dbuf = lineptr->dbuf_top;
	lineptr->mask = BIT_MASK;
}




/* ROUTINE:     flush_doutput;
/*
/* SYNOPSIS:    flush the output buffer;
*/

flush_doutput (lineptr)
bit_string * lineptr;
{
int count = 0;

	while ( lineptr->mask != BIT_MASK ) {
		clr_bit (lineptr);
		count++;
	}
	photo_white (count);
}



/* ROUTINE:     set_dinput;
/*
/* SYNOPSIS:    Initialises the input buffers
*/

set_dinput (lineptr, length)
bit_string * lineptr;
int	length;
{
    unsigned char cbyte;
    int count;
    int i;

    lineptr->dbuf = lineptr->dbuf_top;

    if (length == 0) {
	if (*lineptr->dbuf++ != 0x03) {
	   (void) fputs ("decode_fax: input stream is not a BIT STRING\n",
			 stderr);
	   return (-1);
	}
	cbyte = *lineptr->dbuf++;
	if (cbyte & 0x80) { /* long form */
	    count = cbyte & 0x7f;
	    if (count > 4) {
		(void) fputs ("decode_fax: length error\n", stderr);	
		return (-1);
	    }
	    for (i = 0; i < count; ++i)
	        ++lineptr->dbuf;
	}
    }

   lineptr->pos = *lineptr->dbuf++;
   lineptr->mask = BIT_MASK;

   return (0);
}