"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "viewfax-2.6/faxinput.c" of archive viewfax-2.6.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /* Fax file input processing
2 Copyright (C) 1990, 1995, 2004 Frank D. Cringle.
3
4 This file is part of viewfax - g3/g4 fax processing software.
5
6 viewfax is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2 of the License, or (at your
9 option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28 #include <fcntl.h>
29 #include "faxexpand.h"
30
31 #define FAXMAGIC "\000PC Research, Inc\000\000\000\000\000\000"
32
33 enum { Tbyte=1, Tascii, Tshort, Tlong, Trational };
34 static char *typeStr[] = {
35 "undef", "BYTE", "ASCII", "SHORT", "LONG", "RATIONAL" };
36
37 static char *Filename;
38 static int warned;
39
40 static int
41 errwarn(int err) {
42 if (!(err || verbose)) return 0;
43 if (!warned) {
44 fprintf(stderr, "%s: %s: errors (E), warnings (W), info (I)\n",
45 ProgName, Filename);
46 warned = 1;
47 }
48 return 1;
49 }
50
51 /* Enter an argument in the linked list of pages */
52 struct pagenode *
53 notefile(char *name)
54 {
55 struct pagenode *new = (struct pagenode *) xmalloc(sizeof *new);
56
57 *new = defaultpage;
58 if (firstpage == NULL)
59 firstpage = new;
60 new->prev = lastpage;
61 new->next = NULL;
62 new->pageno = 1;
63 if (lastpage != NULL) {
64 lastpage->next = new;
65 new->pageno = lastpage->pageno + 1;
66 }
67 lastpage = new;
68 new->pathname = name;
69 if ((new->name = strrchr(new->pathname, '/')) != NULL)
70 new->name++;
71 else
72 new->name = new->pathname;
73 if (new->width == 0)
74 new->width = 1728;
75 if (new->vres > 1)
76 new->vres = !(new->name[0] == 'f' && new->name[1] == 'n');
77 new->extra = NULL;
78 return new;
79 }
80
81 static t32bits
82 get4(unsigned char *p, int endian)
83 {
84 return endian ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] :
85 p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
86 }
87
88 static int
89 get2(unsigned char *p, int endian)
90 {
91 return endian ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8);
92 }
93
94 static int
95 showtag(FILE *tf, int ftype, int count, t32bits pos, char *tagname)
96 {
97 int ch;
98
99 if ((ftype != Tascii) && errwarn(1)) {
100 fprintf(stderr, "[W] %s: expected ascii tag, found %d\n",
101 tagname, ftype);
102 return 0;
103 }
104 if (fseek(tf, pos, SEEK_SET) == -1)
105 return -1;
106 fprintf(stderr, "[I] %s: ", tagname);
107 while (count--) {
108 if ((ch = fgetc(tf)) == EOF)
109 return -1;
110 if (ch == 0)
111 break;
112 if ((ch < ' ') || (ch > '~'))
113 ch = '?';
114 fputc(ch, stderr);
115 }
116 if (count)
117 fputs(" <short!>", stderr);
118 if (ch)
119 fputs(" <long!>", stderr);
120 fputc('\n', stderr);
121 return 0;
122 }
123
124 /* generate pagenodes for the images in a tiff file */
125 int
126 notetiff(char *name)
127 {
128 FILE *tf;
129 unsigned char header[8];
130 static const char littleTIFF[4] = "\x49\x49\x2a\x00";
131 static const char bigTIFF[4] = "\x4d\x4d\x00\x2a";
132 int endian;
133 t32bits IFDoff;
134 struct pagenode *pn = NULL;
135
136 if ((tf = fopen(name, "r")) == NULL) {
137 perror(name);
138 return 0;
139 }
140
141 if (fread(header, 8, 1, tf) == 0) {
142 nottiff:
143 fclose(tf);
144 (void) notefile(name);
145 return 0;
146 }
147 if (memcmp(header, &littleTIFF, 4) == 0)
148 endian = 0;
149 else if (memcmp(header, &bigTIFF, 4) == 0)
150 endian = 1;
151 else
152 goto nottiff;
153 IFDoff = get4(header+4, endian);
154 if (IFDoff & 1)
155 goto nottiff;
156 Filename = name;
157 warned = 0;
158 do { /* for each page */
159 unsigned char buf[8];
160 unsigned char *dir = NULL;
161 unsigned char *dp;
162 int ndirent;
163 pixnum iwidth = defaultpage.width ? defaultpage.width : 1728;
164 pixnum iheight = defaultpage.height ? defaultpage.height : 2339;
165 int inverse = defaultpage.inverse;
166 int lsbfirst = 0;
167 int t4opt = 0, comp = 0;
168 int orient = defaultpage.orient;
169 double yres = defaultpage.vres ? 196.0 : 98.0;
170 double xres;
171 struct strip *strips = NULL;
172 unsigned long rowsperstrip = 0;
173 int nstrips = 1;
174
175 if (fseek(tf, IFDoff, SEEK_SET) < 0) {
176 realbad:
177 errwarn(1);
178 fputs("[E] invalid tiff file\n", stderr);
179 bad:
180 if (strips)
181 free(strips);
182 if (dir)
183 free(dir);
184 fclose(tf);
185 Filename = NULL;
186 warned = 0;
187 return 1;
188 }
189 if (fread(buf, 2, 1, tf) == 0)
190 goto realbad;
191 ndirent = get2(buf, endian);
192 dir = (unsigned char *) xmalloc(12*ndirent+4);
193 if (fread(dir, 12*ndirent+4, 1, tf) == 0)
194 goto realbad;
195 for (dp = dir; ndirent; ndirent--, dp += 12) {
196 /* for each directory entry */
197 int tag, ftype;
198 t32bits count, value = 0;
199 tag = get2(dp, endian);
200 ftype = get2(dp+2, endian);
201 count = get4(dp+4, endian);
202 switch(ftype) { /* value is offset to list if count*size > 4 */
203 case Tbyte:
204 break;
205 case Tascii:
206 if (count <= 4)
207 value = IFDoff + 10 + dp - dir;
208 else { /* calc offset but don't read unless later used */
209 value = get4(dp+8, endian);
210 }
211 break;
212 case Tshort:
213 value = get2(dp+8, endian);
214 break;
215 case Tlong:
216 value = get4(dp+8, endian);
217 break;
218 case Trational:
219 value = get4(dp+8, endian);
220 break;
221 default:
222 errwarn(1);
223 fprintf(stderr, "[E] unknown ftype %d\n", ftype);
224 break;
225 }
226 switch(tag) {
227 case 254: /* NewSubFileType */
228 if (errwarn(0))
229 fprintf(stderr, "[I] NewSubfile(%d) = %lu\n",
230 tag, (unsigned long) value);
231 break;
232 case 256: /* ImageWidth */
233 iwidth = value;
234 break;
235 case 257: /* ImageLength */
236 iheight = value;
237 break;
238 case 258: /* BitsPerSample */
239 if ((value != 1) && errwarn(1))
240 fprintf(stderr, "[E] ignored Bits/Sample(%d) = %lu\n",
241 tag, (unsigned long) value);
242 break;
243 case 259: /* Compression */
244 comp = value;
245 break;
246 case 262: /* PhotometricInterpretation */
247 inverse ^= (value == 1);
248 break;
249 case 266: /* FillOrder */
250 lsbfirst = (value == 2);
251 break;
252 case 269: /* DocumentName */
253 if (verbose) {
254 if (showtag(tf, ftype, count, value, "DocumentName") < 0)
255 goto realbad;
256 }
257 break;
258 case 270: /* ImageDescription */
259 if (verbose) {
260 if (showtag(tf, ftype, count, value,
261 "ImageDescription") < 0)
262 goto realbad;
263 }
264 break;
265 case 271: /* Make */
266 if (verbose) {
267 if (showtag(tf, ftype, count, value, "Make") < 0)
268 goto realbad;
269 }
270 break;
271 case 272: /* Model */
272 if (verbose) {
273 if (showtag(tf, ftype, count, value, "Model") < 0)
274 goto realbad;
275 }
276 break;
277 case 273: /* StripOffsets */
278 nstrips = count;
279 strips = (struct strip *) xmalloc(count * sizeof *strips);
280 if (count == 1 || (count == 2 && ftype == 3)) {
281 strips[0].offset = value;
282 if (count == 2)
283 strips[1].offset = get2(dp+10, endian);
284 break;
285 }
286 if (fseek(tf, value, SEEK_SET) < 0)
287 goto realbad;
288 for (count = 0; count < nstrips; count++) {
289 if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
290 goto realbad;
291 strips[count].offset = (ftype == 3) ?
292 get2(buf, endian) : get4(buf, endian);
293 }
294 break;
295 case 274: /* Orientation */
296 switch(value) {
297 default: /* row0 at top, col0 at left */
298 orient = 0;
299 break;
300 case 2: /* row0 at top, col0 at right */
301 orient = TURN_M;
302 break;
303 case 3: /* row0 at bottom, col0 at right */
304 orient = TURN_U;
305 break;
306 case 4: /* row0 at bottom, col0 at left */
307 orient = TURN_U|TURN_M;
308 break;
309 case 5: /* row0 at left, col0 at top */
310 orient = TURN_M|TURN_L;
311 break;
312 case 6: /* row0 at right, col0 at top */
313 orient = TURN_U|TURN_L;
314 break;
315 case 7: /* row0 at right, col0 at bottom */
316 orient = TURN_U|TURN_M|TURN_L;
317 break;
318 case 8: /* row0 at left, col0 at bottom */
319 orient = TURN_L;
320 break;
321 }
322 break;
323 case 277: /* SamplesPerPixel */
324 if ((value != 1) && errwarn(1))
325 fprintf(stderr, "[I] ignored Sample/Pixel(%d) = %lu\n",
326 tag, (unsigned long) value);
327 break;
328 case 278: /* RowsPerStrip */
329 rowsperstrip = value;
330 break;
331 case 279: /* StripByteCounts */
332 if ((count != nstrips) && errwarn(1)) {
333 fprintf(stderr,
334 "[E] StripsPerImage tag273=%d, tag279=%ld\n",
335 nstrips, count);
336 goto realbad;
337 }
338 if (count == 1 || (count == 2 && ftype == 3)) {
339 strips[0].size = value;
340 if (count == 2)
341 strips[1].size = get2(dp+10, endian);
342 break;
343 }
344 if (fseek(tf, value, SEEK_SET) < 0)
345 goto realbad;
346 for (count = 0; count < nstrips; count++) {
347 if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
348 goto realbad;
349 strips[count].size = (ftype == 3) ?
350 get2(buf, endian) : get4(buf, endian);
351 }
352 break;
353 case 282: /* XResolution */
354 if (fseek(tf, value, SEEK_SET) < 0 ||
355 fread(buf, 8, 1, tf) == 0)
356 goto realbad;
357 xres = get4(buf, endian) / get4(buf+4, endian);
358 if ((xres != 204) && errwarn(0))
359 fprintf(stderr, "[W] ignored Xres(%d) = %7.2f (ns)\n",
360 tag, xres);
361 break;
362 case 283: /* YResolution */
363 if (fseek(tf, value, SEEK_SET) < 0 ||
364 fread(buf, 8, 1, tf) == 0)
365 goto realbad;
366 yres = get4(buf, endian) / get4(buf+4, endian);
367 break;
368 case 284: /* PlanarConfiguration */
369 if ((value != 1) && errwarn(0))
370 fprintf(stderr, "[W] ignored PlanarConfig(%d) = %lu\n",
371 tag, (unsigned long) value);
372 break;
373 case 285: /* PageName */
374 case 286: /* XPosition */
375 case 287: /* YPosition */
376 if (errwarn(0))
377 fprintf(stderr,
378 "[W] ignored storage & retrieval tag (%d)\n", tag);
379 break;
380 case 292: /* T4Options */
381 t4opt = value;
382 break;
383 case 293: /* T6Options */
384 if ((value != 0) && errwarn(1))
385 fprintf(stderr, "[W] ignored T6Options(%d) = %lu\n",
386 tag, (unsigned long) value);
387 break;
388 case 296: /* ResolutionUnit */
389 if (value == 3)
390 yres *= 2.54;
391 break;
392 case 297: /* PageNumber */
393 if (errwarn(0))
394 fprintf(stderr, "[I] PageNumber(%d) = %lu/%d\n",
395 tag, (unsigned long) value, get2(dp+10, endian));
396 break;
397 case 305: /* Software */
398 if (errwarn(0)) {
399 if (showtag(tf, ftype, count, value, "Software") < 0)
400 goto realbad;
401 }
402 break;
403 case 306: /* DateTime */
404 if (errwarn(0)) {
405 if (showtag(tf, ftype, count, value, "DateTime") < 0)
406 goto realbad;
407 }
408 break;
409 case 315: /* Artist */
410 if (errwarn(0)) {
411 if (showtag(tf, ftype, count, value, "Artist") < 0)
412 goto realbad;
413 }
414 break;
415 case 316: /* HostComputer */
416 if (errwarn(0)) {
417 if (showtag(tf, ftype, count, value, "HostComputer") < 0)
418 goto realbad;
419 }
420 break;
421 case 320: /* ColorMap */
422 if (errwarn(0))
423 fprintf(stderr, "[W]ignored ColorMap(%d) = %lu\n",
424 tag, (unsigned long) value);
425 break;
426 case 326: /* BadFaxLines */
427 case 327: /* CleanFaxData */
428 case 328: /* ConsecutiveBadFaxLines */
429 if ((value != 0) && errwarn(0))
430 fprintf(stderr, "[I] quality(%d) = %lu\n", tag,
431 (unsigned long) value);
432 break;
433 default:
434 if (errwarn(0)) {
435 fprintf(stderr, "[W] unknown tag %d: #%lu %s",
436 tag, (unsigned long) count, typeStr[ftype]);
437 if ((ftype == Tshort) || (ftype == Tlong))
438 fprintf(stderr, " = %lu", (unsigned long) value);
439 fprintf(stderr, "\n");
440 }
441 break;
442 }
443 }
444 IFDoff = get4(dp, endian);
445 free(dir);
446 dir = NULL;
447 if ((iwidth * iheight == 0) && errwarn(1)) {
448 fprintf(stderr,
449 "[E] fax width x height (%lu x %lu) must be non-zero\n",
450 (unsigned long) iwidth, (unsigned long) iheight);
451 goto bad;
452 }
453 if ((comp < 2 || comp > 4) && errwarn(1)) {
454 fprintf(stderr, "[E] compression=%d unsupported\n", comp);
455 goto bad;
456 }
457 pn = notefile(name);
458 pn->nstrips = nstrips;
459 pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight;
460 pn->strips = strips;
461 pn->width = iwidth;
462 pn->height = iheight;
463 pn->inverse = inverse;
464 pn->lsbfirst = lsbfirst;
465 pn->orient = orient;
466 pn->vres = (yres > 150); /* arbitrary threshold for fine resolution */
467 if (comp == 2)
468 pn->expander = MHexpand;
469 else if (comp == 3)
470 pn->expander = (t4opt & 1) ? g32expand : g31expand;
471 else
472 pn->expander = g4expand;
473 } while (IFDoff);
474 fclose(tf);
475 Filename = NULL;
476 warned = 0;
477 return 1;
478 }
479
480 /* report error and remove bad file from the list */
481 static void
482 badfile(struct pagenode *pn)
483 {
484 struct pagenode *p;
485
486 if (errno)
487 perror(pn->pathname);
488 if (pn == firstpage) {
489 if (pn->next == NULL)
490 exit(1);
491 firstpage = thispage = firstpage->next;
492 firstpage->prev = NULL;
493 }
494 else
495 for (p = firstpage; p; p = p->next)
496 if (p->next == pn) {
497 thispage = p;
498 p->next = pn->next;
499 if (pn->next)
500 pn->next->prev = p;
501 break;
502 }
503 if (pn) free(pn);
504 }
505
506 /* rearrange input bits into t16bits lsb-first chunks */
507 static void
508 normalize(struct pagenode *pn, int revbits, int swapbytes, size_t length)
509 {
510 t32bits *p = (t32bits *) pn->data;
511
512 switch ((revbits<<1)|swapbytes) {
513 case 0:
514 break;
515 case 1:
516 for ( ; length; length -= 4) {
517 t32bits t = *p;
518 *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
519 }
520 break;
521 case 2:
522 for ( ; length; length -= 4) {
523 t32bits t = *p;
524 t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
525 t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
526 *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
527 }
528 break;
529 case 3:
530 for ( ; length; length -= 4) {
531 t32bits t = *p;
532 t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
533 t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
534 t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
535 *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
536 }
537 break;
538 default:
539 fprintf(stderr, "%s: unknown rev %d\n",
540 ProgName, (revbits<<1)|swapbytes);
541 break;
542 }
543 }
544
545
546 /* get compressed data into memory */
547 unsigned char *
548 getstrip(struct pagenode *pn, int strip)
549 {
550 int fd, n;
551 size_t offset, roundup;
552 struct stat sbuf;
553 unsigned char *Data;
554 union { t16bits s; unsigned char b[2]; } so;
555 #define ShortOrder so.b[1]
556
557 so.s = 1;
558 if ((fd = open(pn->pathname, O_RDONLY, 0)) < 0) {
559 badfile(pn);
560 return NULL;
561 }
562
563 if (pn->strips == NULL) {
564 if (fstat(fd, &sbuf) != 0) {
565 close(fd);
566 badfile(pn);
567 return NULL;
568 }
569 offset = 0;
570 pn->length = sbuf.st_size;
571 }
572 else if (strip < pn->nstrips) {
573 offset = pn->strips[strip].offset;
574 pn->length = pn->strips[strip].size;
575 }
576 else {
577 fprintf(stderr, "%s:%s: trying to expand too many strips\n",
578 ProgName, pn->pathname);
579 close(fd);
580 badfile(pn);
581 return NULL;
582 }
583 if (!pn->length) {
584 fprintf(stderr, "%s:%s: trying to expand a null strip\n",
585 ProgName, pn->pathname);
586 close(fd);
587 badfile(pn);
588 return NULL;
589 }
590
591 /* round size to full boundary plus t32bits */
592 roundup = (pn->length + 7) & ~3;
593
594 Data = (unsigned char *) xmalloc(roundup);
595 /* clear the last 2 t32bits, to force the expander to terminate
596 even if the file ends in the middle of a fax line */
597 *((t32bits *) Data + roundup/4 - 2) = 0;
598 *((t32bits *) Data + roundup/4 - 1) = 0;
599
600 /* we expect to get it in one gulp... */
601 if (lseek(fd, offset, SEEK_SET) < 0 ||
602 (n = read(fd, Data, pn->length)) != pn->length) {
603 fprintf(stderr, "%s: expected %d bytes, got %d\n",
604 pn->pathname, pn->length, n);
605 badfile(pn);
606 free(Data);
607 close(fd);
608 return NULL;
609 }
610 close(fd);
611
612 pn->data = (t16bits *) Data;
613 if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)) == 0) {
614 /* handle ghostscript / PC Research fax file */
615 if (Data[24] != 1 || Data[25] != 0)
616 printf("%s: only first page of multipage file %s will be shown\n",
617 ProgName, pn->pathname);
618 pn->length -= 64;
619 pn->vres = Data[29] ? 1 : 0;
620 pn->data += 32;
621 roundup -= 64;
622 }
623
624 normalize(pn, !pn->lsbfirst, ShortOrder, roundup);
625 if (pn->height == 0)
626 pn->height = G3count(pn, pn->expander == g32expand);
627 if (pn->height == 0) {
628 fprintf(stderr, "%s: no fax found in file %s\n", ProgName,
629 pn->pathname);
630 errno = 0;
631 badfile(pn);
632 free(Data);
633 return NULL;
634 }
635 if (pn->strips == NULL)
636 pn->rowsperstrip = pn->height;
637 if (verbose && strip == 0)
638 printf("%s:\n\twidth = %lu\n\theight = %lu\n\tresolution = %s\n",
639 pn->name, (unsigned long) pn->width, (unsigned long) pn->height,
640 pn->vres ? "fine" : "normal");
641 return Data;
642 }