home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
VIEWERS
/
UNIXVIEW
/
XGIFTAR.Z
/
XGIFTAR
/
g3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-05-20
|
10KB
|
482 lines
/** g3.c - read a Group 3 FAX file and product a bitmap
**
** Adapted from Paul Haeberli's <paul@manray.sgi.com> G3 to Portable Bitmap
** code.
**
** modified by jimf on 09.18.90 to fail on any load error. this was done
** to cut down on the false positives caused by a lack of any read ID
** string. the old errors are currently ifdef'ed out -- if you want 'em
** define ALLOW_G3_ERRORS.
**/
/* Edit History
04/15/91 8 nazgul Sanity check line widths
Doing a zclose on all failures
04/14/91 1 schulert add <sys/types> for SYSV systems
04/13/91 6 nazgul Handle reinvocation on the same file
04/13/91 5 nazgul Bug fix to retry with bitreversed, and do not double allocate on multiple calls
04/12/91 4 nazgul Spot faxes that do not have a 000 header
Handle faxes that have the bytes in the wrong order
07/03/90 2 nazgul Added recovery for premature EOF
*/
#include <sys/types.h>
#include <sys/file.h>
#include "image.h"
#include "g3.h"
/* SUPPRESS 530 */
/* SUPPRESS 558 */
/* SUPPRESS 560 */
/****
**
** Local defines
**
****/
#define BITS_TO_BYTES(bits) (bits/8)+((bits-((bits/8)*8)?1:0))
#define TABSIZE(tab) (sizeof(tab)/sizeof(struct tableentry))
#ifdef VMS
#define cols vmscols
#endif
/****
**
** Local variables
**
****/
static int g3_eof = 0;
static int g3_eols;
static int g3_rawzeros;
static int g3_Xrawzeros;
static int maxlinelen;
static int rows, cols;
static int g3_error = 0;
static int g3_verb;
static int curbit;
#define MAX_ERRORS 20
/****
**
** Local tables
**
****/
tableentry *whash[HASHSIZE];
tableentry *bhash[HASHSIZE];
int g3_addtohash(hash, te, n, a, b)
tableentry *hash[];
tableentry *te;
int n, a, b;
{
unsigned int pos;
while (n--) {
pos = ((te->length+a)*(te->code+b))%HASHSIZE;
if (hash[pos] != 0) {
#ifdef ALLOW_G3_ERRORS
fprintf(stderr, "G3: Hash collision during initialization.\n");
exit(1);
#else
++g3_error;
return(-1);
#endif
}
hash[pos] = te;
te++;
}
}
tableentry *g3_hashfind(hash, length, code, a, b)
tableentry *hash[];
int length, code;
int a, b;
{
unsigned int pos;
tableentry *te;
pos = ((length+a)*(code+b))%HASHSIZE;
if (pos >= HASHSIZE) {
#ifndef ALLOW_G3_ERRORS
fprintf(stderr, "G3: Bad hash position, length %d code %d pos %d.\n",
length, code, pos);
exit(2);
#else
++g3_error;
return(NULL);
#endif
}
te = hash[pos];
return ((te && te->length == length && te->code == code) ? te : 0);
}
int g3_getfaxrow(fd, bitrow)
ZFILE *fd;
byte *bitrow;
{
int col;
int curlen, curcode, nextbit;
int count, color;
tableentry *te;
/* First make the whole row white... */
bzero((char *) bitrow, maxlinelen); /* was memset -- jimf 09.11.90 */
col = 0;
g3_rawzeros = 0;
curlen = 0;
curcode = 0;
color = 1;
count = 0;
while (!g3_eof) {
if (col >= MAXCOLS) {
#ifdef ALLOW_G3_ERRORS
if (g3_verb) fprintf(stderr, "G3: Input row %d is too long, skipping to EOL.\n", rows);
g3_skiptoeol(fd);
++g3_error;
return (col);
#else
return(-1);
#endif
}
do {
if (g3_eof) return 0;
if (g3_rawzeros >= 11) {
nextbit = g3_rawgetbit(fd);
if (nextbit) {
if ( col == 0 )
/* 6 consecutive EOLs mean end of document */
g3_eof = (++g3_eols >= 5);
else
g3_eols = 0;
return (col);
}
}
else
nextbit = g3_rawgetbit(fd);
curcode = (curcode<<1) + nextbit;
curlen++;
} while (curcode <= 0);
/* No codewords are greater than 13 bytes */
if (curlen > 13) {
#ifdef ALLOW_G3_ERRORS
if (g3_verb) fprintf(stderr, "G3: Bad code word at row %d, col %d (len %d code 0x%2.2x), skipping to EOL.\n", rows, col, curlen, curcode );
g3_skiptoeol(fd);
++g3_error;
return (col);
#else
return(-1);
#endif
}
if (color) {
/* White codewords are at least 4 bits long */
if (curlen < 4)
continue;
te = g3_hashfind(whash, curlen, curcode, WHASHA, WHASHB);
}
else {
/* Black codewords are at least 2 bits long */
if (curlen < 2)
continue;
te = g3_hashfind(bhash, curlen, curcode, BHASHA, BHASHB);
}
if (!te)
continue;
switch (te->tabid) {
case TWTABLE:
case TBTABLE:
count += te->count;
if (col+count > MAXCOLS)
count = MAXCOLS-col;
if (count > 0) {
if (color) {
col += count;
count = 0;
}
else
g3_bitson(bitrow, col, count);
}
curcode = 0;
curlen = 0;
color = !color;
break;
case MWTABLE:
case MBTABLE:
count += te->count;
curcode = 0;
curlen = 0;
break;
case EXTABLE:
count += te->count;
curcode = 0;
curlen = 0;
break;
default:
fprintf(stderr, "G3: Bad table id from table entry.\n");
#ifndef ALLOW_G3_ERRORS
exit(3);
#else
++g3_error;
return(-1);
#endif
}
}
return (0);
}
int g3_skiptoeol(fd)
ZFILE *fd;
{
while (g3_rawzeros<11 && !g3_eof)
(void) g3_rawgetbit(fd);
while(!g3_rawgetbit(fd) && !g3_eof);
return(0);
}
int g3_rawgetbit(fd)
ZFILE *fd;
{
int b;
static int shdata;
if (curbit >= 8) {
shdata = zgetc(fd);
if (shdata == EOF) {
#ifdef ALLOW_G3_ERRORS
if (g3_verb) fprintf(stderr, "G3: Premature EOF at line %d.\n", rows);
g3_eols = 5;
g3_eof = 1;
++g3_error;
return 0;
#else
return(-1);
#endif
}
curbit = 0;
}
if (shdata & bmask[curbit]) {
g3_Xrawzeros = g3_rawzeros;
g3_rawzeros = 0;
b = 1;
}
else {
g3_rawzeros++;
b = 0;
}
curbit++;
return b;
}
int g3_bitson(b, c, n)
bit *b;
int c, n;
{
int i, col;
bit *bP;
static int bitmask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
bP = b;
col = c;
bP+=(c/8);
i = (c - ((c/8)*8));
while(col <= (c+n)) {
for(;col <= (c+n) && i < 8; i++) {
*bP |= bitmask[i];
col++;
}
i = 0;
bP++;
}
return(0);
}
/* All G3 images begin with a G3 EOL codeword which is eleven binary 0's
* followed by one binary 1. There could be up to 15 0' so that the image
* starts on a char boundary.
*/
/*
* They are all *supposed* to, but in fact some don't. In fact pbmtog3 doesn't seem
* to generate them. So if that fails, we'll also try reading a line and seeing if
* we get any errors. Note that this means we had to move the call to g3_ident
* to after the hash table init. -nazgul
*/
int g3_ident(fd)
ZFILE *fd;
{
int ret = 0, col1, col2, i;
byte *tmpline;
int reverse = 0;
struct cache *dataptr;
int bufptr;
g3_verb = 0;
tmpline = (byte *) lmalloc(maxlinelen);
/* In case this got reset by a previous pass through here */
for (i = 0; i < 8; ++i) {
bmask[7-i] = 1 << i;
}
tryagain:
curbit = 8;
g3_Xrawzeros = 0;
g3_eof = g3_eols = rows = cols = 0;
/* If we have the zeros we're off to a good start, otherwise, skip some lines */
for (g3_rawzeros = 0; !g3_rawgetbit(fd) && !g3_eof;);
if (g3_Xrawzeros >= 11 && g3_Xrawzeros <= 15) {
fd->dataptr = fd->data;
fd->bufptr = 0;
curbit = 8;
g3_skiptoeol(fd);
if (!g3_error) g3_skiptoeol(fd);
if (!g3_error) g3_skiptoeol(fd);
if (!g3_error) g3_skiptoeol(fd);
} else ret = 1;
/* Now get two lines and make sure they are the same length. If not give up.
* Note that it is possible for this to give false positives (value.o on a Sun IPC
* did) but it's unlikely enough that I think we're okay.
*/
dataptr = fd->dataptr;
bufptr = fd->bufptr;
if (!g3_error) col1 = g3_getfaxrow(fd, tmpline);
if (!g3_error) col2 = g3_getfaxrow(fd, tmpline);
if (!g3_error && col1 == col2 && col1 != 0) ret = 1;
else ret = 0;
/* if (ret) printf("%d = %d\n", col1, col2); */
fd->dataptr = dataptr;
fd->bufptr = bufptr;
curbit = 8;
/* This bogus hack is to accomodate some fax modems which apparently use a chip
* with a different byte order. We simply try again with the table reversed.
*/
if (!ret && !reverse) {
rows = cols = g3_error = 0;
fd->dataptr = fd->data;
fd->bufptr = 0;
g3_Xrawzeros = 0;
for (i = 0; i < 8; ++i) {
bmask[i] = 1 << i;
}
reverse = 1;
goto tryagain;
}
g3_eols = rows = cols = 0;
lfree(tmpline);
return(ret);
}
Image *g3Load(fullname, name, verbose)
char *fullname, *name;
unsigned int verbose;
{
ZFILE *fd;
Image *image;
int i, col;
byte *currline;
static int firstTime = 1;
if ((fd = zopen(fullname)) == NULL)
return(NULL);
if (firstTime) {
firstTime = 0;
/* Initialize and load the hash tables */
for ( i = 0; i < HASHSIZE; ++i )
whash[i] = bhash[i] = (tableentry *) 0;
g3_addtohash(whash, twtable, TABSIZE(twtable), WHASHA, WHASHB);
g3_addtohash(whash, mwtable, TABSIZE(mwtable), WHASHA, WHASHB);
g3_addtohash(whash, extable, TABSIZE(extable), WHASHA, WHASHB);
g3_addtohash(bhash, tbtable, TABSIZE(tbtable), BHASHA, BHASHB);
g3_addtohash(bhash, mbtable, TABSIZE(mbtable), BHASHA, BHASHB);
g3_addtohash(bhash, extable, TABSIZE(extable), BHASHA, BHASHB);
}
g3_eof = g3_eols = 0;
curbit = 8; /* Reset on multiple reads */
/* Calulate the number of bytes needed for maximum number of columns
* (bits), create a temprary storage area for it.
*/
maxlinelen = BITS_TO_BYTES(MAXCOLS);
if (!g3_ident(fd)) {
zclose(fd);
return(NULL);
}
g3_verb = verbose;
image = newBitImage(MAXCOLS, MAXROWS);
currline = image->data;
cols = 0;
for (rows = 0; rows < MAXROWS; ++rows) {
col = g3_getfaxrow(fd, currline);
#ifndef ALLOW_G3_ERRORS
if (col < 0) {
freeImage(image);
zclose(fd);
return(NULL);
}
#else
if (g3_error > MAX_ERRORS) {
freeImage(image);
zclose(fd);
return(NULL);
}
#endif
if (g3_eof)
break;
if (col > cols)
cols = col;
currline += BITS_TO_BYTES(cols);
}
zclose(fd);
image->title= dupString(name);
image->width = cols;
image->height = rows;
if (!image->width || !image->height) { /* sanity check */
freeImage(image);
return(NULL);
}
if(verbose)
printf(" %s is a %dx%d G3 FAX image.\n", name, image->width, image->height);
return(image);
}
/* originally this used only g3_ident to determine if it was a G3 image, but
* it was always getting false positives so now it loads the whole image in
* to see if it's reasonable.
*/
int g3Ident(fullname, name)
char *fullname, *name;
{
Image *image;
g3_verb = 0;
if (image= g3Load(fullname, name, 1)) {
freeImage(image);
return(1);
}
return(0);
}