www.pudn.com > commutil.zip > FCONVERT.CPP
// ******************************************************************** //
// //
// FCONVERT.CPP //
// Copyright (c) 1993, Michael Holmes and Bob Flanders //
// C++ Communication Utilities //
// //
// This file contains the routines for converting to and //
// from the G3 fax format. //
// //
// ******************************************************************** //
//
// Conversion Routine Globals
//
int f_handle = -1, // G3 file handle
f_pgcnt, // maximum page count
f_write_flag, // write_out bit buffer flag
f_write_cnt; // write_out global counter
char *f_buffer, // work buffer
*f_ptr, // ..and current pointer
f_filename[MAX_PATH]; // fax filename
long f_page; // current G3 page size
#define HDR_LEN 128 // header length
#define BUF_SIZE 256 // buffer size
/* ******************************************************************** *
*
* f_locate() -- find a G3 formatted file and check its integrity
*
* returns: 0 = file opened
* 1 = file not found
*
* ******************************************************************** */
int f_locate(char *s) // source filename
{
long file_size, // file size
pos; // current file position
if (f_handle != -1) // q. already open?
{
close(f_handle); // a. yes .. close file
f_handle = -1; // ..and clear flag
}
if (NOT first_nonblank(s)) // q. empty string?
return(1); // a. yes .. just return
if ((f_handle = open(s, // q. find and open file ok?
_O_RDONLY | _O_BINARY)) == -1)
return(1); // a. no .. return w/error
file_size = lseek(f_handle, 0L, SEEK_END); // get file size
lseek(f_handle, 0L, SEEK_SET); // ..and back to file start
if ((read(f_handle, page, 128) != 128) || // q. file header available
strncmp((char *) page, "G3", 2)) // ..and our format?
{
close(f_handle); // a. no .. just close file
f_handle = -1; // ..clear flag
return(1); // ..and return to caller
}
pos = lseek(f_handle, 0L, SEEK_CUR); // get starting position
for (f_pgcnt = 0;;) // count available fax pages
{
if (read(f_handle, (char *) &f_page, // q. read in enough to cover
sizeof(long)) != sizeof(long)) // ..the page length field?
break; // a. no .. exit loop
if ((f_page < 1) || // q. page size non-positive?
((f_page + pos + 4) > file_size)) // ..or bigger than the file?
break; // a. yes .. exit loop
if ((pos = lseek(f_handle, f_page, // q. properly position to the
SEEK_CUR)) == -1L) // ..start of the next page?
break; // a. no .. exit loop
f_pgcnt++; // count this page
}
strcpy(f_filename, s); // save filename ..
return(0); // ..then return all ok
}
/* ******************************************************************** *
*
* f_get_next_byte() -- get the next byte from the G3 file
*
* returns: -1 = end of data or error
* n = next byte
*
* ******************************************************************** */
int f_get_next_byte(void)
{
static
int rb; // remaining buffer count
if (f_ptr == 0 || rb == 0) // q. 1st call or out of data?
{ // a. yes .. get the next blk
if (f_page == 0) // q. out of data to read?
return(-1); // a. yes .. return all done
if (f_buffer == 0) // q. buffer allocated?
f_buffer = (char *) // a. no .. get a buffer
malloc_chk(BUF_SIZE);
rb = (int)((f_page > BUF_SIZE) ? // set count to smaller of
BUF_SIZE : f_page); // ..what's left or buffer size
if (read(f_handle, f_buffer, rb) != rb) // q. file read ok?
quit_with(read_error); // a. no .. give error message
f_page -= rb; // deduct what was read
f_ptr = f_buffer; // set up character pointer
}
rb--; // decriment remaining count
return(*(unsigned char *) f_ptr++); // ..and return character
}
/* ******************************************************************** *
*
* f_get_byte() -- get the next value from the G3 file handling DLEs
*
* returns: -1 = end of data or error
* n = next byte
*
* ******************************************************************** */
int f_get_byte(void)
{
int v; // work value
while (1)
{
if ((v = f_get_next_byte()) == -1) // q. out of data?
return(-1); // a. yes .. return EOF
if (v == DLE) // q. DLE character?
{ // a. yes .. get another
if ((v = f_get_next_byte()) == -1) // q. get another char ok?
return(-1); // a. no .. return EOF
if (v == DLE) // q. another DLE?
return(v); // a. yes .. return the goods
}
else
return(v); // else .. return w/character
}
}
/* ******************************************************************** *
*
* f_get_bit() -- get the next bit from the G3 file
*
* returns: -1 = end of data or error
* 0 = zero bit found
* 1 = one bit found
*
* ******************************************************************** */
int f_get_bit(void)
{
static
int w, // work byte
c = 0; // bit count
w >>= 1; // move next bit into place
if (f_ptr == 0 || c == 0) // q. 1st call or out of data?
{ // a. yes .. get a byte
if ((w = f_get_byte()) == -1) // q. out of data?
return(-1); // a. yes .. return EOF
c = 8; // number of available bits
}
c--; // show another one used
return(w & 1); // ..then rtn a bit to caller
}
/* ******************************************************************** *
*
* f_search() -- search for a codeword match
*
* returns: -2 = end of line or error
* -1 = no match found
* n = match found, n is nbr of bits in codeword
*
* ******************************************************************** */
int f_search(int type, // type of code
// 0 = white space
// 1 = black space
int l, // length in bits
int a) // accumulator
{
struct code_entry *e; // codeword table entries
if (l == 12 && a == 1) // q. end of line found?
return(-2); // a. yes .. return to caller
if ((e = code_table[l - 1][type]) != 0) // q. table entry found?
{ // a. yes .. check table
for (; e->code; e++) // scan a codeword table
if (e->code == a) // q. find a codeword match?
return(e->value); // a. yes .. return
}
if (l == 13) // q. reach max codeword size?
return(-2); // a. yes .. return w/error
else
return(-1); // else .. rtn nothing found
}
/* ******************************************************************** *
*
* f_get_code() -- get the next codeword from the G3 stream
*
* returns: 0 = converted next word ok
* 1 = error or end of line
*
* ******************************************************************** */
int f_get_code(int type, // type of code
// 0 = white space
// 1 = black space
int *len) // length in bits
{
int a = 0, // accumulator
b, // one bit work area
l = 0; // working length
while (1)
{
if ((b = f_get_bit()) == -1) // q. get a bit successfully?
return(1); // a. no .. must be out of data
a = (a << 1) | b; // shift in a new bit
l++; // ..tally up bits received
switch (*len = f_search(type, l, a)) // check for match
{
case -2: // end of line or error
return(1); // ..just return
case -1: // nothing found
break; // ..continue looping
default: // found codeword
return(0); // ..return ok
}
}
return(0); // make MSC C/C++ happy
}
/* ******************************************************************** *
*
* f_get_pels() -- get the next group of PELS from the G3 stream
*
* returns: 0 = converted next word ok
* 1 = error or end of line
*
* ******************************************************************** */
int f_get_pels(int type, // type of code
// 0 = white space
// 1 = black space
int *len) // length in bits
{
int a = 0; // accumulator
while (1)
{
if (f_get_code(type, len)) // q. get a code word?
return(1); // a. no .. must be out of data
if (*len > 63) // q. get a makeup code?
a = *len; // a. yes .. save for later
else
{
*len += a; // else .. add in any makeups
return(0); // ..and return all ok
}
}
}
/* ******************************************************************** *
*
* f_get_eol() -- read to end of line in current page
*
* ******************************************************************** */
void f_get_eol(void)
{
int a, // accumulator
b; // work bit
for (a = 0xfff; a != 1;) // try to find an EOL bit
{ // ..pattern of 000000000001
if ((b = f_get_bit()) == -1) // q. get a bit successfully?
return; // a. no .. must be out of data
a = ((a << 1) | b) & 0xfff; // move in new bit
}
}
/* ******************************************************************** *
*
* f_read_g3() -- read a page and convert from G3 format
*
* returns: 0 = page converted sucessfully
* 1 = page not found or error
*
* ******************************************************************** */
int f_read_g3(int n) // page number
{
int pels, // pixels counter
lines, // lines counter
type, // type of codeword
codes, // codewords processed
eol, // consecutive EOLs found
l = 0; // work length
char huge *p; // bitmap line pointer
lseek(f_handle, HDR_LEN, SEEK_SET); // get to start of 1st page
while(1) // loop to find requested page
{
if (read(f_handle, (char *) &f_page, // q. read in enough to cover
sizeof(long)) != sizeof(long)) // ..the page length field?
return(1); // a. no .. return not found
if (--n == 0) // q. find target page?
break; // a. yes .. exit loop
if (lseek(f_handle, f_page, // q. properly position to the
SEEK_CUR) == -1L) // ..start of the next page?
return(1); // a. no .. return not found
}
f_ptr = 0; // set global pointer
f_get_eol(); // find end of first line
for (lines = 0, p = page; // for the whole bitmap
lines < LINES; // ..run through line
lines++, p += LINE) // ..by line
memset(p, 0, LINE); // ..and clear white space
for (lines = 0, p = page, eol = 0; // fill in each line in the
lines < LINES; // ..bitmap page by processing
lines++, p += LINE) // ..one line at a time
{
for (pels = 0, type = 0, codes = 0; // for each bit available
pels < PELS; // ..in the bitmap line get
pels += l, codes++) // ..codewords and convert
{
if (f_get_pels(type, &l)) // q. end of line found?
break; // a. yes .. exit loop
if (l > (PELS - pels)) // q. too much data?
l = PELS - pels; // a. yes .. set to max
if (type) // q. black bits?
set_bits(p, pels, l); // a. yes .. set bits on
type = (type + 1) & 1; // switch back and forth
} // ..between black and white
f_get_eol(); // find the end of this line
if (NOT codes) // q. empty line?
{
eol++; // a. yes .. tally empty lines
if (eol == 6) // q. find the end of page?
break; // a. yes .. finish looping
}
else
eol = 0; // else .. clear EOL counter
}
return(0); // finally, return ok
}
/* ******************************************************************** *
*
* f_write_hdr() -- write a fax file header
*
* ******************************************************************** */
void f_write_hdr(void)
{
char buf[HDR_LEN]; // header buffer
memset(buf, 0, HDR_LEN); // clear buffer to nulls
strcpy(buf, "G3"); // ..and put in our marker
write(f_handle, buf, HDR_LEN); // write header
}
/* ******************************************************************** *
*
* f_write_out() -- write bits to output fax file
*
* ******************************************************************** */
void f_write_out(int bits, // output bits
int len) // ..and number of bits
{
static unsigned
char w; // byte wide queue
if (len > 16) // q. too many bits?
return; // a. yes .. just return
bits <<= 16 - len; // shift to MSB end of word
while (len--) // while there is input
{
w >>= 1; // shift queue over by one
if (bits & 0x8000) // q. source bit on?
w |= 0x80; // a. yes .. turn on dest
if (++f_write_flag == 8) // q. reach limit?
{
write(f_handle, (void *) &w, 1); // a. yes .. write a byte
if (w == DLE) // q. special character?
write(f_handle, (void *) &w, 1);// a. yes .. write it again
f_write_flag = 0; // clear the flag
f_write_cnt++; // ..and tally the byte
}
bits <<= 1; // shift source by one bit
}
}
/* ******************************************************************** *
*
* f_encode() -- encode a string of bits into G3 format
*
* ******************************************************************** */
void f_encode(int cnt, // number of bits from bitmap
int type) // ..and bit color
{
struct encode_entry *ee; // encode entry
if (cnt > 63) // q. big run of bits?
{
ee = &encode_table[(cnt / 64) + 63][type]; // a. yes .. get pointer
f_write_out(ee->code, ee->bits); // ..write make-up code
cnt %= 64; // ..and update bit count
}
ee = &encode_table[cnt][type]; // get element pointer
f_write_out(ee->code, ee->bits); // write terminating code
}
/* ******************************************************************** *
*
* f_scan_out() -- scan the bitmap and output a codeword
*
* ******************************************************************** */
int f_scan_out(char huge *p, // bitmap line
int i, // starting bit offset
int type) // type to search
{
int cnt; // work counter
for (cnt = 0; i < PELS; i++, cnt++) // scan bitmap line
if (get_bit( // q. find a bit which is not
(unsigned char *) p, i) != type)// ..the same as type?
break; // a. yes .. exit loop
f_encode(cnt, type); // build/output codeword
return(cnt); // ..then return with count
}
/* ******************************************************************** *
*
* f_write_page() -- write a fax file page
*
* ******************************************************************** */
void f_write_page(Window *w) // window to display msgs in
{
int i, j = 0, // loop counter
line, // line counter
type; // pixel type
char buf[60], // work buffer
huge *p; // ..and pointer
long start_pos, // page starting position
page_len; // ..and page length
static
long percent, // percent complete
last, // last display time
far *timer = (long far *) // BIOS timer tick counter
MK_FP(0x40, 0x6c); // ..down in low memory
lseek(f_handle, 0L, SEEK_END); // goto end of file
start_pos = tell(f_handle); // ..and get position info
memset(buf, 0, sizeof(buf)); // clear buffer to nulls
write(f_handle, buf, 4); // write page length
write(f_handle, buf, 10); // ..and some nulls
f_write_flag = 0; // clear output flag
f_write_out(1, 12); // ..and write an EOL
for (p = page, line = 0; line < LINES; // for each line in the bitmap
line++, p += LINE) // ..encode into G3 format
{
f_write_cnt = 0; // clear output byte count
if ((*timer - last) > 9) // q. has half a second past?
{
percent = (line * 100L) / LINES; // a. yes .. get percentage
sprintf(buf, write_msg, // build status message
f_pgcnt, percent); // ..into a work buffer
w->Display(buf); // ..display the message
last = *timer; // ..and pickup current time
}
if (reverse_scan((char *) p, 0, LINE)) // q. anything on line?
{ // a. yes .. process
for (i = type = 0; i < PELS; i += j)// scan across the bitmap line
{
j = f_scan_out(p, i, type); // scan bitmap for pixels
type = (type + 1) & 1; // flip-flop the type code
}
}
else
f_encode(1728, 0); // else .. put out blank line
if (f_write_flag) // q. any residual bits?
f_write_out(0, 8 - f_write_flag); // a. yes .. put out the rest
if (i < 40) // q. need to pad out line?
write(f_handle, (void *) &buf, // a. yes .. write a string
40 - i); // ..of up to 40 null bytes
f_write_out(1, 12); // then put out an EOL
}
for (i = 0; i < 5; i++) // at end of page
f_write_out(1, 12); // ..put out 5 more EOLs
buf[0] = DLE; // set up termination
buf[1] = ETX; // ..with DLE ETX
write(f_handle, buf, 2); // ..then put them out
page_len = tell(f_handle) - start_pos - 4; // compute page data length
lseek(f_handle, start_pos, SEEK_SET); // position to length field
write(f_handle, (void *) &page_len, 4); // ..and update field
}
/* ******************************************************************** *
*
* f_build_char() -- fill in bitmap position with a character
*
* ******************************************************************** */
void f_build_char(char cc, // character to use
int c, int r) // column and row
{
UINT *ce, // table entry pointer
i; // loop counter
char huge *p, // bitmap pointer
ch1, ch2; // high and low bytes
ce = &ascii_map[cc][0]; // get entry in table
p = &page[((r * 22L) * LINE) + (c * 2)]; // get starting point
for (i = 0; i < 11; i++, ce++) // for each of the chars rows
{
if (*ce) // q. anything to put in bitmap?
{ // a. yes .. process bits
ch1 = *ce >> 8; // get high order byte
ch2 = *ce & 0xff; // ..and low order byte
*p |= ch1; // "or" in each cols bits
*(p + 1) |= ch2; // ..for both bytes
p += LINE; // move to next line
*p |= ch1; // "or" in each cols bits
*(p + 1) |= ch2; // ..for both bytes
p += LINE; // move to next line
}
else
p += LINE * 2; // else .. skip two bitmap lines
}
}
/* ******************************************************************** *
*
* f_build_page() -- read an ASCII text file and build a bitmap
*
* returns: 0 = end of file reached
* n = characters encoded
*
* ******************************************************************** */
int f_build_page(FILE *f) // input file pointer
{
int i, // chars processed
lines, // lines counter
c, r, // column and row (0 based)
cc; // character buffer
char huge *p; // bitmap line pointer
for (lines = 0, p = page; // for the whole bitmap
lines < LINES; // ..run through line
lines++, p += LINE) // ..by line
memset(p, 0, LINE); // ..and clear white space
c = r = 0; // start column & row at top
for (i = 0; ; i++) // loop building bitmap
{
if ((cc = fgetc(f)) == EOF) // q. get a good character?
return(i); // a. no .. return w/count
f_build_char(cc, c, r); // bld bitmap at column & row
switch (cc) // update column & row
{
case LF: // line feed
if (++r >= ROWS) // q. reach bottom limit?
return(i); // a. yes .. then page is done
break; // else .. get next character
case CR: // carriage return
c = 0; // start at next beginning
break; // ..and get next character
case 12: // form feed
return(++i); // return w/nbr chars processed
case BACKSPACE: // backspace
if (--c < 0) // q. backup too far?
c = 0; // a. yes .. goto column 0
break; // else .. get next character
case TAB: // tab
c = (c & ~0x7) + 8; // move to next tab stop
if (c >= COLUMNS) // q. too far out?
{
c = 0; // a. yes .. just wrap around
if (++r >= ROWS) // q. reach bottom of page?
return(i); // a. yes .. stop here
}
break; // else .. get next character
default: // everything else
if (++c >= COLUMNS) // q. reach right margin?
{
c = 0; // a. yes .. just wrap around
if (++r >= ROWS) // q. reach bottom of page?
return(i); // a. yes .. stop here
}
}
}
return(0); // make MSC C/C++ happy
}
/* ******************************************************************** *
*
* f_build_fax() -- build a fax file from an ASCII text file
*
* ******************************************************************** */
void f_build_fax(char *f, // file name
Window *w) // window to update
{
FILE *fi; // input file
int i; // string index
char buf[60], buf2[60], // format buffers
*p; // ..and pointer
if (f_handle != -1) // q. already open?
{
close(f_handle); // a. yes .. close file
f_handle = -1; // ..and clear flag
}
if ((fi = fopen(f, "rb")) == 0) // q. open ok?
return; // a. no .. just return
strcpy(buf, f); // copy base filename
if ((p = strrchr(buf, '.')) == 0) // q. file extension found?
p = &buf[strlen(buf)]; // a. no .. point to end
strcpy(p, ".fax"); // copy in extension
if ((f_handle = open(buf, // q. open new file ok?
_O_BINARY | _O_TRUNC | _O_RDWR | _O_CREAT)) == -1)
return; // a. no .. just return
sprintf(buf2, create_msg, buf); // build display message
w->Display(buf2); // ..and send to user window
if ((i = 34 - (strlen(f) + // q. able to center the
strlen(status_conv) - 2)) < 0) // .."Converting: XXXX" msg?
i = 0; // a. no .. flush left
memset(buf2, ' ', sizeof(buf2)); // clear area to blanks
sprintf(&buf2[i / 2], status_conv, f); // format build information
status_line(status, buf2); // update status line
f_write_hdr(); // write header information
for (f_pgcnt = 1; ; f_pgcnt++) // loop building and writing
{
if (f_build_page(fi) == 0) // q. read ASCII ok?
break; // a. no .. end of file
f_write_page(w); // encode bitmap & write file
}
fclose(fi); // close input file
close(f_handle); // ..and output file
f_handle = -1; // ..and reset global
f_locate(buf); // set up to view/print file
sprintf(buf2, status_file, // format file information
buf, f_pgcnt); // ..for status line
if (f_pgcnt > 1) // q. more than 1 page fax?
strcat(buf2, "s"); // a. yes .. pluralize page
status_line(status, buf2); // update status line
}