OSDN Git Service

0ad4617234deb086e9826703333b0344ed88df3d
[putex/putex.git] / src / dvisourc / dvitiff.c
1 /* Copyright 1994,1995,1996,1997,1998,1999 Y&Y, Inc.\r
2    Copyright 2007 TeX Users Group\r
3    Copyright 2014 Clerk Ma\r
4 \r
5    This program is free software; you can redistribute it and/or modify\r
6    it under the terms of the GNU General Public License as published by\r
7    the Free Software Foundation; either version 2 of the License, or\r
8    (at your option) any later version.\r
9 \r
10    This program is distributed in the hope that it will be useful, but\r
11    WITHOUT ANY WARRANTY; without even the implied warranty of\r
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
13    General Public License for more details.\r
14 \r
15    You should have received a copy of the GNU General Public License\r
16    along with this program; if not, write to the Free Software\r
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
18    02110-1301 USA.  */\r
19 \r
20 \r
21 /****************************************************************************/\r
22 /* Make PS code from TIFF image file 1, 2, 4, 8 bit pixels only */\r
23 /* Support palette color images => expands to RGB */\r
24 /* Support 24 bit color images converts RBG to gray if colorimage not avail */\r
25 /* Supports: input side - no compression, TIFF_CCITT, LZW, and PACK_BITS */\r
26 /* Does not support BitsPerSample other than power of 2 */\r
27 /* Does not support compression schemes 3 and 4 (CCITT) */\r
28 /* Supports: output side - no compression, ASCII85, LZW, and PACK_BITS */\r
29 /****************************************************************************/\r
30 \r
31 /* Also, code for some other DVIWindo \specials */\r
32 \r
33 /* Revised 1999 June 13 to run in DLL form */\r
34 \r
35 #ifdef _WINDOWS\r
36   #define NOCOMM\r
37   #define NOSOUND\r
38   #define NODRIVERS\r
39   #define STRICT\r
40   #include <windows.h>\r
41 #endif\r
42 \r
43 #include <stdio.h>\r
44 #include <stdlib.h>\r
45 #include <string.h>\r
46 #include <malloc.h>\r
47 #include <setjmp.h>\r
48 \r
49 #ifdef _WINDOWS\r
50   // We must define MYLIBAPI as __declspec(dllexport) before including\r
51   // dvipsone.h, then dvipsone.h will see that we have already\r
52   // defined MYLIBAPI and will not (re)define it as __declspec(dllimport)\r
53   #define MYLIBAPI __declspec(dllexport)\r
54   // #include "dvipsone.h"\r
55 #endif\r
56 \r
57 #include "dvipsone.h"\r
58 \r
59 #ifdef _WINDOWS\r
60   #pragma warning(disable:4100) // unreferenced formal variable \r
61 #endif\r
62 \r
63 #pragma warning(disable:4996)\r
64 #pragma warning(disable:4127) // conditional expression is constant\r
65 \r
66 #pragma hdrstop\r
67 \r
68 #include <time.h>\r
69 \r
70 #include "dvispeci.h"\r
71 \r
72 #define DEBUGTIFF         /* to get in extra tracing code */\r
73 \r
74 /* #define DEBUGBMP */\r
75 \r
76 /* #define DEBUGLZWENCODE */\r
77 \r
78 /* #define DEBUGRUNLENGTH */\r
79 \r
80 /* #define DEBUGCLEANUP */\r
81 \r
82 #define PSLEVEL2\r
83 \r
84 #define LZWCOMPRESSION\r
85 \r
86 #define MAXCOLUMNHEX 72\r
87 \r
88 #define MAXCOLUMNASCII 75\r
89 \r
90 #ifdef TIFF\r
91 \r
92 /* constants for LZW compression/decompression tables */\r
93 \r
94 #define MAXCODES  4096 /* to deal with up to 12 bit codes */\r
95 #define MAXCHR    256  /* 2^8 possible bytes */\r
96 #define CLEAR     256  /* clear string table code */\r
97 #define EOD       257  /* end of data code */\r
98 #define FIRSTCODE 258  /* first code available - new string */\r
99 \r
100 #ifdef PSLEVEL2\r
101   int bRunLengthFlag;   /* Use RunLengthDecode filter 96/Dec/24 */\r
102   #ifdef LZWCOMPRESSION\r
103   int bLZWFlag;         /* Use LZWDecode filter 96/Dec/30 */\r
104   #endif\r
105 /*  can have either of the above set, or none, but not both */\r
106 #endif\r
107 \r
108 unsigned char *StripData;  /* address of Strip Buffer */\r
109 \r
110 unsigned int StripDataLen; /* length of Strip Buffer */\r
111 \r
112 long InStripLen;        /* length of Strip in file 96/Nov/17 */\r
113 \r
114 typedef int BOOL;\r
115 \r
116 char infilename[FILENAME_MAX] = "";\r
117 \r
118 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
119 \r
120 /* using definitions in dvispeci.h */\r
121 \r
122 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
123 \r
124 /* #define MAXIMAGE 4096 */   /* maximum rows & columns - sanity check */\r
125 \r
126 #define MAXIMAGE 65536    /* maximum rows & columns - sanity check */\r
127 \r
128 BOOL bInvertImage   = 0;  /* should gray levels be inverted ? */\r
129 BOOL bColorImage    = 0;  /* is it a color image ? */\r
130                           /* i.e. RGB or color palette */\r
131 BOOL bExpandColor   = 0;  /* color palette image - expand to 24 bit */\r
132                           /* set when ColorMapPtr non-NULL */\r
133 BOOL bCompressColor = 0;  /* compress 24 bit color to one byte */\r
134                           /* for non-color PS output device ? */\r
135                           /* and for BMP with gray palette */\r
136 BOOL bExpandGray    = 0;  /* has Palette, but Palette is gray */\r
137 BOOL bGrayFlag      = 0;  /* non-zero if Palette is gray BMP palette */\r
138 BOOL bLinearFlag    = 0;  /* non-zero if palette is linear BMP palette */\r
139 int PaletteSize     = 0;  /* number of entries in palette */\r
140 \r
141 /* For Windows NT could declare USESHORTINT since 16 bit quantities */\r
142 \r
143 /* #define USESHORTINT */\r
144 \r
145 #ifdef USESHORTINT\r
146 unsigned short int *Palette = NULL; /* pointer to palette */\r
147 #else\r
148 unsigned int *Palette = NULL;       /* pointer to palette */\r
149 #endif\r
150 \r
151 /* char *eps_magic = "\\r
152 currentscreen pop\n\\r
153 {1 add 180 mul cos 1 0.08 add mul exch 2 add 180 mul cos 1 0.08 sub\n\\r
154 mul add 2 div} bind setscreen % Copyright (C) Y&Y 1989\n\\r
155 "; */\r
156 \r
157 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
158 \r
159 /* set to 0.0 0.0 0.0 at top of page ? */\r
160 \r
161 int bTextColor=0;\r
162 \r
163 double textred=0.0;     /* color of text */\r
164 double textgreen=0.0;\r
165 double textblue=0.0;\r
166 \r
167 int bRuleColor=0;\r
168 \r
169 double rulered=0.0;     /* color of rules */\r
170 double rulegreen=0.0;\r
171 double ruleblue=0.0;\r
172 \r
173 int bFigureColor=0;     /* figure color has been specified */\r
174 \r
175 double figurered=0.0;   /* foreground of figure */\r
176 double figuregreen=0.0;\r
177 double figureblue=0.0;\r
178 \r
179 double backred=1.0;     /* background of figure */\r
180 double backgreen=1.0;\r
181 double backblue=1.0;\r
182 \r
183 int bReverseVideo=0;\r
184 \r
185 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
186 \r
187 /* Some code imported from DVIWindo winspeci.c */\r
188 \r
189 /* Stuff for reading simple uncompressed TIFF files (& PackBits compressed) */\r
190 \r
191 unsigned int TIFFVersion;     /* TIFF version number */\r
192 unsigned int bLeastFirst=1;     /* least significant first */\r
193 unsigned int IFDCount;        /* number of items image file directory */\r
194 unsigned long IFDPosition;      /* position of image file directory */\r
195 \r
196 //#pragma optimize ("lge", off)\r
197 \r
198 /* static unsigned short int ureadtwo(FILE *input) {\r
199   unsigned short int c, d;\r
200   c = (unsigned short int) getc(input);\r
201   d = (unsigned short int) getc(input); \r
202   if (bLeastFirst != 0) return ((d << 8) | c);\r
203   else return ((c << 8) | d);\r
204 } */\r
205 \r
206 static unsigned int ureadtwo(FILE *input)\r
207 {\r
208   unsigned int c, d;\r
209   c = (unsigned int) getc(input);\r
210   d = (unsigned int) getc(input);\r
211   if (bLeastFirst != 0)\r
212     return ((d << 8) | c);\r
213   else\r
214     return ((c << 8) | d);\r
215 }\r
216 \r
217 static unsigned long ureadfour(FILE *input)\r
218 {\r
219   unsigned long c, d, e, f;\r
220   c = (unsigned long) getc(input);\r
221   d = (unsigned long) getc(input);\r
222   e = (unsigned long) getc(input);\r
223   f = (unsigned long) getc(input);\r
224   if (bLeastFirst != 0)\r
225     return ((((((f << 8) | e) << 8) | d) << 8) | c);\r
226   else\r
227     return ((((((c << 8) | d) << 8) | e) << 8) | f);\r
228 }\r
229 \r
230 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
231 \r
232 /* char *typename[6] = {"", "BYTE ", "ASCII", "SHORT", "LONG ", "RATIO"}; */\r
233 \r
234 int typesize[6] = {0, 1, 1, 2, 4, 8};   /* units of length/count */\r
235 \r
236 unsigned long TIFFOffset, TIFFLength;\r
237 \r
238 long PSOffset, PSLength, MetaOffset, MetaLength; /* not used ? */\r
239 \r
240 /* we are ignoring the possibility here that length > 1 and such ... */\r
241 \r
242 long indirectvalue (unsigned int type, long length, long offset, FILE *input)\r
243 {\r
244   long present, val=0;\r
245 \r
246 /*  UNUSED (length); */\r
247 #ifdef DEBUGTIFF\r
248   if (length > 1 && traceflag)\r
249   {\r
250     sprintf(logline, "Length %d\n", length);\r
251     showline(logline, 0);\r
252   }\r
253 #endif\r
254   present = ftell(input);     /* remember where we are */\r
255   if (fseek(input, (long) (offset + TIFFOffset), SEEK_SET) != 0)\r
256   {\r
257     sprintf(logline, " Error in seek %s\n", " to indirect value\n");\r
258     showline(logline, 1);\r
259   }\r
260   if (type == TYPE_LONG) val = (long) ureadfour(input);\r
261   else if (type == TYPE_SHORT) val = ureadtwo(input);\r
262   else if (type == TYPE_BYTE) val = getc(input);\r
263   else showline(" Invalid Indirect Value\n", 1);\r
264   fseek(input, present, SEEK_SET);  /* return to where we were */\r
265   return val;\r
266 }\r
267 \r
268 /* get value of a tag field in TIFF file */\r
269 \r
270 long extractvalue (unsigned int type, unsigned long length, long offset, FILE *input)\r
271 {\r
272   if (length == 0)\r
273     return 0;\r
274 \r
275   switch(type)\r
276   {\r
277     case TYPE_BYTE:\r
278       if (length <= 4)\r
279         return offset;\r
280       else\r
281         return indirectvalue(type, (long) length, (long) offset, input);\r
282     case TYPE_SHORT:\r
283       if (length <= 2)\r
284         return offset;\r
285       else\r
286         return indirectvalue(type, (long) length, (long) offset, input);\r
287     case TYPE_LONG:\r
288       if (length == 1)\r
289         return offset;\r
290       else\r
291         return indirectvalue(type, (long) length, (long) offset, input);\r
292     default:\r
293       return -1;\r
294   }\r
295 }\r
296 \r
297 int skipthisimage (FILE *input, unsigned long ifdpos)\r
298 {\r
299   int k, j;\r
300 \r
301   if(fseek(input, (long) ifdpos + TIFFOffset, SEEK_SET) != 0)\r
302   {\r
303     sprintf(logline, " Error in seek %s\n", " while skipping image\n");\r
304     showline(logline, 1);\r
305     return -1;\r
306   }\r
307   IFDCount = ureadtwo(input);     /* How many tags in this IFD */\r
308   for (k = 0; k < (int) IFDCount; k++)  /* read to end of IFD */\r
309   {\r
310     for (j = 0; j < 12; j++)\r
311       (void) getc(input);\r
312   }\r
313   IFDPosition = ureadfour(input);   /* get next IFD offset in file */\r
314   if (IFDPosition == 0) return -1;      /*  no more IFDs !!! */\r
315   else return 0;\r
316 }\r
317 \r
318 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
319 \r
320 /* Must have: ImageWidth, ImageLength, StripOffset, SamplesPerPixel, BitsPerSample */\r
321 \r
322 long ImageWidth;            /* vital ImageWidth */\r
323 long ImageLength;           /* vital ImageLength */\r
324 \r
325 int bytes;                /* total bytes per row output used ? */\r
326 \r
327 int SamplesPerPixel = 1;        /* vital (may be more than 1) */\r
328 int SamplesPerPixelX = 1;       /* SamplesPerPixel-ExtraSamples */\r
329 \r
330 int BitsPerSample = 1;          /* vital */\r
331 \r
332 int ExtraSamples = 0;         /* new 99/May/10 */\r
333 \r
334 unsigned int compression = 0;     /* vital */\r
335 int Orientation = 1;\r
336 int Predictor = 1;            /* for LZW only */\r
337                     /* 2 implies differencing applied */\r
338 long StripOffset = -1;          /* vital (first strip offset) */\r
339 long StripOffsetsPtr;\r
340 int StripOffsetsType;\r
341 int StripOffsetsLength;\r
342 \r
343 long StripByteCount = -1;       /* first StripByteCount */\r
344 long StripByteCountsPtr;\r
345 int StripByteCountsType;\r
346 int StripByteCountsLength;\r
347 \r
348 int RowsPerStrip = 0;\r
349 \r
350 int StripsPerImage;           /* computed from above */\r
351 \r
352 long ColorMapPtr = 0; /* pointer to map in case of Palette Color Images */\r
353 \r
354 int PhotometricInterpretation = 1;  /* default */\r
355 \r
356 int PlanarConfig=1;   /* cannot handle 2 ... */\r
357 \r
358 int BitsPerPixel;   /* BitsPerSample * SamplePerPixel */\r
359 int BitsPerPixelX;    /* BitsPerSample * (SamplePerPixel-ExtraSamples) */\r
360 \r
361 long InRowLength;     /* number of source bytes from file */\r
362 long InRowLengthX;    /* --- after ExtraSamples removed */\r
363 \r
364 long InRowRead;     /* bytes to read from input */\r
365 long BufferLength;    /* number of bytes of intermediate data */\r
366             /* length of lpBuffer allocated space */\r
367 long OutRowLength;    /* number of processed bytes for output */\r
368 \r
369 int CurrentStrip;   /* for debugging purposes */\r
370 \r
371 /* NOTE: MinSampleValue and MaxSampleValue should not affect appearance */\r
372 \r
373 /* int MinSampleValue, MaxSampleValue;  */    /* never used ? */\r
374 \r
375 int ResolutionUnit=2;   /* 1 no dimensions, 2 per inch, 3 per cm */\r
376 \r
377 /* long xresnum, xresden; */    /* x resolution */\r
378 /* long yresnum, yresden; */    /* y resolution */\r
379 \r
380 unsigned long xresnum, xresden;   /* x resolution */  /* 95/Oct/10 */\r
381 unsigned long yresnum, yresden;   /* y resolution */  /* 95/Oct/10 */\r
382 \r
383 int hptagflag=0;          /* non-zero if call from HPTAG */\r
384 /* may need something more elaborate hleft / hright and vhigh / vlow */\r
385 \r
386 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
387 \r
388 /* read the tag fields in the TIFF file, ignore ones we don't care about */\r
389 \r
390 int readfields (FILE *input, unsigned long ifdpos)\r
391 {\r
392   unsigned int k, tag, type;\r
393   unsigned long length, offset;\r
394   int c;\r
395 \r
396 #ifdef DEBUGTIFF\r
397   if (traceflag) showline("Now reading TIFF images fields\n", 0);\r
398 #endif\r
399 \r
400   if (fseek(input, (long) ifdpos + TIFFOffset, SEEK_SET) != 0)\r
401   {\r
402     sprintf(logline, " Error in seek %s\n", " while reading tags");\r
403     showline(logline, 1);\r
404     return -1;\r
405   }\r
406   IFDCount = ureadtwo(input);     /* How many tags in this IFD */\r
407   \r
408   ImageWidth = ImageLength = -1;\r
409   SamplesPerPixel = BitsPerSample = 1;\r
410   ExtraSamples = compression = 0;\r
411   Orientation = 1;\r
412   StripOffset = StripByteCount = -1;\r
413   RowsPerStrip = 0;\r
414   PhotometricInterpretation = 1;  /* default */\r
415   PlanarConfig = Predictor = 1;\r
416   ColorMapPtr = 0;  /* pointer to map in case of Palette Color Images */\r
417 /*  MinSampleValue = -1; MaxSampleValue = -1; */\r
418 /*  xresnum = yresnum = 72; */\r
419   xresnum = yresnum = nDefaultTIFFDPI;\r
420   xresden = yresden = 1;\r
421   ResolutionUnit = 2; \r
422 \r
423   for (k = 0; k < IFDCount; k++)\r
424   {\r
425     tag = ureadtwo(input);    /* tag - key */\r
426     type = ureadtwo(input);   /* value type */\r
427     if (tag == 0 && type == 0) {  /* invalid */\r
428       c = getc(input); ungetc(c, input);\r
429       sprintf(logline, " Tag: %u Type: %u (k %d c %d)\n",\r
430           tag, type, k, c);\r
431       showline(logline, 1);\r
432       break;\r
433     }\r
434     if (type > 5) {\r
435       c = getc(input); ungetc(c, input);\r
436 #ifdef DEBUGTIFF\r
437       if (traceflag)\r
438       {\r
439         sprintf(logline, " Tag: %u Type: %u (k %d c %d)\n", tag, type, k, c);\r
440         showline(logline, 1);\r
441       }\r
442 #endif\r
443 /*      break; */ /* removed 98/Sep/22 */\r
444     }\r
445     length = ureadfour(input);  /* `length' (better named `count') */\r
446     if (length == 1) {\r
447       if (type == TYPE_LONG) offset = ureadfour(input);\r
448       else if (type  == TYPE_SHORT) {\r
449         offset = ureadtwo(input);\r
450         (void) ureadtwo(input);   /* should be zero */\r
451       }\r
452       else if (type == TYPE_BYTE) {\r
453         offset = getc(input);\r
454         (void) getc(input);(void) getc(input);(void) getc(input);\r
455       }\r
456       else offset = ureadfour(input); /* for ratio e.g. */\r
457     }\r
458     else offset = ureadfour(input); /* value */\r
459 \r
460     switch (tag) {\r
461       case IMAGEWIDTH:\r
462         ImageWidth = extractvalue(type, length, (long) offset, input);\r
463         break;\r
464       case IMAGELENGTH:\r
465         ImageLength = extractvalue(type, length, (long) offset, input);\r
466         break;\r
467       case BITSPERSAMPLE:\r
468         BitsPerSample =\r
469               (int) extractvalue(type, length, (long) offset, input);\r
470         break;\r
471       case EXTRASAMPLES:            /* 1999/May/10 */\r
472         ExtraSamples =\r
473               (int) extractvalue(type, length, (long) offset, input);\r
474         break;        \r
475       case COMPRESSION:\r
476         compression =\r
477           (unsigned int) extractvalue(type, length, (long) offset, input);\r
478         break;\r
479       case PREDICTOR:\r
480         Predictor =\r
481           (int) extractvalue(type, length, (long) offset, input);\r
482         break;\r
483       case SAMPLESPERPIXEL:\r
484         SamplesPerPixel =\r
485           (int) extractvalue(type, length, (long) offset, input);\r
486         break;\r
487       case ROWSPERSTRIP:\r
488         RowsPerStrip =\r
489           (int) extractvalue(type, length, (long) offset, input);\r
490         break;\r
491       case STRIPOFFSETS:\r
492         StripOffsetsPtr = offset;\r
493           StripOffsetsType = type;\r
494           StripOffsetsLength = (int) length;\r
495         StripOffset = extractvalue(type, length, (long) offset, input);\r
496         break;\r
497       case STRIPBYTECOUNTS:\r
498         StripByteCountsPtr = offset;\r
499           StripByteCountsType = type;\r
500           StripByteCountsLength = (int) length;\r
501         StripByteCount = extractvalue(type, length, (long) offset, input);\r
502         break;\r
503       case ORIENTATION:\r
504         Orientation =\r
505           (int) extractvalue(type, length, (long) offset, input);\r
506         break;\r
507 /*      case MINSAMPLEVALUE:\r
508         MinSampleValue = (int) extractvalue(type, length, (long) offset, input); \r
509         break; */\r
510 /*      case MAXSAMPLEVALUE:\r
511         MaxSampleValue = (int) extractvalue(type, length, (long) offset, input);\r
512         break; */\r
513       case XRESOLUTION:\r
514         xresnum = indirectvalue(TYPE_LONG, 1, (long) offset, input); \r
515         xresden = indirectvalue(TYPE_LONG, 1, (long) offset+4, input); \r
516         break; \r
517       case YRESOLUTION:\r
518         yresnum = indirectvalue(TYPE_LONG, 1, (long) offset, input); \r
519         yresden = indirectvalue(TYPE_LONG, 1, (long) offset+4, input); \r
520         break; \r
521       case RESOLUTIONUNIT:\r
522         ResolutionUnit = (int) extractvalue(type, length, (long) offset, input); \r
523         break; \r
524       case PHOTOMETRICINTERPRETATION:\r
525         PhotometricInterpretation = \r
526           (int) extractvalue(type, length, (long) offset, input);\r
527         break;\r
528       case PLANARCONFIG:\r
529          PlanarConfig = \r
530           (int) extractvalue(type, length, (long) offset, input);\r
531         break;\r
532       case COLORMAP:\r
533 /*        ColorMap = extractvalue(type, length, (long) offset, input); */\r
534         ColorMapPtr = offset;\r
535 /*    Assume the type is SHORT (16 bit per entry) */\r
536 /*    Assume the length is 3 * 2 ^ BitsPerSample - 1 */\r
537         break;\r
538       default:              /* ignore unknown tags */\r
539         break;\r
540     }\r
541   }\r
542   return 0;\r
543 }\r
544 \r
545 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
546 \r
547 int computeheader(void);\r
548 void writepsheader(FILE *, long, long);\r
549 void writepstrailer(FILE *);\r
550 int readpackbits(unsigned char *lpBuffer, FILE *input, int RowLength);\r
551 int huffmanrow(unsigned char *lpBuffer, FILE *input, int width);\r
552 int DecodeLZW(FILE *output, FILE *input, unsigned char *lpBuffer);\r
553 void expandcolor(unsigned char *s, long width);\r
554 void expandgray(unsigned char *s, long width);\r
555 void compresscolor(unsigned char *s, long width);\r
556 int writearow(FILE *output, unsigned char *s, unsigned long width);\r
557 \r
558 #ifdef PSLEVEL2\r
559 void ASCIIinitfilter(FILE *output);\r
560 void ASCIIflushfilter(FILE *output);\r
561 void RUNinitfilter(FILE *output);\r
562 void RUNflushfilter(FILE *output);\r
563 #ifdef LZWCOMPRESSION\r
564 void LZWinitfilter(FILE *output);\r
565 void LZWflushfilter(FILE *output);\r
566 void LZWput(int, FILE *);\r
567 #endif\r
568 #endif\r
569 \r
570 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
571 \r
572 /* Remember to deallocate at end */ /* Read color map from TIFF image */\r
573 \r
574 /* do we need to use unsigned short for NT ? */\r
575 \r
576 int ReadColorMap (FILE *input, long ColorMapPtr, int BitsPerSample)\r
577 {\r
578   long present;\r
579   int k, n, nint;\r
580 \r
581 /*  should make all these unsigned short int instead for NT */\r
582 #ifdef USESHORTINT\r
583   unsigned short int *PalettePtr;\r
584 #else\r
585   unsigned int *PalettePtr;\r
586 #endif\r
587 \r
588 #ifdef DEBUGTIFF\r
589 #ifdef USESHORTINT\r
590   unsigned short int *PaletteRed;\r
591   unsigned short int *PaletteGreen;\r
592   unsigned short int *PaletteBlue;\r
593 #else\r
594   unsigned int *PaletteRed;\r
595   unsigned int *PaletteGreen;\r
596   unsigned int *PaletteBlue;\r
597 #endif\r
598 #endif\r
599 \r
600 /*  need three tables each of 2 ^ BitsPerSample integers */\r
601   n = 1 << BitsPerSample;   /* integers per table */\r
602   PaletteSize = n;      /* remember for later */\r
603   nint = n * 3;       /* total number of integers */\r
604 #ifdef DEBUGTIFF\r
605   if (traceflag)\r
606   {\r
607     sprintf(logline, "Reading Color Map of size %d\n", n);\r
608     showline(logline, 1);\r
609   }\r
610 #endif\r
611 /*  check following allocation in NT ? should we use short int ? */\r
612 #ifdef USESHORTINT\r
613   Palette = (unsigned short int *)\r
614         malloc(nint * sizeof(unsigned short int));\r
615 #else\r
616 /*  Palette = (unsigned int *) malloc(nint * 2); */ /* bytes */\r
617   Palette = (unsigned int *) malloc(nint * sizeof(unsigned int));\r
618 #endif\r
619   if (Palette == NULL)\r
620   {\r
621     showline(" ERROR: Unable to allocate memory\n", 1);\r
622     checkexit(1);\r
623 //    or more serious exit(1) ???\r
624   }\r
625   present = ftell(input);\r
626 #ifdef DEBUGTIFF\r
627   if (traceflag)\r
628   {\r
629     sprintf(logline, "Going to ColorMap at %ld + %lu\n",\r
630          ColorMapPtr, TIFFOffset);\r
631     showline(logline, 1);\r
632   }\r
633 #endif\r
634   if (fseek (input, (long) ColorMapPtr + TIFFOffset, SEEK_SET) != 0)\r
635   {\r
636     sprintf(logline, " Error in seek %s\n", " to ColorMap");\r
637     showline(logline, 1);\r
638   }\r
639   PalettePtr = Palette;\r
640 /*  Following shoud work in NT even if we use int instead of short */\r
641   for (k = 0; k < nint; k++) *PalettePtr++ = ureadtwo (input);\r
642   fseek (input, present, SEEK_SET);\r
643 /*  return 0; */\r
644 \r
645   PaletteRed = Palette;\r
646   PaletteGreen = PaletteRed + PaletteSize;\r
647   PaletteBlue = PaletteGreen + PaletteSize;\r
648 \r
649   bGrayFlag = 1;    // non-zero if palette is all grays\r
650   for (k = 0; k < n; k++)\r
651   {\r
652     if (PaletteRed[k] != PaletteGreen[k] ||\r
653         PaletteGreen[k] != PaletteBlue[k])\r
654     {\r
655       bGrayFlag = 0;\r
656       break;\r
657     }\r
658   }         // bGrayFlag presently not used\r
659 \r
660   bLinearFlag = 0;  // non-zero if Palette is simply linear\r
661   if (bGrayFlag) {\r
662     bLinearFlag = 1;\r
663     for (k = 0; k < n; k++)\r
664     {\r
665       if (PaletteRed[k] != (unsigned int) (k * 255 / (n-1))) {\r
666         bLinearFlag = 0;\r
667         break;\r
668       }\r
669     }\r
670   }         // bLinearFlag presently not used\r
671 \r
672 //  bGrayFlag and bLinearFlag could be used to produce smaller output files\r
673 \r
674 #ifdef DEBUGTIFF\r
675   if (traceflag)\r
676   {\r
677     PaletteRed = Palette;\r
678     PaletteGreen = PaletteRed + PaletteSize;\r
679     PaletteBlue = PaletteGreen + PaletteSize;\r
680     for (k = 0; k < n; k++) {\r
681       if (traceflag) {\r
682         sprintf(logline, "INX %d\tR %u\tG %u\tB %u\n",\r
683              k, PaletteRed[k], PaletteGreen[k], PaletteBlue[k]);\r
684         showline(logline, 0);\r
685       }\r
686     }\r
687   }\r
688 #endif\r
689   return 0;\r
690 }\r
691 \r
692 /* returns -1 if output error */    /* given InRowLengthX */\r
693 /* expand color if needed - or expand gray if needed */\r
694 /* compress color if needed */\r
695 /* write out a row of image */\r
696 \r
697 int ProcessRow (FILE *output, unsigned char *lpBuffer, long InRowLengthX,\r
698   long BufferLength, long OutRowLength)\r
699 {\r
700 /*  if (traceflag)\r
701     printf("ProcessRow InRowLengthX %d\n", InRowLengthX); */ /* DEBUGGING */\r
702 /*  if (traceflag)\r
703     printf("bExpandColor %d bExpandGray %d bCompressColor %d\n",\r
704        bExpandColor, bExpandGray, bCompressColor); */ /* DEBUGGING */\r
705 #ifndef _WINDOWS\r
706   if (traceflag) fflush(stdout);    /* DEBUGGING ONLY */\r
707 #endif\r
708   if (bExpandColor) expandcolor(lpBuffer, InRowLengthX);\r
709   else if (bExpandGray) expandgray(lpBuffer, InRowLengthX);\r
710   if (bCompressColor) compresscolor(lpBuffer, BufferLength);\r
711 #ifdef DEBUGTIFF\r
712   if (traceflag) {      /* DEBUGGING */\r
713     sprintf(logline, "ProcessRow OutRowLength %d\n", OutRowLength);\r
714     showline(logline, 0);\r
715   }\r
716 #endif\r
717   if (writearow(output, lpBuffer, OutRowLength) != 0) return -1;\r
718   else return 0;\r
719 }\r
720 \r
721 /* Throw out ExtraSamples in SamplesPerPixel */\r
722 /* IMPORTANT NOTE: assume for the moment samples are one byte */\r
723 \r
724 int RemoveExtraSamples (unsigned char *lpBuffer, int InRowLength)\r
725 {\r
726   unsigned char *s = lpBuffer;\r
727   unsigned char *t = lpBuffer;\r
728   int i, k, n = InRowLength / SamplesPerPixel;\r
729 \r
730 #ifdef DEBUGTIFF\r
731   if (traceflag)\r
732   {\r
733     sprintf(logline, "RemoveExtraSamples InRowLength %d\n", InRowLength);\r
734     showline(logline, 1);\r
735   }\r
736 #endif\r
737   if (ExtraSamples == 0) return InRowLength;\r
738 /*  check that BitsPerSample == 8 ??? */  \r
739   for (k = 0; k < n; k++) {\r
740     for (i = 0; i < SamplesPerPixelX; i++) *t++ = *s++;\r
741     s += ExtraSamples;\r
742   }\r
743   return (int) (t - lpBuffer);\r
744 }\r
745 \r
746 /* readflag != 0 when reading file only to get tag fields */\r
747 \r
748 int readTIFFfile (FILE *output, FILE *input,\r
749   long dwidth, long dheight, int nifd, int readflag)\r
750 {\r
751 /*  int i, j, flag; */\r
752   int i, flag;\r
753 /*  long present; */\r
754 /*  int k, color, n; */\r
755   unsigned long ImageSize;\r
756   unsigned int nread;\r
757   unsigned char *lpBuffer=NULL;\r
758   int nLen;\r
759 \r
760   TIFFVersion = ureadtwo(input);\r
761   if (TIFFVersion != TIFF_VERSION)\r
762   {\r
763     sprintf(logline, " Incorrect TIFF version code %d\n", TIFFVersion);\r
764     showline(logline, 1);\r
765     return -1;    /* bad version number for TIFF file */\r
766   }\r
767   \r
768 /*  Skip to desired image (if not first in file) */\r
769 \r
770   IFDPosition = ureadfour(input);   /* get first IFD offset in file */\r
771   while (nifd-- > 1) {\r
772     if (skipthisimage(input, IFDPosition) < 0)\r
773     {\r
774       sprintf(logline, " ERROR: Subimage %d not found", nifd);\r
775       showline(logline, 1);\r
776       return -1;\r
777     }\r
778   }\r
779 \r
780 /*  Now at desired image */\r
781   (void) readfields(input, IFDPosition);  /* read tag fields in TIFF file */\r
782 \r
783   IFDPosition = ureadfour(input);   /* get next IFD offset in file */\r
784 \r
785 /*  if (readflag == 0) return -1; */  /*  only scanning for width & height */\r
786   if (readflag != 0) return -1; /*  only scanning for width & height */\r
787 \r
788   bColorImage = 0;      /* if image is RGB or Palette color */\r
789   bExpandColor = 0;     /* comes on if Palette color image */\r
790   bExpandGray = 0;      /* comes on if Palette is gray */\r
791   bCompressColor = 0;     /* if image is colored and not `colorimage'  */\r
792   if (ColorMapPtr) {      /* is it a palette color image ? */\r
793     (void) ReadColorMap(input, ColorMapPtr, BitsPerSample);\r
794     bExpandColor = 1;\r
795     bColorImage = 1;\r
796   }\r
797 \r
798 #ifdef DEBUGTIFF\r
799   if (traceflag)\r
800   {\r
801     sprintf(logline, "Width %ld, Height %ld, BitsPerSample %d, SamplesPerPixel %d\n", \r
802        ImageWidth, ImageLength, BitsPerSample, SamplesPerPixel);\r
803     showline(logline, 1);\r
804   }\r
805 #endif\r
806 \r
807 #ifdef DEBUGTIFF\r
808   if (traceflag)\r
809   {\r
810     sprintf(logline, "Compression %u PhotometricInterpretation %d\n",\r
811      compression, PhotometricInterpretation);\r
812     showline(logline, 1);\r
813   }\r
814 #endif\r
815 \r
816 #ifdef DEBUGTIFF\r
817   if (traceflag && Predictor != 1)\r
818   {\r
819     sprintf(logline, "Predictor %d\n", Predictor);\r
820     showline(logline, 1);\r
821   }\r
822 #endif\r
823 \r
824   if (ExtraSamples > 0) SamplesPerPixelX = SamplesPerPixel-ExtraSamples;\r
825   else SamplesPerPixelX = SamplesPerPixel;\r
826   \r
827   BitsPerPixel = BitsPerSample * SamplesPerPixel;\r
828   if (ExtraSamples > 0) BitsPerPixelX = BitsPerSample * SamplesPerPixelX;\r
829   else BitsPerPixelX = BitsPerPixel;\r
830 \r
831   InRowLength = (ImageWidth * BitsPerPixel + 7) / 8;  /* row length file */\r
832   if (ExtraSamples > 0)InRowLengthX = (ImageWidth * BitsPerPixelX + 7) / 8;\r
833   else InRowLengthX = InRowLength;\r
834 \r
835   if (RowsPerStrip > 0)\r
836     StripsPerImage = (int) ((ImageLength + RowsPerStrip - 1) / RowsPerStrip);\r
837   else StripsPerImage = 1;\r
838 \r
839   if (bExpandColor) BufferLength = ImageWidth * 3;\r
840   else if (bExpandGray) BufferLength = ImageWidth;\r
841   else BufferLength = InRowLength;\r
842 \r
843 /*  do compression of 24 bit color if use of `colorimage' not allowed */\r
844 /*  if (bitsperpixel == 24 && bCompressFlag != 0 && forceice == 0) */\r
845 /*  if (BitsPerPixel == 24 && bCompressFlag != 0) */\r
846 /*  if ((BitsPerPixel == 24 || bExpandColor) && bAllowColor == 0)  */\r
847   if ((BitsPerPixelX == 24 || bExpandColor) && ! bAllowColor)\r
848   {\r
849     sprintf(logline, " color image (bits %d expand %d): use `*c' flag?",\r
850          BitsPerPixelX, bExpandColor);  /* 96/Aug/15 */\r
851 //    showline(logline, 1);\r
852     showline(logline, 0);     // reduce severity 2000 March 16\r
853     bCompressColor = 1;\r
854     OutRowLength = BufferLength / 3;\r
855   }\r
856   else OutRowLength = BufferLength;\r
857 \r
858 #ifdef DEBUGTIFF\r
859   if (traceflag)\r
860   {\r
861     sprintf(logline, "InRowLength %ld BufferLength %ld OutRowLength %ld\n",\r
862       InRowLength, BufferLength, OutRowLength);\r
863     showline(logline, 1);\r
864   }\r
865 #endif\r
866 \r
867 /*  deal with GhostScript TIFF file format with gaps */   /* 94/Dec/16 */\r
868 /*  shouldn't this only kick in if we are not using (LZW) compression ? */\r
869   if (bGhostHackFlag) {       /*  made conditional 95/Nov/10 */\r
870     if (InRowLength + 1 == StripByteCount)\r
871     {\r
872       InRowLength++;        /* a hack */\r
873     }\r
874   }\r
875 /*  should also increase BufferLength allocation ? 95/Nov/10 */\r
876 \r
877 #ifdef PSLEVEL2\r
878   bRunLengthFlag = 0;\r
879   if (bAllowCompression) {\r
880 /*    Use runlength encoding if monochrome *or* if original uses it */\r
881 /*    if (BitsPerSample == 1 && SamplesPerPixel == 1) */\r
882     if (BitsPerSample == 1 && SamplesPerPixelX == 1)\r
883       bRunLengthFlag = 1;\r
884     if (compression == PACK_BITS) bRunLengthFlag = 1;\r
885 #ifdef LZWCOMPRESSION\r
886     bLZWFlag = 0;\r
887 /*    Use LZW if runlength encoding not chosen */\r
888     if (bRunLengthFlag == 0)\r
889     {\r
890 //      if (compression == LZW_COMPRESSION) bLZWFlag = 1;\r
891 //      else; bLZWFlag = 1          /* otherwise use LZW */\r
892       bLZWFlag = 1;\r
893     }\r
894 #endif\r
895   }\r
896 #endif\r
897 \r
898   if (computeheader() != 0) return -1;  /* noticed format not supported? */\r
899 \r
900   writepsheader(output, dwidth, dheight);\r
901 \r
902 /*  following should already be taken care of in `computeheader' */\r
903 /*  if (compression > 1 && compression != PACK_BITS) */\r
904   if (compression > TIFF_CCITT && compression != LZW_COMPRESSION &&\r
905     compression != PACK_BITS)\r
906   {\r
907     sprintf(logline, " ERROR: Unknown compression scheme (%d)", compression);\r
908     showline(logline, 1);\r
909     return -1;\r
910   }\r
911 \r
912 /*  ImageSize = (unsigned long) InRowLength * ImageLength; */\r
913   ImageSize = (unsigned long) InRowLengthX * ImageLength;\r
914 /*  check whether values reasonable */\r
915   if (ImageSize == 0)\r
916   {\r
917     sprintf(logline, " ERROR: Zero image size, %d %d (%s)",\r
918         InRowLengthX, ImageLength, "readTIFFfile");\r
919     showline(logline, 1);\r
920     return -1;\r
921   }\r
922   if (ImageWidth > MAXIMAGE || ImageLength > MAXIMAGE ||  /* bad data ? */\r
923     ImageSize > 67108864) { /* arbitrary limits (to catch bad files) */\r
924     sprintf(logline,\r
925       " ERROR: image file too large\n(%ld x %ld (%d) => %ld bytes)",\r
926         ImageWidth, ImageLength, BitsPerPixel, ImageSize);\r
927     showline(logline, 1);\r
928     return -1;\r
929   }\r
930   if (ImageWidth < 0 || ImageLength < 0 ||    /* missing fields */\r
931         StripOffset < 0) {          /* missing fields */\r
932     showline(" ERROR: TIFF file missing required tags", 1);\r
933     return -1;\r
934   }\r
935 \r
936   if (fseek(input, (long) StripOffset + TIFFOffset, SEEK_SET) != 0)\r
937   {\r
938     sprintf(logline, " Error in seek %s\n", " to StripOffset\n");\r
939     showline(logline, 1);\r
940     return -1;\r
941   }\r
942 \r
943 /*  Maybe use far memory ? */ /* lot of changes if we do this ... */\r
944 /*  Maybe don't use if LZW compression ? */\r
945 /*  if (compression != LZW_COMPRESSION)  */\r
946 /*  if ((lpBuffer = malloc((int) BufferLength)) == NULL) {  */\r
947 /*  Accomodate GhostScript gap bug work around ... just in case 95/Nov/10 */\r
948 /*  nLen = BufferLength + 1; */\r
949   nLen = (int) ((BufferLength + 3) / 4) * 4;\r
950   if ((lpBuffer = malloc(nLen)) == NULL)\r
951   {\r
952     sprintf(logline, " ERROR: Unable to allocate %d bytes\n", nLen);\r
953     showline(logline, 1);\r
954     checkexit(1);         /* 1995/July/15 ? */\r
955 //    or more serious exit(1) ???\r
956   }\r
957 \r
958 /*  in case minsamplevalue and maxsamplevalue not given in tags */\r
959 /*  if (MinSampleValue < 0 || MaxSampleValue < 0 ||\r
960       MinSampleValue == MaxSampleValue) {\r
961     MinSampleValue = 0; MaxSampleValue = (1 << BitsPerSample) - 1;\r
962   } */  /* never used */\r
963 \r
964 /*  Actually go and read the file now ! */\r
965 \r
966 /*  following should already be taken care of in `computeheader' */\r
967 \r
968   if (compression > TIFF_CCITT && compression != LZW_COMPRESSION &&\r
969     compression != PACK_BITS)\r
970   {\r
971     sprintf(logline, " ERROR: Unknown compression scheme (%d)", compression);\r
972     showline(logline, 1);\r
973     return -1;\r
974   }\r
975 #ifdef DEBUGTIFF\r
976   if (traceflag)\r
977   {\r
978     if (compression == PACK_BITS) sprintf(logline, "Using PACK_BITS\n");\r
979     else if (compression == TIFF_CCITT) sprintf(logline, "Using TIFF_CCITT\n");\r
980     else if (compression == LZW_COMPRESSION) sprintf(logline, "Using LZW\n");\r
981     showline(logline, 1);\r
982   }\r
983 #endif\r
984 \r
985   flag = 0;               /* flag gets set if EOF hit */\r
986 \r
987 #ifdef PSLEVEL2\r
988   if (bLevel2)\r
989   {\r
990     ASCIIinitfilter(output);            /* 96/Dec/20 */\r
991     if (bRunLengthFlag) RUNinitfilter(output);    /* 96/Dec/24 */\r
992 #ifdef LZWCOMPRESSION\r
993     else if (bLZWFlag) LZWinitfilter(output);   /* 96/Dec/28 */\r
994 #endif\r
995   }\r
996 #endif\r
997 \r
998 /*  LZW needs to be done by strips, the others can be done by row */\r
999 \r
1000   if (compression == LZW_COMPRESSION) DecodeLZW(output, input, lpBuffer);\r
1001 \r
1002   else {    /* else not LZW compression */\r
1003 \r
1004     for (i = 0; i < (int) ImageLength; i++) { /* read image lines */\r
1005 \r
1006       if (compression == PACK_BITS) {   /* compressed binary file */\r
1007         if (readpackbits (lpBuffer, input, (int) InRowLength) != 0) {\r
1008           flag = -1;\r
1009           break;\r
1010         }\r
1011       }\r
1012       else if (compression == TIFF_CCITT) { /* CCITT 1D compression */\r
1013         if (huffmanrow (lpBuffer, input, (int) ImageWidth) != 0) {\r
1014           flag = -1;\r
1015           break;\r
1016         }\r
1017       }\r
1018       else {                /* uncompressed file */\r
1019         nread = fread(lpBuffer, 1, (unsigned int) InRowLength, input);\r
1020         if (nread != (unsigned int) InRowLength) {  /* read a row */\r
1021           flag = -1;\r
1022           showline("Premature EOF ", 1);  /* ??? */\r
1023           break;\r
1024         } \r
1025       }\r
1026 #ifdef DEBUGTIFF\r
1027       if (traceflag)\r
1028       {\r
1029         sprintf(logline, "readTIFFFile InRowLength %d\n", InRowLength);\r
1030         showline(logline, 1);\r
1031       }\r
1032 #endif\r
1033       if (ExtraSamples > 0)\r
1034         (void) RemoveExtraSamples(lpBuffer, InRowLength); /* 99/May/10 */\r
1035 \r
1036 #ifdef DEBUGTIFF\r
1037       if (traceflag)\r
1038       {\r
1039         sprintf(logline, "readTIFFFile OutRowLength %d BufferLength %d\n",\r
1040              OutRowLength, BufferLength);\r
1041         showline(logline, 1);\r
1042       }\r
1043 #endif\r
1044 \r
1045 /*      if (ProcessRow (output, lpBuffer, InRowLength, BufferLength, */\r
1046       if (ProcessRow (output, lpBuffer, InRowLengthX, BufferLength,\r
1047         OutRowLength) != 0)\r
1048       {\r
1049         showline("\n", 0);\r
1050         showline("ERROR: Output error ", 1);\r
1051         perrormod((outputfile != NULL) ? outputfile : "");\r
1052         break;\r
1053       }\r
1054 /*      if (flag != 0) break; *//* hit EOF or other error */\r
1055 /*      check on abort flag here somewhere also ? */\r
1056     } /* end of this row */\r
1057   } /* end of not LZW compression */\r
1058 \r
1059 //  Have to flush filters in reverse order\r
1060 #ifdef PSLEVEL2\r
1061   if (bLevel2)\r
1062   {\r
1063     if (bRunLengthFlag) RUNflushfilter(output); /* 96/Dec/24 */\r
1064 #ifdef LZWCOMPRESSION\r
1065     else if (bLZWFlag) LZWflushfilter(output);  /* 96/Dec/28 */\r
1066 #endif\r
1067     ASCIIflushfilter(output);       /* 96/Dec/20 */\r
1068   }\r
1069 #endif\r
1070   \r
1071 /* now finished reading */  /* maybe use far memory for lpBuffer ? */\r
1072 \r
1073   if (lpBuffer != NULL) {\r
1074     free(lpBuffer);\r
1075     lpBuffer = NULL;\r
1076   }\r
1077   if (Palette != NULL) {\r
1078     free(Palette);\r
1079     Palette = NULL;\r
1080   }\r
1081   writepstrailer(output);\r
1082   return flag;\r
1083 }    /* end of readTIFFfile(...) */\r
1084 \r
1085 /**********************************************************************/\r
1086 \r
1087 /* following is from windef.h */\r
1088 \r
1089 typedef unsigned long       DWORD;\r
1090 typedef int                 BOOL;\r
1091 typedef unsigned char       BYTE;\r
1092 typedef unsigned short      WORD;\r
1093 typedef float               FLOAT;\r
1094 typedef int                 INT;\r
1095 typedef unsigned int        UINT;\r
1096 \r
1097 typedef long        LONG;\r
1098 \r
1099 /* following is from wingdi.h */\r
1100 \r
1101 #ifndef _WINDOWS\r
1102 \r
1103 #define FAR\r
1104 \r
1105 #include <pshpack2.h>\r
1106 typedef struct tagBITMAPFILEHEADER {\r
1107   WORD    bfType;\r
1108   DWORD   bfSize;\r
1109   WORD    bfReserved1;\r
1110   WORD    bfReserved2;\r
1111   DWORD   bfOffBits;\r
1112 } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;\r
1113 #include <poppack.h>\r
1114 \r
1115 typedef struct tagBITMAPINFOHEADER {\r
1116   DWORD      biSize;\r
1117   LONG       biWidth;\r
1118   LONG       biHeight;\r
1119   WORD       biPlanes;\r
1120   WORD       biBitCount;\r
1121   DWORD      biCompression;\r
1122   DWORD      biSizeImage;\r
1123   LONG       biXPelsPerMeter;\r
1124   LONG       biYPelsPerMeter;\r
1125   DWORD      biClrUsed;\r
1126   DWORD      biClrImportant;\r
1127 } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;\r
1128 \r
1129 #include <pshpack1.h>\r
1130 typedef struct tagRGBTRIPLE {\r
1131   BYTE    rgbtBlue;\r
1132   BYTE    rgbtGreen;\r
1133   BYTE    rgbtRed;\r
1134 } RGBTRIPLE;\r
1135 #include <poppack.h>\r
1136 \r
1137 typedef struct tagRGBQUAD {\r
1138   BYTE    rgbBlue;\r
1139   BYTE    rgbGreen;\r
1140   BYTE    rgbRed;\r
1141   BYTE    rgbReserved;\r
1142 } RGBQUAD;\r
1143 typedef RGBQUAD FAR* LPRGBQUAD;\r
1144 \r
1145 #endif\r
1146 \r
1147 BITMAPFILEHEADER bmfh;\r
1148 \r
1149 BITMAPINFOHEADER bmih;\r
1150 \r
1151 /* RGBQUAD colortable[256]; */\r
1152 \r
1153 int dpifrom(int res)\r
1154 {\r
1155   double dres = (double) res * 25.4 / 1000.0;\r
1156   dres = (double) ((int) (dres * 10.0 + 0.5)) / 10.0;\r
1157   return (int) (dres + 0.5);\r
1158 }\r
1159 \r
1160 int colormaplength;   /* ??? */\r
1161 int mingrey, maxgrey; /* ??? */\r
1162 int nColors;      /* ??? */\r
1163 long OffBits;     /* ??? */\r
1164 long ImageSize;     /* ??? */\r
1165 \r
1166 /* readflag is non-zero in prescan */\r
1167 \r
1168 int readBMPfields (FILE *input, int readflag)\r
1169 {\r
1170   long nLen;\r
1171   double dw, dh;\r
1172 \r
1173   ImageWidth = ImageLength = -1;\r
1174   SamplesPerPixel = BitsPerSample = 1;\r
1175   ExtraSamples = 0;\r
1176   compression = 0; Orientation = 1;\r
1177   StripOffset = -1; StripByteCount = -1;\r
1178   PhotometricInterpretation = 1;  /* default */\r
1179   PlanarConfig = 1; Predictor = 1;\r
1180   ColorMapPtr = 0;  /* pointer to map in case of Palette Color Images */\r
1181   mingrey = -1; maxgrey = -1;\r
1182   xresnum = yresnum = nDefaultTIFFDPI;    /* 96/Apr/3 */  \r
1183   xresden = yresden = 1;        /* 93/Oct/20 */\r
1184   ResolutionUnit = 2;         /* default dpi */ /* 93/Oct/20 */\r
1185 \r
1186   fseek(input, 0, SEEK_END);\r
1187   nLen = ftell(input);        /* Length of file */\r
1188 //  fseek(input, 0, SEEK_SET);      /* rewind */\r
1189   rewind(input);\r
1190   fread(&bmfh, sizeof(bmfh), 1, input); /*  read file header */\r
1191   if (bmfh.bfType != (77 * 256 + 66)) {     /*  "BM" */\r
1192     sprintf(logline, "Not BMP file %X\n", bmfh.bfType);\r
1193     showline(logline, 1);\r
1194     return -1;\r
1195   }\r
1196 /* "Size of header %lu\n", bmih.biSize compare to nLen ? */\r
1197   OffBits = bmfh.bfOffBits;\r
1198 /* "Offset to image %lu\n", bmih.bfOffBits */\r
1199 #ifdef DEBUGBMP\r
1200   if (traceflag && sreadflag)\r
1201   {\r
1202     sprintf(logline, "\nnLen %ld bfSize %ld bfOffBits %ld ",\r
1203        nLen, bmfh.bfSize, bmfh.bfOffBits);\r
1204     showline(logline, 1);\r
1205   }\r
1206 #endif\r
1207 /*  bmfh.bfSize file size in words ? NO */\r
1208 /*  bmfh.bfOffBits offset from end of header ? NO */\r
1209 \r
1210   fread(&bmih, sizeof(bmih), 1, input); /*  read bitmap info header */\r
1211 \r
1212 /*  if (bmih.biClrUsed > 0) nColor = bmih.biClrUsed;\r
1213   else if (bmih.biBitCount < 24) nColor = 1 << bmih.biBitCount; */\r
1214   if (bmih.biClrUsed > 0) nColors = bmih.biClrUsed;\r
1215   else if (bmih.biBitCount < 24) nColors = 1 << bmih.biBitCount;\r
1216   else nColors = 0;\r
1217   ImageWidth = bmih.biWidth;\r
1218   ImageLength = bmih.biHeight;\r
1219   if (bmih.biBitCount < 24) {\r
1220     BitsPerSample = bmih.biBitCount;\r
1221     SamplesPerPixel = 1;\r
1222   }\r
1223   else {\r
1224     BitsPerSample = 8;\r
1225     SamplesPerPixel = 3;\r
1226   }\r
1227 #ifdef DEBUGBMP\r
1228   if (traceflag && readflag) {\r
1229     sprintf(logline, "\nBMIH: %d x %d bits %d x %d",\r
1230       ImageWidth, ImageLength, SamplesPerPixel, BitsPerSample);\r
1231     showline(logline, 1);\r
1232   }\r
1233   if (traceflag && readflag) {\r
1234     sprintf(logline, "\nBMIH: Size %ld Planes %d Compression %d SizeImage %ld ColorsUsed %d",\r
1235         bmih.biSize, bmih.biPlanes,\r
1236         bmih.biCompression, bmih.biSizeImage, bmih.biClrUsed);\r
1237     showline(logline, 1);\r
1238 \r
1239   }\r
1240 #endif\r
1241 \r
1242 /* "Number of image planes %u\n", bmih.biPlanes */\r
1243 /* "Compression %lu\n", bmih.biCompression */\r
1244 /* "Size of compressed image %lu\n", bmih.biSizeImage */\r
1245 /* "Number of colors used %lu %d\n", bmih.biClrUsed */\r
1246 \r
1247 /* "Horizontal pixel per meter %ld\n", bmih.biXPelsPerMeter */\r
1248   xresnum = dpifrom(bmih.biXPelsPerMeter);\r
1249   if (xresnum == 0) xresnum = nDefaultTIFFDPI;\r
1250   dw = (double) ImageWidth / xresnum;\r
1251 /* "%d dpi (horizontal)\twidth %lg inch\n", xresnum, dw */\r
1252 \r
1253 /* "Vertical pixel per meter %ld\n", bmih.biYPelsPerMeter */\r
1254   yresnum = dpifrom(bmih.biYPelsPerMeter);\r
1255   if (yresnum == 0) yresnum = nDefaultTIFFDPI;\r
1256   dh = (double) ImageLength / yresnum;\r
1257 /* "%d dpi (vertical)\theight %lg inch\n", yresnum, dh */\r
1258 \r
1259   compression = bmih.biCompression; /* save it */\r
1260   ColorMapPtr = 0;\r
1261   if (nColors > 0) {    /*  read color table unless 24 bit */\r
1262     if (nColors > 256) {\r
1263       sprintf(logline, " ERROR: too many colors: %d\n", nColors);\r
1264       showline(logline, 1);\r
1265       nColors = 256;\r
1266       return -1;\r
1267     }\r
1268     ColorMapPtr = ftell(input); /* color map starts here */\r
1269     TIFFOffset = 0;\r
1270     colormaplength = sizeof(RGBQUAD) * nColors;\r
1271 /*    fread(&colortable, sizeof(RGBQUAD), nColors, input); */\r
1272   }\r
1273 /*  ColorMapPtr should be zero for 24 bit RGB images */\r
1274   OffBits= sizeof(bmfh) + sizeof(bmih) + sizeof(RGBQUAD) * nColors;\r
1275   fseek(input, OffBits, SEEK_SET);\r
1276   if (bmih.biSizeImage > 0) ImageSize = bmih.biSizeImage;\r
1277   else ImageSize = nLen - OffBits;\r
1278 #ifdef DEBUGBMP\r
1279   if (traceflag && readflag)\r
1280   {\r
1281     sprintf(logline, "\nImage at %ld size %ld bytes ", OffBits, ImageSize);\r
1282     showline(logline, 1);\r
1283   }\r
1284 #endif\r
1285   return 0;\r
1286 }\r
1287 \r
1288 int readBMPPalette (FILE *input, long ColorMapPtr, int BitsPerSample)\r
1289 {\r
1290   long present;\r
1291   int k, n, nint;\r
1292   RGBQUAD rgb;\r
1293 /*  should make all these unsigned short int instead for NT */\r
1294 \r
1295 #ifdef USESHORTINT\r
1296   unsigned short int *PaletteRed;\r
1297   unsigned short int *PaletteGreen;\r
1298   unsigned short int *PaletteBlue;\r
1299 #else\r
1300   unsigned int *PaletteRed;\r
1301   unsigned int *PaletteGreen;\r
1302   unsigned int *PaletteBlue;\r
1303 #endif\r
1304 \r
1305 /*  need three tables each of 2 ^ BitsPerSample integers */\r
1306   n = 1 << BitsPerSample;   /* integers per table */\r
1307 #ifdef DEBUGBMP\r
1308   if (traceflag) {\r
1309     sprintf(logline, "Reading Color Map of size %d\n", n);\r
1310     showline(logline, 1);\r
1311   }\r
1312 #endif\r
1313   PaletteSize = n;      /* remember for later */\r
1314   nint = n * 3;       /* total number of integers */\r
1315 /*  check following allocation in NT ? should we use short int ? */\r
1316 #ifdef USESHORTINT\r
1317   Palette = (unsigned short int *)\r
1318         malloc(nint * sizeof(unsigned short int));\r
1319 #else\r
1320   Palette = (unsigned int *) malloc(nint * sizeof(unsigned int)); \r
1321 #endif\r
1322   if (Palette == NULL) {\r
1323     showline("Unable to allocate memory\n", 1);\r
1324     checkexit(1);\r
1325 //    or more serious exit(1) ???\r
1326   }\r
1327   PaletteRed = Palette;\r
1328   PaletteGreen = PaletteRed + PaletteSize;\r
1329   PaletteBlue = PaletteGreen + PaletteSize;\r
1330 \r
1331   present = ftell(input);\r
1332 #ifdef DEBUGBMP\r
1333   if (traceflag) {\r
1334     sprintf(logline, "Going to ColorMap at %ld\n", ColorMapPtr);\r
1335     showline(logline, 1);\r
1336   }\r
1337 #endif\r
1338   if (fseek (input, (long) ColorMapPtr, SEEK_SET) != 0)\r
1339   {\r
1340     sprintf(logline, " Error in seek %s\n", " to ColorMap\n");\r
1341     showline(logline, 1);\r
1342   }\r
1343   for (k = 0; k < n; k++) {\r
1344     fread (&rgb, sizeof(RGBQUAD), 1, input);\r
1345     PaletteRed[k] = rgb.rgbRed; \r
1346 /*    PaletteRed[k] = rgb.rgbRed << 8; */\r
1347     PaletteGreen[k] = rgb.rgbGreen; \r
1348 /*    PaletteGreen[k] = rgb.rgbGreen << 8; */\r
1349     PaletteBlue[k] = rgb.rgbBlue; \r
1350 /*    PaletteBlue[k] = rgb.rgbBlue << 8; */\r
1351   }\r
1352   bGrayFlag = 1;      /* non-zero if palette has only grays */\r
1353   for (k = 0; k < n; k++) {\r
1354     if (PaletteRed[k] != PaletteGreen[k] ||\r
1355       PaletteGreen[k] != PaletteBlue[k]) {\r
1356       bGrayFlag = 0;\r
1357       break;\r
1358     }\r
1359   }\r
1360   bLinearFlag = 0;    /* non-zero if Palette is simply linear */\r
1361   if (bGrayFlag) {\r
1362     bLinearFlag = 1;\r
1363     for (k = 0; k < n; k++) {\r
1364       if (PaletteRed[k] != (unsigned int) (k * 255 / (n-1))) {\r
1365 #ifdef DEBUGBMP\r
1366         if (traceflag) {\r
1367           sprintf(logline, "R[%d] = %d not %d\n",\r
1368             k, PaletteRed[k], (k * 255 / (n-1)));\r
1369           showline(logline, 1);\r
1370         }\r
1371 #endif\r
1372         bLinearFlag = 0;\r
1373         break;\r
1374       }\r
1375     }\r
1376   }\r
1377   \r
1378 /*  fseek (input, present, SEEK_SET); */\r
1379 #ifdef IGNORED\r
1380   if (traceflag) {    /* show palette */\r
1381     for (k = 0; k < n; k++) {\r
1382       sprintf(logline, "INX %d\tR %u\tG %u\tB %u\n",\r
1383         k, PaletteRed[k], PaletteGreen[k], PaletteBlue[k]);\r
1384       showline(logline, 1);\r
1385     }\r
1386   }\r
1387 #endif\r
1388   return 0; \r
1389 }\r
1390 \r
1391 /* readflag != 0 when prescanning to get fields */\r
1392 \r
1393 int readBMPfile (FILE *output, FILE *input,\r
1394          long dwidth, long dheight, int readflag)\r
1395 {\r
1396   unsigned char *lpBuffer=NULL;\r
1397   int i, flag;\r
1398   int nLen;\r
1399   unsigned int nread;\r
1400   unsigned char *s;\r
1401   int c, d, e=0;      /* keep compiler happy */\r
1402   int k, n;\r
1403   int evenflag=0;\r
1404   int nibble;\r
1405 \r
1406   (void) readBMPfields(input, readflag);  /* read tag fields in BMP file */\r
1407   BitsPerPixel = BitsPerSample * SamplesPerPixel; /* for bmp only */\r
1408   BitsPerPixelX = BitsPerPixel;\r
1409   if (readflag != 0) return 0;  /* if only reading for info */\r
1410   bColorImage = 0;      /* if image is RGB or Palette color */\r
1411   bExpandColor = 0;     /* comes on if Palette color image */\r
1412   bExpandGray = 0;      /* comes on if Palette is gray */\r
1413   bCompressColor = 0;     /* if image is colored and not `colorimage'  */\r
1414   if (ColorMapPtr > 0) {      /* do not read if 24 bit color */\r
1415     readBMPPalette (input, ColorMapPtr, BitsPerSample);\r
1416 /*    check on bGrayFlag and bLinearFlag here ... */\r
1417 #ifdef DEBUGBMP\r
1418     if (traceflag) {\r
1419       sprintf(logline, "bGrayFLag %d bLinearFlag %d\n",\r
1420           bGrayFlag, bLinearFlag);\r
1421       showline(logline, 1);\r
1422     }\r
1423 #endif\r
1424     if (bGrayFlag) bColorImage = 0;\r
1425     else bColorImage = 1;\r
1426     if (! bLinearFlag) {\r
1427       if (bGrayFlag) bExpandGray = 1;\r
1428       else bExpandColor = 1;\r
1429     }\r
1430     if (BitsPerPixel == 1 && bGrayFlag != 0) {\r
1431       bExpandGray = 0;    /*    treat as MonoChrome */\r
1432       if (bLinearFlag) bInvertImage = 0;\r
1433       else bInvertImage = 1;\r
1434     }\r
1435 /*    ??? check this */\r
1436   }\r
1437   else PaletteSize = 0; /* not Palette Color */\r
1438   if (bLinearFlag) PaletteSize = 0; /* no need to use Palette ??? */\r
1439 \r
1440 #ifdef DEBUGBMP\r
1441   if (traceflag) {\r
1442     sprintf(logline, \r
1443   "bColorImage %d bExpandColor %d bCompressColor %d PaletteSize %d\n", \r
1444          bColorImage, bExpandColor, bCompressColor, PaletteSize);\r
1445     showline(logline, 1);\r
1446   }\r
1447   if (traceflag) {\r
1448     sprintf(logline, "Width %ld, Height %ld, BitsPerSample %d, SamplesPerPixel %d\n", \r
1449          ImageWidth, ImageLength, BitsPerSample, SamplesPerPixel);\r
1450     showline(logline, 1);\r
1451   }\r
1452 #endif\r
1453 \r
1454 /* copied pretty much from readTIFF ... */\r
1455 \r
1456   SamplesPerPixelX = SamplesPerPixel;\r
1457   \r
1458   BitsPerPixel = BitsPerSample * SamplesPerPixel;   /* only BMP */\r
1459   BitsPerPixelX = BitsPerPixel;\r
1460   ExtraSamples = 0;\r
1461   InRowLength = (ImageWidth * BitsPerPixel + 7) / 8;  /* row length file */\r
1462 \r
1463   InRowRead = ((InRowLength + 3) / 4) * 4;  /* multiple of 4 bytes */\r
1464   if (bExpandColor) BufferLength = ImageWidth * 3;\r
1465   else if (bExpandGray) BufferLength = ImageWidth;\r
1466   else BufferLength = InRowLength;\r
1467   \r
1468   if ((BitsPerPixel == 24 || bExpandColor) && ! bAllowColor) {\r
1469     sprintf(logline, " color image (bits %d expand %d): use `*c' flag?",\r
1470          BitsPerPixel, bExpandColor); /* 96/Aug/15 */\r
1471     showline(logline, 1);\r
1472     bCompressColor = 1;\r
1473     OutRowLength = BufferLength / 3;\r
1474   }\r
1475   else OutRowLength = BufferLength;\r
1476 \r
1477 #ifdef DEBUGBMP\r
1478   if (traceflag)\r
1479   {\r
1480     sprintf(logline, "InRowLength %ld BufferLength %ld OutRowLength %ld\n",\r
1481          InRowLength, BufferLength, OutRowLength);\r
1482     showline(logline, 1);\r
1483   }\r
1484 #endif\r
1485   \r
1486 #ifdef PSLEVEL2\r
1487   bRunLengthFlag = 0;\r
1488   if (bAllowCompression) {\r
1489 /*    Use runlength encoding if monochrome *or* if original uses it */\r
1490 /*    if (BitsPerSample == 1 && SamplesPerPixel == 1) */\r
1491     if (BitsPerSample == 1 && SamplesPerPixelX == 1)\r
1492       bRunLengthFlag = 1;\r
1493     if (compression == PACK_BITS) bRunLengthFlag = 1;\r
1494 #ifdef LZWCOMPRESSION\r
1495     bLZWFlag = 0;\r
1496 /*    Use LZW if runlength encoding not chosen */\r
1497     if (bRunLengthFlag == 0) {\r
1498 //      if (compression == LZW_COMPRESSION) bLZWFlag = 1;\r
1499 //      else bLZWFlag = 1;          /* otherwise use LZW */\r
1500       bLZWFlag = 1;\r
1501     }\r
1502 #endif\r
1503   }\r
1504 #endif\r
1505 \r
1506   if (computeheader () != 0) return -1; /* noticed format not supported? */\r
1507 \r
1508   writepsheader(output, dwidth, dheight);\r
1509 \r
1510   ImageSize = (unsigned long) InRowLength * ImageLength; /* for bmp only */\r
1511 \r
1512 /*  check whether values reasonable */  \r
1513   if (ImageSize == 0) {\r
1514     sprintf(logline, " ERROR: Zero image size %d %d (%s)",\r
1515         InRowLength, ImageLength, "readBMPfile");\r
1516     showline(logline, 1);\r
1517     return -1;\r
1518   }\r
1519   if (ImageWidth > MAXIMAGE || ImageLength > MAXIMAGE ||  /* bad data ? */\r
1520     ImageSize > 67108864) { /* arbitrary limits (to catch bad files) */\r
1521     sprintf(logline,\r
1522         " ERROR: image file too large\n(%ld x %ld (%d) => %ld bytes)", \r
1523         ImageWidth, ImageLength, BitsPerPixel, ImageSize);\r
1524     showline(logline, 1);\r
1525     return -1;\r
1526   }\r
1527 \r
1528 #ifdef DEBUGBMP\r
1529   if (traceflag)\r
1530   {\r
1531     sprintf(logline, "Seeking to %ld\n", OffBits);\r
1532     showline(logline, 1);\r
1533   }\r
1534 #endif\r
1535   if (fseek(input, (long) OffBits, SEEK_SET) != 0)\r
1536   {\r
1537     sprintf(logline, " Error in seek %s\n", " to OffBits\n");\r
1538     showline(logline, 1);\r
1539     return -1;\r
1540   }\r
1541   nLen = (int) ((BufferLength + 3) / 4) * 4;\r
1542   lpBuffer = malloc(nLen);\r
1543   if (lpBuffer == NULL)\r
1544   {\r
1545     sprintf(logline, " ERROR: Unable to allocate %d bytes\n", nLen);\r
1546     showline(logline, 1);\r
1547     checkexit(1);\r
1548 //    or more serious exit(1) ???\r
1549   }\r
1550 \r
1551   flag = 0;               /* flag gets set if EOF hit */\r
1552 \r
1553 #ifdef PSLEVEL2\r
1554   if (bLevel2)\r
1555   {\r
1556     ASCIIinitfilter(output);            /* 96/Dec/20 */\r
1557     if (bRunLengthFlag) RUNinitfilter(output);    /* 96/Dec/24 */\r
1558 #ifdef LZWCOMPRESSION\r
1559     else if (bLZWFlag) LZWinitfilter(output);   /* 96/Dec/28 */\r
1560 #endif\r
1561   }\r
1562 #endif\r
1563 \r
1564   for (i = 0; i < (int) ImageLength; i++) { /* read image lines */\r
1565 \r
1566 /*    May need to uncompress here if compression != 0 */\r
1567 /*    nread = fread(lpBuffer, 1, (unsigned int) InRowLength, input); */\r
1568     if (compression == 0)\r
1569       nread = fread(lpBuffer, 1, (unsigned int) InRowRead, input);\r
1570     else if (BitsPerPixel == 4) { /* decompress, four bit images */\r
1571       evenflag = 1;       /* even nibble is next (output) */\r
1572       s = lpBuffer;\r
1573       while (s <= lpBuffer + InRowRead) {\r
1574         c = getc(input);\r
1575 #ifdef DEBUGBMP\r
1576         if (traceflag) {\r
1577           sprintf(logline, " %d", c);\r
1578           showline(logline, 1);\r
1579         }\r
1580 #endif\r
1581         if (c > 0) {      /* repeating group pixel count */\r
1582           d = getc(input);  /* pixel */\r
1583           e = d & 15;     /* decompose right nibble */\r
1584           d = d >> 4;     /* decompose left nibble */\r
1585 #ifdef DEBUGBMP\r
1586           if (traceflag) {\r
1587             sprintf(logline, " repeat %d %d", d, e);\r
1588             showline(logline, 1);\r
1589           }\r
1590 #endif\r
1591           for (k = 0; k < c; k++) {\r
1592             nibble = (k % 2 == 0) ? d : e;\r
1593 /*            now stuff nibble */\r
1594             if (evenflag) *s = (unsigned char) (nibble << 4);\r
1595 /*            else *s++ = *s | nibble; */\r
1596             else *s++ = (unsigned char) (*s | nibble);\r
1597             evenflag = 1 - evenflag;\r
1598           }\r
1599 #ifdef DEBUGBMP\r
1600           if (traceflag) {\r
1601             sprintf(logline, " buffered: %d,", s - lpBuffer);\r
1602             showline(logline, 1);\r
1603           }\r
1604 #endif\r
1605         }\r
1606         else {    /* c == 0 */\r
1607           c = getc(input);  /* pixel count */\r
1608 #ifdef DEBUGBMP\r
1609           if (traceflag) {\r
1610             sprintf(logline, " literal %d", c);\r
1611             showline(logline, 1);\r
1612           }\r
1613 #endif\r
1614           if (c > 2) {    /* literal group */\r
1615             for (k = 0; k < c; k++) {\r
1616               if (k % 2 == 0) {\r
1617                 d = getc(input);\r
1618                 e = d & 15;     /* decompose right nibble */\r
1619                 d = d >> 4;     /* decompose left nibble */\r
1620 #ifdef DEBUGBMP\r
1621                 if (traceflag) {\r
1622                   sprintf(logline, " %d %d", d, e);\r
1623                   showline(logline, 1);\r
1624                 }\r
1625 #endif\r
1626                 nibble = d;\r
1627               }\r
1628               else nibble = e;\r
1629 /*              now stuff nibble */\r
1630               if (evenflag) *s = (unsigned char) (nibble << 4);\r
1631 /*              else *s++ = *s | nibble; */\r
1632               else *s++ = (unsigned char) (*s | nibble);\r
1633               evenflag = 1 - evenflag;\r
1634             }\r
1635             n = 2 + (c+1)/2;    /* bytes read */\r
1636             if ((n % 2) != 0) {   /* padded out to even bytes */\r
1637               d = getc(input);\r
1638 #ifdef DEBUGBMP\r
1639               if (traceflag) {\r
1640                 sprintf(logline, " discard: %d", d);\r
1641                 showline(logline, 1);\r
1642               }\r
1643 #endif\r
1644             }\r
1645 #ifdef DEBUGBMP\r
1646             if (traceflag) {\r
1647               sprintf(logline, " buffered: %d,", s - lpBuffer);\r
1648               showline(logline, 1);\r
1649             }\r
1650 #endif\r
1651           }\r
1652           else if (c == 0) {\r
1653             if (evenflag++ == 0) s++; /* pad last nibble */\r
1654 #ifdef DEBUGBMP\r
1655             if (traceflag) {\r
1656               sprintf(logline, " EOL\n");\r
1657               showline(logline, 1);\r
1658             }\r
1659 #endif\r
1660             if (s < lpBuffer + InRowLength) {\r
1661               sprintf(logline, " Did not fill row %d %d\n",\r
1662                   s - lpBuffer, InRowLength);\r
1663               showline(logline, 1);\r
1664               while (s < lpBuffer + InRowLength) *s++ = '\0';\r
1665             }\r
1666             while (s < lpBuffer + InRowRead) *s++ = '\0';\r
1667             break;  /* end of row */\r
1668           }\r
1669           else if (c == 1) {\r
1670 #ifdef DEBUGBMP\r
1671             if (traceflag) {\r
1672               showline(" EOI\n", 0);\r
1673             }\r
1674 #endif\r
1675             if (i != (int) ImageLength - 1) {\r
1676 #ifdef DEBUGBMP\r
1677               if (traceflag) {\r
1678                 sprintf(logline, "i+1 %d ImageLength %d\n",\r
1679                     i+1, ImageLength);\r
1680                 showline(logline, 0);\r
1681               }\r
1682 #endif\r
1683               showline(" Premature end of image\n", 1);\r
1684             }\r
1685             break;  /* end of picture */\r
1686           }\r
1687           else if (c == 2) {  /* rats! */\r
1688             showline(" Skips not implemented\n", 1);\r
1689           }\r
1690         }\r
1691       }\r
1692       nread = s - lpBuffer;\r
1693     }\r
1694     else {  /* decompress, eight bit images only so far */\r
1695       s = lpBuffer;\r
1696       while (s <= lpBuffer + InRowRead) {\r
1697         c = getc(input);\r
1698 #ifdef DEBUGBMP\r
1699         if (traceflag) {\r
1700           sprintf(logline, " %d", c);\r
1701           showline(logline, 0);\r
1702         }\r
1703 #endif\r
1704         if (c > 0) {      /* repeating group */\r
1705           d = getc(input);  /* pixel */\r
1706 #ifdef DEBUGBMP\r
1707           if (traceflag) {\r
1708             sprintf(logline, " repeat: %d", d);\r
1709             showline(logline, 0);\r
1710           }\r
1711 #endif\r
1712 /*          for (k = 0; k < c; k++) *s++ = d; */\r
1713           for (k = 0; k < c; k++) *s++ = (unsigned char) d;\r
1714 #ifdef DEBUGBMP\r
1715           if (traceflag) {\r
1716             sprintf(logline, " buffered: %d,", s - lpBuffer);\r
1717             showline(logline, 0);\r
1718           }\r
1719 #endif\r
1720         }\r
1721         else {\r
1722 #ifdef DEBUGBMP\r
1723           if (traceflag) {\r
1724             sprintf(logline, " buffered: %d,", s - lpBuffer);\r
1725             showline(logline, 0);\r
1726           }\r
1727 #endif\r
1728           c = getc(input);  /* pixel count */\r
1729 #ifdef DEBUGBMP\r
1730           if (traceflag) {\r
1731             sprintf(logline, " %d", c);\r
1732             showline(logline, 0);\r
1733           }\r
1734 #endif\r
1735           if (c > 2) {    /* literal group */\r
1736             for (k = 0; k < c; k++) {\r
1737               d = getc(input);\r
1738               *s++ = (unsigned char) d;\r
1739 #ifdef DEBUGBMP\r
1740               if (traceflag) {\r
1741                 sprintf(logline, " %d", d);\r
1742                 showline(logline, 0);\r
1743               }\r
1744 #endif\r
1745             }\r
1746             if ((c % 2) != 0) {   /* padded out to even bytes */\r
1747               d = getc(input);\r
1748 #ifdef DEBUGBMP\r
1749               if (traceflag) {\r
1750                 sprintf(logline, " %d", d);\r
1751                 showline(logline, 0);\r
1752               }\r
1753 #endif\r
1754             }\r
1755           }\r
1756           else if (c == 0) {\r
1757             if (evenflag++ == 0) *s++ = '\0'; /* pad last byte */\r
1758 #ifdef DEBUGBMP\r
1759             if (traceflag) {\r
1760               sprintf(logline, " EOL\n");\r
1761               showline(logline, 0);\r
1762             }\r
1763 #endif\r
1764             if (s < lpBuffer + InRowLength) {\r
1765               sprintf(logline, " Did not fill row %d %d\n",\r
1766                    s - lpBuffer, InRowLength);\r
1767               showline(logline, 1);\r
1768               while (s < lpBuffer + InRowLength) *s++ = '\0';\r
1769             }\r
1770             while (s < lpBuffer + InRowRead) *s++ = '\0';\r
1771             break;  /* end of row EOL */\r
1772           }\r
1773           else if (c == 1) {\r
1774             if (evenflag++ == 0) *s++ = '\0';;    /* pad last byte */\r
1775 #ifdef DEBUGBMP\r
1776             if (traceflag) showline(" EOI\n", 0);\r
1777 #endif\r
1778             if (i != (int) ImageLength - 1) {\r
1779               showline(" Premature end of image\n", 1);\r
1780             }\r
1781             break;  /* end of picture EOF */\r
1782           }\r
1783           else if (c == 2) {  /* rats! */\r
1784             showline(" Skips not implemented\n", 1);\r
1785           }\r
1786         }\r
1787       }\r
1788       nread = s - lpBuffer;\r
1789     }\r
1790 /*    if (nread != (unsigned int) InRowLength) */\r
1791     if (nread != (unsigned int) InRowRead) {\r
1792       flag = -1;\r
1793 #ifdef DEBUGBMP\r
1794       if (traceflag) {\r
1795         sprintf(logline, "nread %d InRowRead %d\n", nread, InRowRead);\r
1796         showline(logline, 1);\r
1797       }\r
1798 #endif\r
1799       showline(" ERROR: Premature EOF\n", 1);\r
1800       break;\r
1801     } \r
1802 \r
1803     if (ProcessRow (output, lpBuffer, InRowLength, BufferLength,\r
1804             OutRowLength) != 0) {\r
1805       showline(" Output error\n", 1);     /* BMP */\r
1806       perrormod((outputfile != NULL) ? outputfile : "");\r
1807       break;\r
1808     }\r
1809 /*      if (flag != 0) break; *//* hit EOF or other error */\r
1810 /*      check on abort flag here somewhere also ? */\r
1811   } /* end of this row */\r
1812 \r
1813 //  Have to flush filters in reverse order\r
1814 #ifdef PSLEVEL2\r
1815   if (bLevel2) {\r
1816     if (bRunLengthFlag) RUNflushfilter(output); /* 96/Dec/24 */\r
1817 #ifdef LZWCOMPRESSION\r
1818     else if (bLZWFlag) LZWflushfilter(output);  /* 96/Dec/28 */\r
1819 #endif\r
1820     ASCIIflushfilter(output);       /* 96/Dec/20 */\r
1821   }\r
1822 #endif\r
1823 \r
1824 /* now finished reading */  /* maybe use far memory for lpBuffer ? */\r
1825 \r
1826   if (lpBuffer != NULL) {\r
1827     free(lpBuffer);\r
1828     lpBuffer = NULL;\r
1829   }\r
1830   if (Palette != NULL) {\r
1831     free(Palette);\r
1832     Palette = NULL;\r
1833   }\r
1834   writepstrailer(output);\r
1835   return flag;\r
1836 /*  UNDER CONSTRUCTION !!! */\r
1837 }    /* end of readBMPfile(...) */\r
1838   \r
1839 \r
1840 /**********************************************************************/\r
1841 \r
1842 /* Try and see whether EPSF file and read header info if so: */\r
1843 /* fills in TIFFOffset and PSOffset and MetaOffset and lengths */\r
1844 /* returns zero if not an EPSF file */ /* file position is end of EPSF head */\r
1845 \r
1846 int readepsfhead (FILE *special)\r
1847 {\r
1848   int c, d, e, f;\r
1849 \r
1850   PSOffset = 0;       /* redundant */\r
1851   MetaOffset = 0;       /* redundant */\r
1852   TIFFOffset = 0;       /* redundant */\r
1853 \r
1854   c = getc(special); d = getc(special);\r
1855   e = getc(special); f = getc(special);\r
1856   if (c == 'E' + 128 && d == 'P' + 128 &&\r
1857     e == 'S' + 128 && f == 'F' + 128) {\r
1858     bLeastFirst = 1;\r
1859     PSOffset = (long) ureadfour(special); /* read PS start offset */ \r
1860     PSLength = (long) ureadfour(special); /* read PS length */\r
1861     MetaOffset = (long) ureadfour(special); /* read MF start offset */\r
1862     MetaLength = (long) ureadfour(special); /* read MF length */\r
1863     TIFFOffset = (long) ureadfour(special); /* read TIFF start offset */\r
1864     TIFFLength = (long) ureadfour(special); /* read TIFF length */\r
1865     (void) ureadtwo(special);     /* should be 255, 255 */\r
1866     return -1;\r
1867   }\r
1868   else return 0;              /* not an EPSF file */\r
1869 }\r
1870 \r
1871 int BMPflag=0;    /* non-zero while processing BMP image */\r
1872 \r
1873 int readimagefilesub (FILE *output, FILE *special,\r
1874   long dwidth, long dheight, int nifd, int readflag)\r
1875 {\r
1876 /*  long present; */\r
1877   int c, d; \r
1878 \r
1879   TIFFOffset = 0;       /* normally beginning of file */\r
1880   PSOffset = 0;\r
1881   MetaOffset = 0;\r
1882   BMPflag=0;\r
1883 \r
1884   c = getc(special);\r
1885   (void) ungetc(c, special);\r
1886   if (c > 128) {        /* see whether perhaps EPSF file */\r
1887     if (readepsfhead(special) != 0) {     /* is it EPSF file ? */\r
1888 /*    If valid EPSF header with pointer to TIFF we get here */\r
1889     if (TIFFOffset == 0 || TIFFLength == 0) {\r
1890         showline(" ERROR: Zero TIFF offset or length\n", 1);\r
1891         return -1;\r
1892       }\r
1893       if (fseek(special, TIFFOffset, SEEK_SET) != 0)\r
1894       {\r
1895         sprintf(logline, " Error in seek %s\n", "to TIFFOffset\n");\r
1896         showline(logline, 1);\r
1897         return -1;\r
1898       }\r
1899     }\r
1900     else {\r
1901       showline(" ERROR: Not a valid EPSF or TIFF file\n", 1);\r
1902       return -1;\r
1903     }\r
1904   }             /* end of c > 128 (EPSF file) */\r
1905 \r
1906 /*  Try and deal with PostScript ASCII stuff */\r
1907 /*  Or may meet TIFF / BMP preamble */ \r
1908   c = getc(special); d = getc(special);\r
1909   if (c == '%' && d == '!') {   /* ordinary PS file ? */\r
1910     showline(" ERROR: Ordinary PS file, not TIFF\n", 1);\r
1911     return -1;\r
1912   }\r
1913   else if (c == 'I' && d == 'I') bLeastFirst = 1; /* PC style TIFF file */\r
1914   else if (c == 'M' && d == 'M') bLeastFirst = 0; /* Mac style TIFF file */\r
1915   else if (c == 'B' && d == 'M') BMPflag = 1;   /* BMP 98/Jun/28 */\r
1916   else {\r
1917     showline(" ERROR: Not a valid EPSF, TIFF or BMP file\n", 1);\r
1918     return -1;    /* not a TIFF subfile !!! */\r
1919   }\r
1920 \r
1921 /*  now have decided that this is a TIFF file (or TIFF preview) or BMP */\r
1922   if (BMPflag)\r
1923     (void) readBMPfile(output, special, dwidth, dheight, readflag);\r
1924   else\r
1925     (void) readTIFFfile(output, special, dwidth, dheight, nifd, readflag);\r
1926   return 0;\r
1927 }\r
1928 \r
1929 /*  In prescan to read TIFF tags, readflag = 1 */\r
1930 /*  Later, when actually using the file, readflag = 0 */\r
1931 /*  Prescan only happens if dheight and dwidth are not already given */\r
1932 /*  Returns -1 if file not found */\r
1933 \r
1934 int readimagefile (FILE *output, char *filename,\r
1935   long dwidth, long dheight, int nifd, int readflag)\r
1936 {\r
1937 /*  char infilename[FILENAME_MAX]; */ /* make global */\r
1938   FILE *special;\r
1939 /*  long present;  */\r
1940   int flag;\r
1941 \r
1942   strcpy(infilename, filename);\r
1943 /*  if ((special = findepsfile(infilename, -1, "tif")) == NULL) { */\r
1944 /*  if ((special = findepsfile(infilename, "tif", 1, readflag)) == NULL) */\r
1945 /*  1996/Mar/2 don't warn during prescan when readflag = 1 ??? */\r
1946   if ((special = findepsfile(infilename, "tif", !readflag, readflag)) == NULL)\r
1947     return -1;          \r
1948 \r
1949 #ifdef DEBUGTIFF\r
1950   if (traceflag)\r
1951   {\r
1952     sprintf(logline, "\nManaged to open file %s\n", infilename);\r
1953     showline(logline, 0);\r
1954   }\r
1955 #endif\r
1956   flag = readimagefilesub (output, special, dwidth, dheight, nifd, readflag);\r
1957   fclose(special);\r
1958   return flag;\r
1959 }\r
1960 \r
1961 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
1962 \r
1963 int column;\r
1964 \r
1965 /* Bitspersample can be 1, 2, 4, 8 for ease of conversion to PS */\r
1966 /* Each row takes an integral number of bytes */\r
1967 \r
1968 /* Expand palette color image into full RGB color image */\r
1969 /* Presently only set up for 8 bit palettes ... !!! */\r
1970 \r
1971 void expandcolor (unsigned char *lpBuffer, long width)\r
1972 {\r
1973   int k, n, ns;\r
1974 #ifdef USESHORTINT\r
1975   unsigned short int *PaletteRed;\r
1976   unsigned short int *PaletteGreen;\r
1977   unsigned short int *PaletteBlue;\r
1978 #else\r
1979   unsigned int *PaletteRed;\r
1980   unsigned int *PaletteGreen;\r
1981   unsigned int *PaletteBlue;\r
1982 #endif\r
1983   unsigned char *s;\r
1984   unsigned char *t;\r
1985   unsigned int red=0, green=0, blue=0;\r
1986   int PaletteIndex, Mask;\r
1987   int Byte = 0, BitsLeft = 0;\r
1988 \r
1989 #ifdef DEBUGTIFF\r
1990 /*  if (traceflag) printf("Palette Color => Color "); */\r
1991 #endif\r
1992 \r
1993   if (Palette == NULL)\r
1994   {\r
1995     showline(" ERROR: missing palette information\n", 1);\r
1996     return;\r
1997   }\r
1998   PaletteRed = Palette;\r
1999   PaletteGreen = PaletteRed + PaletteSize;\r
2000   PaletteBlue = PaletteGreen + PaletteSize;\r
2001   Mask = (1 << BitsPerSample) - 1;\r
2002 \r
2003 /*  First slide input data upwards to top of buffer area */\r
2004 \r
2005   n = (int) width;          /* InRowLengthX */\r
2006   ns = (int) ImageWidth;        /* samples per row */\r
2007 \r
2008 /*  if (BufferLength <= InRowLength) */\r
2009   if (BufferLength <= InRowLengthX) {\r
2010     showline(" ERROR: buffer overflow\n", 1);\r
2011     return;\r
2012   }\r
2013 \r
2014 /*  possibly use InRowLengthX ? in next two places */\r
2015 \r
2016   for (k = n-1; k >= 0; k--)  /* move it up to end of lpBuffer space */\r
2017 /*    lpBuffer[k + BufferLength - InRowLength] = lpBuffer[k]; */\r
2018     lpBuffer[k + BufferLength - InRowLengthX] = lpBuffer[k];\r
2019   \r
2020 /*  s = lpBuffer + BufferLength - InRowLength; */ /* start of input data */\r
2021   s = lpBuffer + BufferLength - InRowLengthX; /* start of input data */\r
2022   if (BitsPerSample != 8) {         /* nibble code init */\r
2023     Byte = 0; BitsLeft = 0;\r
2024   }\r
2025   t = lpBuffer;               /* start of output data */\r
2026   for (k = 0; k < ns; k++) {\r
2027     if (BitsPerSample != 8) {       /* slow, but inefficient ! */\r
2028       if (BitsLeft <= 0) {\r
2029         Byte = *s++; BitsLeft = 8;\r
2030       }\r
2031       BitsLeft -= BitsPerSample;\r
2032 /*      PaletteIndex = Byte >> (BitsPerSample - BitsLeft); */\r
2033       PaletteIndex = Byte >> BitsLeft;\r
2034       PaletteIndex = PaletteIndex & Mask;\r
2035 /*      BitsLeft -= BitsPerSample; */\r
2036     }\r
2037     else PaletteIndex = *s++;\r
2038     if (PaletteIndex < PaletteSize) {\r
2039       red = PaletteRed[PaletteIndex];\r
2040       green = PaletteGreen[PaletteIndex];\r
2041       blue = PaletteBlue[PaletteIndex];\r
2042     }\r
2043     else {\r
2044       sprintf(logline, " ERROR: Bad Palette Index %d >= %d\n",\r
2045           PaletteIndex, PaletteSize);\r
2046       showline(logline, 1);\r
2047     }\r
2048 #ifdef DEBUGTIFF\r
2049     if (traceflag) {\r
2050       sprintf(logline, "INX %d\tR %u\tG %u\tB %u\n",\r
2051                 PaletteIndex, red, green, blue); \r
2052       showline(logline, 0);\r
2053     }\r
2054 #endif\r
2055     if (BMPflag) {        /* BMP */\r
2056       *t++ = (unsigned char) red; \r
2057       *t++ = (unsigned char) green; \r
2058       *t++ = (unsigned char) blue;\r
2059     }\r
2060     else {            /* TIFF */\r
2061       *t++ = (unsigned char) (red >> 8); \r
2062       *t++ = (unsigned char) (green >> 8); \r
2063       *t++ = (unsigned char) (blue >> 8);\r
2064     }\r
2065   } \r
2066 }\r
2067 \r
2068 /* This is called for BMP image when palette is used, but it is gray */\r
2069 /* (i.e. R=G=B) and it is *not* linear (i.e. Palette[k] == k) */\r
2070 \r
2071 void expandgray (unsigned char *lpBuffer, long width)\r
2072 {\r
2073   int k, n, ns;\r
2074 #ifdef USESHORTINT\r
2075   unsigned short int *PaletteRed;\r
2076   unsigned short int *PaletteGreen;\r
2077   unsigned short int *PaletteBlue;\r
2078 #else\r
2079   unsigned int *PaletteRed;\r
2080   unsigned int *PaletteGreen;\r
2081   unsigned int *PaletteBlue;\r
2082 #endif\r
2083   unsigned char *s;\r
2084   unsigned char *t;\r
2085   unsigned int red, green, blue;\r
2086   int PaletteIndex, Mask;\r
2087   int Byte = 0, BitsLeft = 0;\r
2088 \r
2089 #ifdef DEBUGBMP\r
2090 /*  if (traceflag) printf("Palette Gray => Gray ");  */\r
2091 #endif\r
2092 \r
2093   if (Palette == NULL)\r
2094   {\r
2095     showline(" ERROR: missing palette information\n", 1);\r
2096     return;\r
2097   }\r
2098   PaletteRed = Palette;\r
2099   PaletteGreen = PaletteRed + PaletteSize;\r
2100   PaletteBlue = PaletteGreen + PaletteSize;\r
2101   Mask = (1 << BitsPerSample) - 1;\r
2102 \r
2103 /*  First slide input data upwards to top of buffer area */\r
2104 \r
2105   n = (int) width;          /* InRowLength */\r
2106   ns = (int) ImageWidth;        /* samples per row */\r
2107 \r
2108 /*  if (BufferLength <= InRowLength) */\r
2109   if (BufferLength <= InRowLengthX)\r
2110   {\r
2111     showline(" ERROR: buffer overflow\n", 1);\r
2112     return;\r
2113   }\r
2114 \r
2115   for (k = n-1; k >= 0; k--)\r
2116 /*    lpBuffer[k + BufferLength - InRowLength] = lpBuffer[k]; */\r
2117     lpBuffer[k + BufferLength - InRowLengthX] = lpBuffer[k];\r
2118 \r
2119 /*  s = lpBuffer + BufferLength - InRowLength; */ /* start of input data */\r
2120   s = lpBuffer + BufferLength - InRowLengthX;   /* start of input data */\r
2121   if (BitsPerSample != 8) {         /* nibble code init */\r
2122     Byte = 0; BitsLeft = 0;\r
2123   }\r
2124   t = lpBuffer;               /* start of output data */\r
2125   for (k = 0; k < ns; k++) {\r
2126     if (BitsPerSample != 8) {       /* slow, but inefficient ! */\r
2127       if (BitsLeft <= 0) {\r
2128         Byte = *s++; BitsLeft = 8;\r
2129       }\r
2130       BitsLeft -= BitsPerSample;\r
2131 /*      PaletteIndex = Byte >> (BitsPerSample - BitsLeft); */\r
2132       PaletteIndex = Byte >> BitsLeft;\r
2133       PaletteIndex = PaletteIndex & Mask;\r
2134 /*      BitsLeft -= BitsPerSample; */\r
2135     }\r
2136     else PaletteIndex = *s++;\r
2137     if (PaletteIndex < PaletteSize) {\r
2138       red = PaletteRed[PaletteIndex];\r
2139       green = PaletteGreen[PaletteIndex];   /* not used */\r
2140       blue = PaletteBlue[PaletteIndex];   /* not used */\r
2141     }\r
2142     else {\r
2143       sprintf(logline, " ERROR: Bad Palette Index %d >= %d\n",\r
2144            PaletteIndex, PaletteSize);\r
2145       showline(logline, 1);\r
2146       red = green = blue = 0;         /* keep compiler happy */\r
2147     }\r
2148 #ifdef DEBUGTIFF\r
2149 /*    if (traceflag) printf("Index %d red %u green %u blue %u\n", */\r
2150     if (traceflag) {\r
2151       sprintf(logline, "INX %d\tR %u\tG %u\tB %u\n",\r
2152           PaletteIndex, red, green, blue); \r
2153       showline(logline, 0);\r
2154     }\r
2155 #endif\r
2156     if (BMPflag) *t++ = (unsigned char) red; /* BMP */\r
2157     else *t++ = (unsigned char) (red >> 8);  /* TIFF */\r
2158   } \r
2159 }\r
2160 \r
2161 /* gray = 0.3 * red + 0.59 * green + 0.11 * blue */\r
2162 \r
2163 void compresscolor (unsigned char *lpBuffer, long width)\r
2164 {\r
2165   int k, n;\r
2166   unsigned char *s;\r
2167   unsigned char *t;\r
2168   unsigned int red, green, blue, gray;\r
2169 \r
2170 #ifdef DEBUGTIFF\r
2171   if (traceflag) showline("Color => Gray ", 0);\r
2172 #endif\r
2173   s = lpBuffer; t = lpBuffer;\r
2174   n = (int) (width / 3);\r
2175   for (k = 0; k < n; k++) {\r
2176     red = *s++; green = *s++; blue = *s++;\r
2177     gray = (int) (((long) blue * 28 + (long) red * 77 + (long) green * 151)\r
2178       >> 8);\r
2179     *t++ = (unsigned char) gray;\r
2180   } \r
2181\r
2182 \r
2183 /*****************************************************************************/\r
2184 \r
2185 #ifdef PSLEVEL2\r
2186 \r
2187 //#pragma optimize ("lge", on)    /* 2000 June 17 */\r
2188 \r
2189 /* use ASCII85Encode if bLevel2 enabled */\r
2190 \r
2191 /* ASCII85 encoding (b1 b2 b3 b4) => (c1 c2 c3 c4 c5) */\r
2192 \r
2193 /* b1 * 256^3 + b2 * 256^2 + b3 * 256  + b4 = \r
2194    c1 * 85^4  + c2 * 85^3  + c3 * 85^2 + c4 * 85 + c5 */\r
2195 \r
2196 /* Add `!' =  33 to make ASCII code. ! represents 0, u represent 84. */\r
2197 \r
2198 /* If all five digits are zero, use z instead of !!!!! - special case. */\r
2199 \r
2200 /* At end, given n = 1, 2, 3 bytes of binary data, append 4 - n zeros.\r
2201    Encode this in usual way (but *without* z special case). \r
2202    Write first (n+1) bytes.  Follow by -> (EOD) */\r
2203 \r
2204 unsigned long asciinum = 0;   /* accumulated so far up to four bytes */\r
2205 int asciicount = 0;       /* how many bytes accumulated so far */  \r
2206 \r
2207 /* Output 4 bytes --- 32 bit unsigned int --- as 5 ASCII 85 bytes */\r
2208 /* nbytes is number of bytes accumulated, which is 4 until the last time */\r
2209 /* Move this inline for speed ? */\r
2210 \r
2211 void ASCIIlong (FILE *output, unsigned long n, int nbytes)\r
2212 {\r
2213   unsigned int c[5];\r
2214   int k;\r
2215 \r
2216 //  sprintf(logline, "ASCIIlong %08X %d ", n, nbytes);\r
2217 //  showline(logline, 0);   // debugging only\r
2218   if (nbytes == 0) nbytes--;      /* nothing to do at end - avoid ! */\r
2219   if (n == 0 && nbytes == 4) {    /* special case !!!!! => z */\r
2220     PSputc('z', output);      /* shorthand for !!!!! */\r
2221     column++;\r
2222     if (column >= MAXCOLUMNASCII) {\r
2223       PSputc('\n', output);\r
2224       column = 0;\r
2225     }\r
2226     return;\r
2227   }\r
2228   for (k = 4; k >= 0; k--) {    /* get base 85 digits reverse order */\r
2229     c[k] = (unsigned int) (n % 85);\r
2230     n = n / 85;\r
2231   }\r
2232   for (k = 0; k < 5; k++) {   /* spit them out in correct order */\r
2233     if (nbytes-- < 0) {         /* last one, finish with EOD */\r
2234       if (column+1 >= MAXCOLUMNASCII) { /* see if space for ~> */\r
2235         PSputc('\n', output);\r
2236         column = 0;\r
2237       }\r
2238       PSputs("~>\n", output); /* EOD */\r
2239       column = 0;\r
2240       return;\r
2241     }\r
2242     PSputc((char) (c[k] + '!'), output);\r
2243     column++;\r
2244     if (column >= MAXCOLUMNASCII) {\r
2245       PSputc('\n', output);\r
2246       column = 0;\r
2247     }\r
2248   } /* end of for k = 0; k < 5; k++ */\r
2249 }\r
2250 \r
2251 /* Output single byte (accumulate until four seen, then call ASCIIlong) */\r
2252 /* Move this inline for speed ? */\r
2253 \r
2254 void ASCIIout (FILE *output, unsigned int x)\r
2255 {\r
2256 //  sprintf(logline, "ASCII %d ", x);\r
2257 //  showline(logline, 0);     // debugging only\r
2258   if (x > 255) x = x & 255;   // sanity check ???\r
2259   asciinum = (asciinum << 8) | x;\r
2260   asciicount++;\r
2261   if (asciicount >= 4) {\r
2262     ASCIIlong(output, asciinum, asciicount);\r
2263     asciinum = 0;\r
2264     asciicount = 0;\r
2265   }\r
2266 }\r
2267 \r
2268 /* initialize ASCII85 filter */\r
2269 \r
2270 void ASCIIinitfilter (FILE *output)   /* 96/Dec/20 */\r
2271 {\r
2272 //  showline("ASCIIinitfilter ", 0);  // debugging only\r
2273   asciinum = 0;\r
2274   asciicount = 0;\r
2275   column = 0;     /* ??? */\r
2276 }\r
2277 \r
2278 void RUNinitfilter (FILE *output)    /* 95/Dec/24 */\r
2279 {\r
2280 /*  apparently nothing special to do */\r
2281 }\r
2282 \r
2283 /* flush out anything left in ASCII85 filter */\r
2284 \r
2285 void ASCIIflushfilter (FILE *output)  /* 96/Dec/20 */\r
2286 {\r
2287   int k;\r
2288 //  showline("ASCIIflushfilter ", 0); // debugging only\r
2289   for (k = asciicount; k < 4; k++) {\r
2290     asciinum = (asciinum << 8);   /* append n-4 zeros */\r
2291   }\r
2292   ASCIIlong(output, asciinum, asciicount);\r
2293   asciinum = 0;\r
2294   asciicount = 0;\r
2295 }\r
2296 \r
2297 void RUNflushfilter (FILE *output)\r
2298 {\r
2299   ASCIIout(output, 128);          /* EOD */\r
2300 }\r
2301 \r
2302 /*****************************************************************************/\r
2303 \r
2304 /* write a row in ASCII85 format */\r
2305 \r
2306 void writearowASCII (FILE *output, unsigned char *s, unsigned long width)\r
2307 {\r
2308   unsigned int c;\r
2309   int k, n, i;\r
2310   unsigned long num;\r
2311 \r
2312   n = (int) width;\r
2313   k = 0;\r
2314   if (asciicount > 0) { /* finish off group of four bytes first */\r
2315     for (i = asciicount; i < 4; i++) {\r
2316       ASCIIout(output, *s++);\r
2317       k++;\r
2318       if (k >= n) break;  /* in case of miniscule width! */\r
2319     }\r
2320   }\r
2321   while (k < n-3) {   /* then do groups of four bytes */\r
2322     num = 0;\r
2323     for (i = 0; i < 4; i++) {\r
2324       c = *s++;\r
2325       num = (num << 8) | c;\r
2326     }\r
2327     ASCIIlong(output, num, 4);\r
2328     k += 4;\r
2329   }\r
2330   while (k < n) {     /* then do remaining bytes at tail of row */\r
2331     ASCIIout(output, *s++);\r
2332     k++;\r
2333   }\r
2334 }\r
2335 \r
2336 /**************************************************************************/\r
2337 \r
2338 #if (defined(DEBUGLZWENCODE) || defined(DEBUGRUNLENGTH))\r
2339 int debugflag=1;      /* debugging output */\r
2340 #endif\r
2341 \r
2342 /* Do run encoding per row (rather than image) --- easier, if not optimal */\r
2343 \r
2344 void dumprun(FILE *output, int nlen, int previous)\r
2345 {\r
2346 #ifdef DEBUGRUNLENGTH\r
2347   int i;\r
2348   if (nlen <= 0) {\r
2349     sprintf(logline, "Zero length run %d ", nlen);\r
2350     showline(logline, 0);\r
2351     return;\r
2352   }\r
2353   else if (nlen < 3) {\r
2354     sprintf(logline, " ERROR: run %d < 3\n", nlen);\r
2355     showline(logline, 1);\r
2356   }\r
2357   else if (nlen > 128) {\r
2358     sprintf(logline, " ERROR: run %d > 128", nlen);\r
2359     showline(logline, 1);\r
2360   }\r
2361   for (i = 0; i < nlen; i++) {\r
2362     sprintf(logline, "%02X", previous);\r
2363     showline(logline, 1);\r
2364   }\r
2365 #endif\r
2366   ASCIIout(output, 257 - nlen);\r
2367   ASCIIout(output, previous);\r
2368 }\r
2369 \r
2370 void dumpnonrun(FILE *output, int nlen, unsigned char *buffer)\r
2371 {\r
2372   int i;\r
2373   unsigned char *s;\r
2374 \r
2375 #ifdef DEBUGRUNLENGTH\r
2376   if (nlen <= 0) {\r
2377     sprintf(logline, "Zero length nonrun %d ", nlen);\r
2378     showline(logline, 0);\r
2379     return;\r
2380   }\r
2381   if (nlen > 128) {\r
2382     sprintf(logline, " ERROR: nonrun %d > 128", nlen);\r
2383     showline(logline, 1);\r
2384   }\r
2385   if (debugflag) {\r
2386     s = buffer;\r
2387     for (i = 0; i < nlen; i++) {\r
2388       int c;\r
2389       c = *s++;\r
2390       sprintf(logline, "%02X", c);\r
2391       showline(logline, 1);\r
2392     }\r
2393   }\r
2394 #endif\r
2395   ASCIIout(output, nlen - 1);\r
2396   s = buffer;\r
2397   for (i = 0; i < nlen; i++) ASCIIout(output, *s++);\r
2398 }\r
2399 \r
2400 /* RunLengthEncode filter */\r
2401 \r
2402 /* This basically has two states: */\r
2403 /* (1) accumulating non-run (runflag == 0) */\r
2404 /* (2) accumulating run (runflag != 0) */\r
2405 /* Here (1) is the starting state */\r
2406 /* Dumps out when (i) state changes (ii) 128 bytes seen (iii) end input */\r
2407 \r
2408 void writearowrun (FILE *output, unsigned char *s, unsigned long width)\r
2409 {\r
2410   int runflag;      /* non-zero if in accumulating run state */\r
2411   int previous;     /* character that appears to be repeating */\r
2412   int repeat;       /* how many times we have seen previous */\r
2413   int bcount;       /* count of bytes buffered up (s-new) */\r
2414   unsigned char *new;   /* points to part of string not yet dumped */\r
2415   int n, k, c;\r
2416 \r
2417   n = (int) width;\r
2418   k = 0;\r
2419   bcount = 0;       /* non run length accumulated */\r
2420   new = s;        /* points to first byte not yet output */\r
2421   previous = -1;      /* previous character in a run */\r
2422   repeat = 0;       /* how many repetetions of previous */\r
2423   runflag = 0;      /* start in non run state */\r
2424 \r
2425   while (k < n) {\r
2426     c = *s;       /* grab next byte */\r
2427     if (runflag) {        /* accumulating a run ? */\r
2428       if (repeat >= 128) {  /* run too long ? */\r
2429         dumprun(output, repeat, previous);\r
2430         new = s;\r
2431         previous = c;\r
2432         repeat = 1;\r
2433         bcount = 1;\r
2434         runflag = 0;      /* switch back to non run state */\r
2435       }\r
2436       else if (c == previous) { /* continue the run ? */\r
2437         repeat++;\r
2438       }\r
2439       else {            /* c != previous --- end of a run */\r
2440         dumprun(output, repeat, previous);\r
2441         new = s;\r
2442         previous = c;\r
2443         repeat = 1;\r
2444         bcount = 1;\r
2445         runflag = 0;      /* switch back to non run state */\r
2446       }\r
2447     }\r
2448     else {            /* runflag == 0 accumulating a non run */\r
2449       if (bcount >= 128) {  /* accumulated too much ? */\r
2450         dumpnonrun(output, bcount, new);\r
2451         new = s;\r
2452         previous = c;\r
2453         bcount = 1;\r
2454         repeat = 1;\r
2455 /*        and stay in non run mode */\r
2456       }\r
2457       else if (c == previous) {\r
2458         repeat++;\r
2459         if (repeat >= 4) {  /* end of non-run */\r
2460           if (bcount+1 > repeat)\r
2461             dumpnonrun(output, bcount-repeat+1, new);\r
2462           bcount = 0;         /* needed ? */\r
2463           runflag = 1;  /* switch to accumulating run state */\r
2464 /*          don't change previous, repeat */\r
2465         }\r
2466         if (runflag == 0) bcount++;\r
2467       }\r
2468       else {\r
2469         bcount++;\r
2470         previous = c;\r
2471 /*        don't change new, bcount */\r
2472         repeat = 1;\r
2473       }\r
2474     }\r
2475     s++;\r
2476     k++;\r
2477   } /* end of while loop */\r
2478 #ifdef DEBUGRUNLENGTH\r
2479 /*  if (debugflag) showline("EOL ", 0); */\r
2480 #endif\r
2481   if (runflag) dumprun(output, repeat, previous);\r
2482   else if (repeat >= bcount  && repeat > 1)\r
2483     dumprun(output, repeat, previous);\r
2484   else dumpnonrun(output, bcount, new);\r
2485 #ifdef DEBUGRUNLENGTH\r
2486   if (debugflag) showline("\n", 0);\r
2487 #endif\r
2488 }\r
2489 \r
2490 /**************************************************************************/\r
2491 \r
2492 /* code for LZW compression on OUTPUT side  LZWcompress rewrite 2000 June 17 */\r
2493 \r
2494 #ifdef LZWCOMPRESSION\r
2495 \r
2496 struct NODE {\r
2497   int chr;      // byte to get to this node --- or -1\r
2498 //  NODE nextinlist;  // next in list at this level ptr\r
2499   int nextinlist;   // next in list at this level\r
2500 //  NODE nextlevel;   // first at next level ptr\r
2501   int nextlevel;    // first at next level\r
2502 };\r
2503 \r
2504 // May get some added performance by making the last two components be\r
2505 // pointers rather than indeces...\r
2506 \r
2507 struct NODE *node=NULL;   // array of nodes --- allocated\r
2508 \r
2509 int currentnode;  // code of node currently at\r
2510 int nextnode;   // code of next node to be used\r
2511 int codelength;   // how many bits needed for code at this stage 9, 10, 11, 12\r
2512 \r
2513 void DeAllocStringsOut (void) // called from dvibody() in dvipsone.c\r
2514 {\r
2515   if (node != NULL) {\r
2516     free(node);\r
2517     node = NULL;\r
2518   }\r
2519 }\r
2520 \r
2521 void CleanOut (FILE *output, int n)\r
2522 {\r
2523   int k;\r
2524 \r
2525 //  sprintf(logline, "CLEANOUT %d\n", n);\r
2526 //  showline(logline, 0);\r
2527 \r
2528 //  0 to MAXCHR, and CLEAR and EOD\r
2529   for (k = 0; k < FIRSTCODE; k++) {\r
2530     node[k].chr = -1;\r
2531     node[k].nextinlist = -1;\r
2532     node[k].nextlevel = -1;\r
2533   }\r
2534   LZWput(CLEAR, output);    // using current code length\r
2535   nextnode = FIRSTCODE;   // next node available\r
2536   currentnode = n;      // string in progress\r
2537   codelength = 9;       // reset code length now\r
2538 }\r
2539 \r
2540 int SetupNodes (FILE *output)\r
2541 {\r
2542   int nlen;\r
2543 \r
2544   if (node == NULL) {\r
2545     nlen = MAXCODES * sizeof(struct NODE);  // 49,152 bytes\r
2546     if (traceflag) {\r
2547       sprintf(logline, "Allocating %d bytes\n", nlen);  // debugging only\r
2548       showline(logline, 0);\r
2549     }\r
2550     node = (struct NODE *) malloc(nlen);\r
2551     if (node == NULL) {\r
2552       sprintf(logline, "Unable to allocate %d bytes for NODE table\n", nlen);\r
2553       showline(logline, 1);\r
2554       checkexit(1);\r
2555     }\r
2556   }\r
2557 //  LZWput(CLEAR, output);      // do separately\r
2558 //  nextnode = FIRSTCODE;\r
2559 //  currentnode = -1;\r
2560   codelength = 9;         // need to initialize\r
2561 //  CleanOut(output, -1);     // do separately\r
2562   return 0;\r
2563 }\r
2564 \r
2565 #ifdef IGNORED\r
2566 // We are at node n and adding a new branch for byte chr -- NOT USED\r
2567 void AddaNode (FILE *output, int n, int chr, int previous)\r
2568 {\r
2569   int k, klast;\r
2570 //  if (nextnode < 0 || nextnode >= MAXCODES) showline("TABLE OVERFLOW", 1);\r
2571 //  Is there already a node at the next level ?\r
2572   k = node[n].nextlevel;\r
2573   if (k < 0) {    // no, start next level list\r
2574     node[n].nextlevel = nextnode; // link to new node\r
2575   }\r
2576   else {                // yes, link to end of that list\r
2577 //    k = node[n].nextlevel;\r
2578 //    find end of linked list\r
2579     while (k >= 0) {\r
2580       klast = k;\r
2581       k = node[klast].nextinlist;\r
2582     }\r
2583     node[klast].nextinlist = nextnode;  // link new node to end of list\r
2584   }\r
2585 //  set up new node being added\r
2586 //  node[nextnode].code = nextnode;\r
2587   node[nextnode].chr = chr;\r
2588   node[nextnode].nextinlist = -1;\r
2589   node[nextnode].nextlevel = -1;\r
2590   nextnode++;\r
2591   if (nextnode == 512 || nextnode == 1024 || nextnode == 2048) {\r
2592 //    sprintf(logline, "CODELENGTH %d ", codelength);\r
2593 //    showline(logline, 0);\r
2594     codelength++;\r
2595   }\r
2596   else if (nextnode == 4096) CleanOut(output, chr);\r
2597 }\r
2598 #endif\r
2599 \r
2600 // We are adding a new node for byte chr\r
2601 \r
2602 void NewNode (FILE *output, int chr, int previous) {\r
2603   if (nextnode < 0 || nextnode >= MAXCODES) showline("TABLE OVERFLOW", 1);\r
2604 //  set up new node being added\r
2605 //  node[nextnode].code = nextnode;\r
2606 //  sprintf(logline, "NEW NODE %d %d\n", chr, previous);\r
2607 //  showline(logline, 1);\r
2608 //  sprintf(logline, "NEW NODE %d for %d from %d ", nextnode, chr, previous);\r
2609 //  showline(logline, 1);   // debugging only\r
2610   node[nextnode].chr = chr;\r
2611   node[nextnode].nextinlist = -1;\r
2612   node[nextnode].nextlevel = -1;\r
2613   nextnode++;\r
2614   if (nextnode == 512 || nextnode == 1024 || nextnode == 2048) {\r
2615 //    sprintf(logline, "CODELENGTH %d ", codelength);\r
2616 //    showline(logline, 0);\r
2617     codelength++;\r
2618   }\r
2619   else if (nextnode == 4096) CleanOut(output, chr);\r
2620 }\r
2621 \r
2622 // Process next incoming byte\r
2623 \r
2624 void DoNextByte (FILE *output, int chr) { // called from  writearowLZW\r
2625   int k, klast;\r
2626 //  sprintf(logline, "(%d) ", chr);   // debugging only\r
2627 //  showline(logline, 0);\r
2628   if (currentnode < 0) {  // starting from scratch ? (empty string)\r
2629     currentnode = chr;\r
2630     return;\r
2631   }\r
2632   k = node[currentnode].nextlevel;\r
2633   if (k < 0) {  // does next level exist ?\r
2634 //    AddaNode(currentnode, n);\r
2635     LZWput(currentnode, output);    // new string NOT in table\r
2636     node[currentnode].nextlevel = nextnode; // NEXT LEVEL\r
2637 //    sprintf(logline, "NEW LEVEL %d %d %d ", currentnode, nextnode, chr);\r
2638 //    showline(logline, 0);       // debugging only\r
2639     NewNode(output, chr, currentnode);  // new node at nextnode\r
2640     currentnode = chr;          // string of one byte\r
2641     return;\r
2642   }\r
2643 //  there is a list at the next level --- search it\r
2644 //  k = node[currentnode].nextlevel;\r
2645   while (k >= 0 && node[k].chr != chr) {\r
2646     klast = k;\r
2647     k = node[klast].nextinlist;\r
2648   }\r
2649   if (k < 0) {              // hit end of list ?\r
2650 //    AddaNode(currentnode, n);\r
2651     LZWput(currentnode, output);    // new string NOT in table\r
2652     node[klast].nextinlist = nextnode;  // NEXT IN LIST\r
2653 //    sprintf(logline, "NEW ELEM %d (%d) %d %d ", currentnode, klast, nextnode, chr);\r
2654 //    showline(logline, 0);       // debugging only\r
2655     NewNode(output, chr, currentnode);  // new node at nextnode\r
2656     currentnode = chr;          // string of one byte\r
2657     return;\r
2658   }\r
2659 //  we did find this string in the table\r
2660 //  if (k < 0 || k >= MAXCODES) showline("ERROR ", 0);  // debugging only\r
2661   currentnode = k;  // it IS in table, no output\r
2662 }\r
2663 \r
2664 #ifdef IGNORED\r
2665 void DoCleanup (FILE *output)  // not used - see LZWflushfilter\r
2666 {\r
2667   if (currentnode >= 0) LZWput(currentnode, output);\r
2668 //  LZWput(CLEAR, output);\r
2669 //  nextnode = FIRSTCODE;\r
2670 //  currentnode = -1;\r
2671 //  codelength = 9;\r
2672   CleanOut(output, -1);\r
2673 }\r
2674 #endif\r
2675 \r
2676 /***************************************************************************/\r
2677 \r
2678 int perrow = 100;\r
2679 \r
2680 long leftover;    /* byte accumulated so far - need up to 12 + 12 bits */\r
2681 int bitsused;   /* bits used so far */\r
2682 \r
2683 /* stuff codelength bits of c into output stream */\r
2684 /* may produce one or two bytes ready to spit out */\r
2685 /* bitsused is always < 8 before and always < 8 after this */\r
2686 \r
2687 void LZWput (int code, FILE *output)\r
2688 {\r
2689   int c;\r
2690 \r
2691 //  if (bitsused < 0 || bitsused >= 8) showline("ERROR ", 1);\r
2692 #ifdef DEBUGLZWENCODE\r
2693   if (debugflag)\r
2694   {\r
2695     if (code >= (1 << codelength))\r
2696     sprintf(logline, "code %d too long for code length %d\n",\r
2697         code, codelength);\r
2698     showline(logline, 1);\r
2699   }\r
2700 #endif\r
2701 //  sprintf(logline, "LEFT %08X USED %d ", leftover, bitsused);\r
2702 //  showline(logline, 0);   // debugging only\r
2703   leftover = (leftover << codelength) | code;\r
2704   bitsused += codelength;\r
2705   if (bitsused >= 16) {\r
2706     c = (int) (leftover >> (bitsused - 8)); /* get left most 8 bits */\r
2707     ASCIIout(output, c & 255);      // expand ?\r
2708     bitsused -= 8;\r
2709   }\r
2710   c = (int) (leftover >> (bitsused - 8)); /* get left most 8 bits */\r
2711   ASCIIout(output, c & 255);        // expand ?\r
2712   bitsused -= 8;\r
2713 //  if (bitsused < 0 || bitsused >= 8) showline("ERROR ", 1);\r
2714 }\r
2715 \r
2716 void LZWputinit (FILE *output) {  /* called from LZWinitfilter */\r
2717 //  showline("LZWputinit ", 0); // debugging only\r
2718   leftover = 0;\r
2719   bitsused = 0;\r
2720 }\r
2721 \r
2722 void LZWputflush (FILE *output)\r
2723 {\r
2724   int c;\r
2725 //  showline("LZWputflush ", 0);  // debugging only\r
2726   if (bitsused == 0) return;    /* nothing left to push out */\r
2727   c = (int) (leftover << (8 - bitsused));\r
2728 /*  c = (int) (leftover >> (bitsused - 8)); */  /* same thing ? */\r
2729   ASCIIout(output, c & 255);      /* fill last byte with zeros */\r
2730 /*  leftover = 0; */\r
2731 /*  bitsused = 0; */\r
2732 }\r
2733 \r
2734 void LZWinitfilter (FILE *output) /*  initialization  */\r
2735 {\r
2736 //  showline("LZWinitfilter ", 0);    // debugging only\r
2737   LZWputinit(output);\r
2738 //  LZWput(CLEAR, output);  /* write CLEAR */\r
2739   SetupNodes(output);\r
2740   CleanOut(output, -1);\r
2741 /*  codelength = 9; */\r
2742 }\r
2743 \r
2744 void LZWflushfilter (FILE *output) /* termination */\r
2745 {\r
2746 //  showline("LZWflushfilter ", 0);   // debugging only\r
2747   if (currentnode >= 0) {\r
2748     LZWput(currentnode, output);\r
2749 #ifdef DEBUGLZWENCODE\r
2750     if (debugflag > 1) showcode(currentnode);\r
2751 #endif\r
2752   }\r
2753   LZWput(EOD, output);\r
2754 #ifdef DEBUGLZWENCODE\r
2755   if (debugflag) showline("EOD ", 1);\r
2756   if (debugflag) {\r
2757     sprintf(logline, "%d entries ", nextnode);\r
2758     showline(logline, 1);\r
2759   }\r
2760 #endif\r
2761   LZWputflush(output);\r
2762 /*  CleanOut(output, -1); */\r
2763 }\r
2764 \r
2765 /* Basic LZW encoding for output */ /* encode width bytes starting at *s */\r
2766 /* Initialization and Termination taken care of elsewhere */\r
2767 /* int code; */ /* code of the string matched so far to input */\r
2768 /* int last; */ /* last character of input string */\r
2769 \r
2770 int writearowLZW (FILE *output, unsigned char *s, unsigned long width)\r
2771 {\r
2772   unsigned char *send = s + width;\r
2773 \r
2774 /*  This picks up unfinished business --- currentnode >= 0 */\r
2775   while (s < send) {\r
2776     DoNextByte(output, *s++);\r
2777   }\r
2778   return 0;\r
2779 /*  This may leave unfinished business --- currentnode >= 0 */\r
2780 }\r
2781 \r
2782 #endif /* end of ifdef LZWCOMPRESSION */\r
2783 \r
2784 /*************************************************************************/\r
2785 \r
2786 //#pragma optimize ("lge", off)\r
2787 \r
2788 #endif /* end of ifdef PSLEVEL2 */\r
2789 \r
2790 /* write row in hex format */\r
2791 \r
2792 void writearowhex (FILE *output, unsigned char *s, unsigned long width)\r
2793 {\r
2794   unsigned int c, d;\r
2795   int k, n;\r
2796 \r
2797   n = (int) width;\r
2798   column = 0;\r
2799   for (k = 0; k < n; k++) {\r
2800     if (column >= MAXCOLUMNHEX) {\r
2801 //      putc('\n', output);\r
2802       PSputc('\n', output);\r
2803       column = 0;\r
2804     }\r
2805     c = *s++;\r
2806     d = c & 15;\r
2807     c = c >> 4;\r
2808     if (c > 9) {\r
2809 //      putc(c + 'A' - 10, output);\r
2810       PSputc((char) (c + 'A' - 10), output);\r
2811     }\r
2812     else {\r
2813 //      putc(c + '0', output);\r
2814       PSputc((char) (c + '0'), output);\r
2815     }\r
2816     column++;\r
2817     if (d > 9) {\r
2818 //      putc(d + 'A' - 10, output);\r
2819       PSputc((char) (d + 'A' - 10), output);\r
2820     }\r
2821     else {\r
2822 //      putc(d + '0', output);\r
2823       PSputc((char) (d + '0'), output);\r
2824     }\r
2825     column++;\r
2826   }\r
2827 //  putc('\n', output);   /* also start each image row on new line */\r
2828   PSputc('\n', output);   /* also start each image row on new line */\r
2829   column = 0;\r
2830 }\r
2831 \r
2832 /* returns -1 if output error */  /* write a row of data in hex */\r
2833 \r
2834 int writearow (FILE *output, unsigned char *s, unsigned long width)\r
2835 {\r
2836 #ifdef PSLEVEL2\r
2837   if (bLevel2) {\r
2838     if (bRunLengthFlag) writearowrun(output, s, width);\r
2839 #ifdef LZWCOMPRESSION\r
2840     else if (bLZWFlag) writearowLZW(output, s, width);\r
2841 #endif\r
2842     else writearowASCII(output, s, width);\r
2843   }\r
2844   else writearowhex(output, s, width);\r
2845 #else\r
2846   writearowhex(output, s, width);\r
2847 #endif\r
2848 \r
2849 //  if (ferror(output)) \r
2850   if (output != NULL && ferror(output))\r
2851   {\r
2852     showline(" ERROR: Output error\n", 1);\r
2853     perrormod((outputfile != NULL) ? outputfile : "");\r
2854     return -1;\r
2855   }\r
2856   if (bAbort) abortjob();   /* 97/Mar/1 ? */\r
2857   if (abortflag) return -1;\r
2858   return 0;\r
2859 }\r
2860 \r
2861 int computeheader (void) {\r
2862 /*  int changeflag= 0; */\r
2863 \r
2864 #ifdef DEBUGTIFF\r
2865   if (traceflag) showline("Now computing header information\n", 0);\r
2866 #endif\r
2867 \r
2868 /*  Now for some sanity checks */\r
2869   if (PlanarConfig != 1) {\r
2870     showline(" ERROR: Multiple color planes not supported\n", 1);\r
2871     return -1; \r
2872   }\r
2873   if (BitsPerSample > 8) {\r
2874     sprintf(logline, " ERROR: Maximum of 8 bits per sample (%d)\n",\r
2875       BitsPerSample);\r
2876     showline(logline, 1);\r
2877     return -1;\r
2878   }\r
2879   if ((BitsPerSample & (BitsPerSample-1)) != 0) {\r
2880     sprintf(logline, " ERROR: Bits per sample must be power of two (%d)\n",\r
2881       BitsPerSample);\r
2882     showline(logline, 1);\r
2883     return -1;\r
2884   }\r
2885   if (compression > TIFF_CCITT && compression != LZW_COMPRESSION &&\r
2886     compression != PACK_BITS ) {\r
2887     sprintf(logline,  " ERROR: Unknown compression scheme (%d)", compression);\r
2888     showline(logline, 1);\r
2889     return -1;\r
2890   }\r
2891 \r
2892   if (PhotometricInterpretation == 3) { /* that is palette color */\r
2893 /*    if (SamplesPerPixel != 1) */\r
2894     if (SamplesPerPixelX != 1) {\r
2895       showline(" ERROR: Palette color must have one sample per pixel", 1);\r
2896       return -1;\r
2897     }\r
2898   }\r
2899 /*  check whether need to use `colorimage' operator instead of `image' */\r
2900 /*  if (SamplesPerPixel != 1) */\r
2901   if (SamplesPerPixelX != 1) {\r
2902 //    if (PhotometricInterpretation != 2)\r
2903     if (PhotometricInterpretation != 2 && PhotometricInterpretation != 5)\r
2904 //      showline(" More than one sample per pixel, but not RGB?", 1);\r
2905       showline(" More than one sample per pixel, but not RGB or CMYK?", 1);\r
2906     bColorImage = 1;\r
2907     if (! bAllowColor) {\r
2908       sprintf(logline, " WARNING: More than one sample per pixel (%d) use `*c' flag?",\r
2909         SamplesPerPixel);\r
2910       showline(logline, 0);\r
2911 /*      return -1; */\r
2912       bCompressColor = 1;     /* then need to compress colors */\r
2913     }\r
2914   }\r
2915 /*  if (verboseflag && PhotometricInterpretation > 3) {\r
2916     printf("Photometricinterpretation %d\n", PhotometricInterpretation);\r
2917   }  */\r
2918 /*  0 => 0 will be white and 2^n-1 black */\r
2919 /*  1 => 0 will be black and 2^n-1 white (default) */\r
2920 /*  2 => RGB model */\r
2921 /*  3 => palette color */\r
2922 /*  4 => transparency mask */\r
2923 /*  Fix this one later */\r
2924 /*  if (PhotometricInterpretation == 3) bColorImage = 1;  */\r
2925 /*  if (ColorMapPtr != 0)   bColorImage = 1; */\r
2926   if (PhotometricInterpretation == 3 && ColorMapPtr == 0) {\r
2927     showline(" ERROR: Palette Color Image must have Palette!\n", 1);\r
2928     return -1;\r
2929   }\r
2930   if (PhotometricInterpretation == 2)\r
2931   {\r
2932 /*    if (SamplesPerPixel == 1)  */\r
2933     if (SamplesPerPixelX == 1)\r
2934     {\r
2935       sprintf(logline, " %s, but not more than one sample per pixel?\n", "RGB");\r
2936       showline(logline, 1);\r
2937     }\r
2938     if (! bAllowColor)\r
2939     {\r
2940       sprintf(logline, " WARNING: %s color image (%d) use `*c' flag?", "RGB", SamplesPerPixel);\r
2941 //      showline(logline, 1);\r
2942       showline(logline, 0);\r
2943       bCompressColor = 1;\r
2944     }\r
2945     bColorImage = 1;\r
2946   }\r
2947   if (PhotometricInterpretation == 5) { // 2000 May 27\r
2948 /*    if (SamplesPerPixel == 1)  */\r
2949     if (SamplesPerPixelX == 1)\r
2950     {\r
2951       sprintf(logline, " %s, but not more than one sample per pixel?\n", "CMYK");\r
2952       showline(logline, 1);\r
2953     }\r
2954     if (! bAllowColor)\r
2955     {\r
2956       sprintf(logline, " WARNING: %s color image (%d) use `*c' flag?", "CMYK", SamplesPerPixel);\r
2957 //      showline(logline, 1);\r
2958       showline(logline, 0);\r
2959       bCompressColor = 1;\r
2960     }\r
2961     bColorImage = 1;\r
2962   }\r
2963 /*  0 => 0 will be white and 2^n-1 black */\r
2964 /*  1 => 0 will be black and 2^n-1 white (default) */\r
2965 \r
2966   if (PhotometricInterpretation == 0)\r
2967   {\r
2968 #ifdef DEBUGTIFF\r
2969     if (traceflag) showline("Image grey levels will be inverted\n", 0); \r
2970 #endif\r
2971     bInvertImage = 1;\r
2972   }\r
2973   else bInvertImage = 0;\r
2974 \r
2975 #ifdef DEBUGTIFF\r
2976   if (traceflag)\r
2977   {\r
2978     sprintf(logline, "ExpandColor %d CompressColor %d InvertImage %d\n",\r
2979       bExpandColor, bCompressColor, bInvertImage);\r
2980     showline(logline, 0);\r
2981   }\r
2982 #endif\r
2983 \r
2984 /*  compute bytes per row (both input and output?) */\r
2985 /*  if (bColorImage)bytes = (int) (((long) ImageWidth * BitsPerPixel + 7) / 8);\r
2986   else bytes = (int) (((long) ImageWidth * BitsPerSample + 7) / 8); */\r
2987 /*  Following only correct if no expansion or contraction of color images */\r
2988 /*  bytes = (int) (((long) ImageWidth * BitsPerPixel + 7) / 8); */\r
2989   bytes = (int) OutRowLength;     /* ever used ? */\r
2990 #ifdef DEBUGTIFF\r
2991   if (traceflag) {\r
2992     sprintf(logline, "%d bytes per row\n", bytes);\r
2993     showline(logline, 0);\r
2994   }\r
2995 #endif\r
2996   return 0;\r
2997 }\r
2998 \r
2999 /* long xll=0, yll=0, xur=0, yur=0;  */\r
3000 \r
3001 /*  {1 exch sub} settransfer */\r
3002 /*  currenttranser {1 exch sub 0 exec} exch 4 put bind */\r
3003 /*  char *invertgray=\r
3004   "[{1 exch sub} /exec load currentransfer /exec load] cvx settransfer\n"; */\r
3005 \r
3006 /* compress some of this code into DVIPREAM.PS ? */\r
3007 \r
3008 void writepsheader (FILE *output, long dwidth, long dheight)\r
3009 {\r
3010   int bits=1;         /* bits per pixel in image */\r
3011   int samples=3;        /* samples per pixel 96/July/7 */\r
3012   int bMonoChrome=0;      /* if need to use image mask */\r
3013 /*  int paintback=0; */     /* if need to paint background */\r
3014 /*  long XOffset, YOffset; */\r
3015   long YOffset;\r
3016 \r
3017 #ifdef DEBUGTIFF\r
3018   if (traceflag) showline("Now writing out header information\n", 0);\r
3019 #endif\r
3020 /*  if (BitsPerSample == 1) bMonoChrome = 1; */ /* use image mask */\r
3021 \r
3022   if (bExpandColor) bits = 8;\r
3023   else if (bExpandGray) bits = 8;\r
3024   else bits = BitsPerSample;\r
3025 \r
3026   if (bits == 1) bMonoChrome = 1;       /* use image mask */\r
3027 \r
3028   if (bExpandColor) samples = 3;\r
3029   else if (bExpandGray) samples = 1;\r
3030 /*  else samples = SamplesPerPixel; */      /* 96/July/7 */\r
3031   else samples = SamplesPerPixelX;\r
3032 \r
3033 //  fprintf(output, "\nsave\n");\r
3034 //  putc('\n', output);\r
3035   PSputc('\n', output);\r
3036 //  fputs("save ", output);\r
3037   PSputs("save ", output);\r
3038   if (stripcomment == 0) {\r
3039     sprintf(logline, "%% %s\n", infilename);  /* 98/Jul/12 */\r
3040     PSputs(logline, output);\r
3041   }\r
3042   else {\r
3043 //    putc('\n', output);\r
3044     PSputc('\n', output);\r
3045   }\r
3046   if (! bColorImage) {    /* only use screen for B/W */\r
3047 /*    if (bInvertImage) fputs("invert\n", output); */\r
3048     if (bInvertImage && !bMonoChrome) {\r
3049 //      fputs("invert\n", output);\r
3050       PSputs("invert\n", output);\r
3051     }\r
3052 /*    if (wantmagic)  fputs(eps_magic, output); */\r
3053 /*    fprintf(output, "currentscreen pop dviscreen\n"); */\r
3054     if (wantmagictiff) {\r
3055       if (frequency > 0) {  /* did user specified frequency & angle ? */\r
3056         sprintf(logline, "%d %d dviscreen\n", frequency, angle);\r
3057         PSputs(logline, output);\r
3058       }\r
3059       else {\r
3060 //        fputs("currentscreen pop dviscreen\n", output);\r
3061         PSputs("currentscreen pop dviscreen\n", output);\r
3062       }\r
3063     }\r
3064   }\r
3065 /*  for monochrome, paint background first, then use imagemask */\r
3066 /*  if (BitsPerSample == 1) {\r
3067     if (bFigureColor) \r
3068       fprintf(output, "%lg %lg %lg rgb\n",\r
3069         figurered, figuregreen, figureblue); \r
3070     else if (bTextColor) fputs("black\n", output);\r
3071     paintback = 1;\r
3072   } */\r
3073 /*  create the string before or after the `save' ? */\r
3074 /*  fprintf(output, "/picstr %d string def\n", bytes);  */\r
3075 /*  string not needed if using ASCII85Decode filter 96/Dec/20 */\r
3076   if (! bLevel2) {\r
3077     sprintf(logline, "/picstr %d string def\n", bytes);\r
3078     PSputs(logline, output);\r
3079   }\r
3080 //  fprintf(output, "%d %d translate ", xll, yll);\r
3081 //  fputs("currentpoint translate ", output);\r
3082   PSputs("currentpoint translate ", output);\r
3083   if (dwidth == 0 || dheight == 0) {\r
3084     showline(" Zero width or height ", 1);\r
3085   }\r
3086 #ifdef ALLOWSCALE\r
3087   if (outscaleflag) {\r
3088     sprintf(logline, "%.9lg %.9lg scale\n",\r
3089       (double) dwidth / outscale, (double)  dheight / outscale);\r
3090   }\r
3091   else {\r
3092     sprintf(logline, "%ld %ld scale\n", dwidth, dheight);\r
3093   }\r
3094 #else\r
3095   sprintf(logline, "%ld %ld scale\n", dwidth, dheight);\r
3096 #endif\r
3097   PSputs(logline, output);\r
3098 \r
3099 /*  if (bFigureColor && paintback) { */   /* need to paint background */\r
3100 /*  proper support for \special{figurecolor: . . . . . .} 94/Mar/14 */\r
3101   if (BitsPerSample == 1) {       /* need to paint background ? */\r
3102 /*    fputs("gsave\n", output); */    /* not needed */\r
3103 /*    paint background here in background color */\r
3104 /*    if (backred != 1.0 || backgreen != 1.0 || backblue != 1.0)  */\r
3105     if (bFigureColor) {\r
3106       sprintf(logline, "%lg %lg %lg rgb\n",\r
3107         backred, backgreen, backblue);    /* color for background */\r
3108       PSputs(logline, output);\r
3109     }\r
3110     else {\r
3111 //      fputs("white\n", output);\r
3112       PSputs("white\n", output);\r
3113     }\r
3114 /*  now paint background in this color *//* use `box' in preamble ? */\r
3115     if (bSuppressBack == 0) {\r
3116 //      fputs("0 0 moveto 1 0 lineto ", output);\r
3117       PSputs("0 0 moveto 1 0 lineto ", output);\r
3118 /*      fputs("0 0 moveto 1 0 lineto 1 -1 lineto 0 -1 lineto closepath fill\n", output); */\r
3119 /*      background seems to be painted above not on image 95/Dec/31 */\r
3120 /*      fputs("0 0 moveto 1 0 lineto 1 1 lineto 0 1 lineto closepath fill\n", output); */\r
3121       if (hptagflag != 0) {\r
3122 //        fputs("1 1 lineto 0 1 lineto ", output);\r
3123         PSputs("1 1 lineto 0 1 lineto ", output);\r
3124       }\r
3125 /*      background seems to be painted below not on image 96/May/6 */\r
3126       else {\r
3127 //        fputs("1 -1 lineto 0 -1 lineto ", output);\r
3128         PSputs("1 -1 lineto 0 -1 lineto ", output);\r
3129       }\r
3130 //      fputs("closepath fill\n", output);\r
3131       PSputs("closepath fill\n", output);\r
3132     }\r
3133     if (bFigureColor) {\r
3134       sprintf(logline, "%lg %lg %lg rgb\n",\r
3135         figurered, figuregreen, figureblue); /* color for foreground */\r
3136       PSputs(logline, output);\r
3137     }\r
3138     else {\r
3139 //      fputs("black\n", output);\r
3140       PSputs("black\n", output);\r
3141     }\r
3142 /*    fputs("grestore\n", output); */   /* not needed */\r
3143   }\r
3144 //  fprintf(output, "%ld %ld %d\n", ImageWidth, ImageLength, bits);\r
3145   sprintf(logline, "%ld %ld ", ImageWidth, ImageLength);\r
3146   PSputs(logline, output);\r
3147   if (bMonoChrome) {\r
3148     if (bInvertImage) {\r
3149 //      fputs("true\n", output);\r
3150       PSputs("true\n", output);\r
3151     }\r
3152     else {\r
3153 //      fputs("false\n", output);\r
3154       PSputs("false\n", output);\r
3155     }\r
3156   }\r
3157   else {\r
3158     sprintf(logline, "%d\n", bits);       /* not monochrome */\r
3159     PSputs(logline, output);\r
3160   }\r
3161   if (BMPflag) {              /* new mode 98/Jul/9 */\r
3162     sprintf(logline, "[%ld 0 0 %ld 0 %ld]\n",\r
3163                 ImageWidth, -ImageLength, 0);\r
3164     PSputs(logline, output);\r
3165   }\r
3166   else {\r
3167     if (hptagflag != 0) YOffset = 0;\r
3168     else YOffset = ImageLength;\r
3169     sprintf(logline, "[%ld 0 0 %ld 0 %ld]\n",\r
3170         ImageWidth, ImageLength, YOffset);\r
3171     PSputs(logline, output);\r
3172   }\r
3173 /*  fputs("{currentfile picstr readhexstring pop} bind\n", output); */\r
3174   if (bLevel2) {\r
3175 //    fputs("currentfile", output);\r
3176     PSputs("currentfile", output);\r
3177 //    fputs(" /ASCII85Decode filter", output);\r
3178     PSputs(" /ASCII85Decode filter", output);\r
3179     if (bRunLengthFlag) {\r
3180 //      fputs(" /RunLengthDecode filter", output);\r
3181       PSputs(" /RunLengthDecode filter", output);\r
3182     }\r
3183 #ifdef LZWCOMPRESSION\r
3184     else if (bLZWFlag) {\r
3185 //      fputs(" /LZWDecode filter", output);\r
3186       PSputs(" /LZWDecode filter", output);\r
3187     }\r
3188 #endif\r
3189 //    putc('\n', output);\r
3190     PSputc('\n', output);\r
3191   }\r
3192   else {\r
3193 //    fputs("{currentfile picstr readhexstring pop} bind\n", output);\r
3194     PSputs("{currentfile picstr readhexstring pop} bind\n", output);\r
3195   }\r
3196 /*  samples per pixel better be 1 (grey), 3 (RGB) or 4 (CMYK) */\r
3197   if (bColorImage && bAllowColor) {\r
3198 //    fprintf(output, "false %d colorimage\n", SamplesPerPixel); \r
3199     sprintf(logline, "false %d colorimage", samples); /* 96/July/7 */\r
3200     PSputs(logline, output);\r
3201   }\r
3202 /*  else if (bCompressColor) fputs("image\n", output); */\r
3203   else if (bMonoChrome) {\r
3204 //    fputs("imagemask", output); /* monochrome */\r
3205     PSputs("imagemask", output);  /* monochrome */\r
3206   }\r
3207   else {\r
3208 //    fputs("image", output); /* either not color, or color compressed */\r
3209     PSputs("image", output);  /* either not color, or color compressed */\r
3210   }\r
3211 //  putc('\n', output);\r
3212   PSputc('\n', output);\r
3213 /*  image data must follow right away */\r
3214 }\r
3215 \r
3216 void writepstrailer (FILE *output)\r
3217 {\r
3218 #ifdef DEBUGTIFF\r
3219   if (traceflag) showline("Now writing trailer\n", 0);\r
3220 #endif\r
3221 /*  if (BitsPerSample == 1) {\r
3222     if (bTextColor) fprintf(output, "%lg %lg %lg rgb\n",\r
3223           Textred, Textgreen, Textblue);\r
3224     else if(bFigureColor) fputs("black\n");\r
3225   } */              /* monochrome - not needed */\r
3226 //  fputs("restore\n", output);\r
3227   PSputs("restore\n", output);\r
3228 }\r
3229 \r
3230 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
3231 \r
3232 /* Read a row using PACK_BITS compression scheme */\r
3233 /* returns non-zero if problems encountered */\r
3234 \r
3235 int readpackbits (unsigned char *lpBuffer, FILE *input, int RowLength)\r
3236 {\r
3237   unsigned char *u=lpBuffer;\r
3238   int c, k, n, total=0, flag=0;\r
3239   \r
3240   for(;;) {\r
3241     if ((n = getc(input)) < 0) {  /* premature EOF */\r
3242       showline(" Premature EOF", 1);\r
3243       flag = -1;\r
3244       break;  \r
3245     }\r
3246     else if (n < 128) {     /* use next (n+1) bytes as is */\r
3247       for (k=0; k < n+1; k++) *u++ = (char) getc(input);  \r
3248       total += n+1;\r
3249     }\r
3250     else if (n > 128) {     /* repeat next byte (257 - n) times */\r
3251       c = getc(input);\r
3252       for (k=0; k < (257 - n); k++) *u++ = (char) c;   \r
3253       total += (257 - n);\r
3254     }\r
3255 /*    and n == 128 is a NOP */\r
3256     if (total == RowLength) break;  /* enough bytes yet ? */\r
3257     if (total > RowLength) {    /* too many bytes ? */\r
3258       showline(" Too many bytes in compressed row\n", 1);\r
3259       flag = -1;\r
3260       break;\r
3261     }\r
3262   }\r
3263   return flag;\r
3264 }\r
3265 \r
3266 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
3267 \r
3268 /* Implement 1d CCITT Huffman code decompression (minus EOL) */\r
3269 /* ==> implies BitsPerSample == 1 */\r
3270 /* white runs = 0, black runs = 1 */\r
3271 /* normal PhotometricInterpretation == 0 */\r
3272 /* invert black/white if PhotometricInterpretation == 1 */\r
3273 \r
3274 int bytex, bitsleft;        /* input buffering in splitting bits */\r
3275 \r
3276 int getbit (FILE *input)\r
3277 {\r
3278   if (bitsleft-- <= 0) {\r
3279     if ((bytex = getc(input)) == EOF) {\r
3280       sprintf(logline, " Unexpected EOF (%s)\n", "getbit TIFF");\r
3281       showline(logline, 0);\r
3282 /*      checkexit(1); */      /* Wait for it to create bad code */\r
3283     }\r
3284     bitsleft = 7;\r
3285   }\r
3286   bytex = bytex << 1;\r
3287 #ifdef DEBUGTIFF\r
3288   if (traceflag) {\r
3289     sprintf(logline, "%d", (bytex & 256) ? 1 : 0);\r
3290     showline(logline, 0);\r
3291   }\r
3292 #endif\r
3293   if (bytex & 256) return 1;\r
3294   else return 0;\r
3295 }\r
3296 \r
3297 //#pragma optimize ("lge", on)\r
3298 \r
3299 /* It's the Huffman code stuff that wants to be not optimized */\r
3300 \r
3301 //#pragma optimize ("lge", off)\r
3302 \r
3303 /* Actually commonmake may be OK with compiler optimizations ON */\r
3304 \r
3305 int commonmake (FILE *input) /* common black/white make up codes (7 zeros) */\r
3306 {\r
3307 #ifdef DEBUGTIFF\r
3308   if (traceflag) {\r
3309     showline("commonmake entry ", 0);\r
3310   }\r
3311 #endif\r
3312   if (getbit(input)) {  /* 00000001 */\r
3313     if (getbit(input)) {  /* 000000011 */\r
3314       if (getbit(input)) {  /* 0000000111 */\r
3315         if (getbit(input)) {  /* 00000001111 */\r
3316           if (getbit(input)) {  /* 000000011111 */\r
3317             return 2560;\r
3318           }\r
3319           else { /* 000000011110 */\r
3320             return 2496;\r
3321           }\r
3322         }\r
3323         else { /* 00000001110 */\r
3324           if (getbit(input)) {  /* 000000011101 */\r
3325             return 2432;\r
3326           }\r
3327           else { /* 000000011100 */\r
3328             return 2368;\r
3329           }\r
3330         }\r
3331       }\r
3332       else { /* 0000000110 */\r
3333         if (getbit(input)) {  /* 00000001101 */\r
3334           return 1920;\r
3335         }\r
3336         else { /* 00000001100 */\r
3337           return 1856;\r
3338         }\r
3339       }\r
3340     }\r
3341     else { /* 000000010 */\r
3342       if (getbit(input)) {  /* 0000000101 */\r
3343         if (getbit(input)) {  /* 00000001011 */\r
3344           if (getbit(input)) {  /* 000000010111 */\r
3345             return 2304;\r
3346           }\r
3347           else { /* 000000010110 */\r
3348             return 2240;\r
3349           }\r
3350         }\r
3351         else { /* 00000001010 */\r
3352           if (getbit(input)) {  /* 000000010101 */\r
3353             return 2176;\r
3354           }\r
3355           else { /* 000000010100 */\r
3356             return 2112;\r
3357           }\r
3358         }\r
3359       }\r
3360       else { /* 0000000100 */\r
3361         if (getbit(input)) {  /* 00000001001 */\r
3362           if (getbit(input)) {  /* 000000010011 */\r
3363             return 2048;\r
3364           }\r
3365           else { /* 000000010010 */\r
3366             return 1984;\r
3367           }\r
3368         }\r
3369         else { /* 00000001000 */\r
3370           return 1792;\r
3371         }\r
3372       }\r
3373     }\r
3374   }\r
3375   else { /* 00000000 */\r
3376 /*  Actually, EOL code is not supposed to be used in TIFF compression 2 */\r
3377     if (!getbit(input)) { /* 000000000 */\r
3378       if (!getbit(input)) { /* 0000000000 */\r
3379         if (!getbit(input)) { /* 00000000000 */\r
3380           if (getbit(input)) { /* 000000000001 */\r
3381             showline("EOL ", 1);\r
3382             return 0;       /* ??? */\r
3383           }\r
3384         }\r
3385       }\r
3386     }\r
3387   }\r
3388   showline(" Impossible make-up run\n", 1);\r
3389   return -1;  /* error */\r
3390 }\r
3391 \r
3392 /* Compiler screws up the following code if optimizations turned on */\r
3393 \r
3394 int whiterun (FILE *input)\r
3395 {\r
3396 #ifdef DEBUGTIFF\r
3397   if (traceflag)\r
3398   {\r
3399     showline("whiterun entry ", 0);\r
3400   }\r
3401 #endif\r
3402   if (getbit(input)) {  /* 1 */\r
3403     if (getbit(input)) {  /* 11 */\r
3404       if (getbit(input)) {  /* 111 */\r
3405         if (getbit(input)) {  /* 1111 */\r
3406           return 7;\r
3407         }\r
3408         else {      /* 1110 */\r
3409           return 6;\r
3410         }\r
3411       }\r
3412       else {      /* 110 */\r
3413         if (getbit(input)) {  /* 1101 */\r
3414           if (getbit(input)) { /* 11011 */\r
3415             return 64;    /* make up */\r
3416           }\r
3417           else {      /* 11010 */\r
3418             if (getbit(input)) { /* 110101 */\r
3419               return 15;\r
3420             }\r
3421             else {      /* 110100 */\r
3422               return 14;\r
3423             }\r
3424           }\r
3425         }\r
3426         else {      /* 1100 */\r
3427           return 5;\r
3428         }\r
3429       }\r
3430     }\r
3431     else {      /* 10 */\r
3432       if (getbit(input)) {  /* 101 */\r
3433         if (getbit(input)) {  /* 1011 */\r
3434           return 4;\r
3435         }\r
3436         else {      /* 1010 */\r
3437           if (getbit(input)) { /* 10101 */\r
3438             if (getbit(input)) { /* 101011 */\r
3439               return 17;\r
3440             }\r
3441             else {      /* 101010 */\r
3442               return 16;\r
3443             }\r
3444           }\r
3445           else {      /* 10100 */\r
3446             return 9;\r
3447           }\r
3448         }\r
3449       }\r
3450       else {      /* 100 */\r
3451         if (getbit(input)) {  /* 1001 */\r
3452           if (getbit(input)) { /* 10011 */\r
3453             return 8;\r
3454           }\r
3455           else {      /* 10010 */\r
3456             return 128; /* make up */\r
3457           }\r
3458         }\r
3459         else {      /* 1000 */\r
3460           return 3;\r
3461         }\r
3462       }\r
3463     }\r
3464   }\r
3465   else {      /* 0 */\r
3466     if (getbit(input)) {  /* 01 */\r
3467       if (getbit(input)) {  /* 011 */\r
3468         if (getbit(input)) {  /* 0111 */\r
3469           return 2;\r
3470         }\r
3471         else {      /* 0110 */\r
3472           if (getbit(input)) { /* 01101 */\r
3473             if (getbit(input)) { /* 011011 */\r
3474               if (getbit(input)) { /* 0110111 */\r
3475                 return 256; /* make up */\r
3476               }\r
3477               else {      /* 0110110 */\r
3478                 if (getbit(input)) {  /* 01101101 */\r
3479                   if (getbit(input)) {  /* 011011011 */\r
3480                     return 1408;  /* make up */\r
3481                   }\r
3482                   else { /*  011011010 */\r
3483                     return 1344;  /* make up */\r
3484                   }\r
3485                 }\r
3486                 else {      /* 01101100 */\r
3487                   if (getbit(input)) {  /* 011011001 */\r
3488                     return 1280;  /* make up */\r
3489                   }\r
3490                   else { /* 011011000 */\r
3491                     return 1216;  /* make up */\r
3492                   }\r
3493                 }\r
3494               }\r
3495             }\r
3496             else { /* 011010 */\r
3497               if (getbit(input)) { /* 0110101 */\r
3498                 if (getbit(input)) { /* 01101011 */\r
3499                   if (getbit(input)) { /* 011010111 */\r
3500                     return 1152;  /* make up */\r
3501                   }\r
3502                   else {      /* 011010110 */\r
3503                     return 1088;  /* make up */\r
3504                   }\r
3505                 }\r
3506                 else { /* 01101010 */\r
3507                   if (getbit(input)) { /* 011010101 */\r
3508                     return 1024;  /* make up */\r
3509                   }\r
3510                   else { /* 011010100 */\r
3511                     return 960; /* make up */\r
3512                   }\r
3513                 }\r
3514               }\r
3515               else { /* 0110100 */\r
3516                 if (getbit(input)) { /* 01101001 */\r
3517                   if (getbit(input)) { /* 011010011 */\r
3518                     return 896; /* make up */\r
3519                   }\r
3520                   else { /* 011010010 */\r
3521                     return 832; /* make up */\r
3522                   }\r
3523                 }\r
3524                 else { /* 01101000 */\r
3525                   return 576; /* make up */\r
3526                 }\r
3527               }\r
3528             }\r
3529           }\r
3530           else { /* 01100 */\r
3531             if (getbit(input)) { /* 011001 */\r
3532               if (getbit(input)) { /* 0110011 */\r
3533                 if (getbit(input)) { /* 01100111 */\r
3534                   return 640; /* make up */\r
3535                 }\r
3536                 else { /* 01100110 */\r
3537                   if (getbit(input)) { /* 011001101 */\r
3538                     return 768; /* make up */\r
3539                   }\r
3540                   else { /* 011001100 */\r
3541                     return 704; /* make up */\r
3542                   }\r
3543                 }\r
3544               }\r
3545               else { /* 0110010 */\r
3546                 if (getbit(input)) { /* 01100101 */\r
3547                   return 512; /* make up */\r
3548                 }\r
3549                 else { /* 01100100 */\r
3550                   return 448; /* make up */\r
3551                 }\r
3552               }\r
3553             }\r
3554             else { /* 011000 */\r
3555               return 1664;  /* make up */\r
3556             }\r
3557           }\r
3558         }\r
3559       }\r
3560       else {      /* 010 */\r
3561         if (getbit(input)) {  /* 0101 */\r
3562           if (getbit(input)) { /* 01011 */\r
3563             if (getbit(input)) { /* 010111 */\r
3564               return 192;   /* make up */\r
3565             }\r
3566             else { /* 010110 */\r
3567               if (getbit(input)) { /* 0101101 */\r
3568                 if (getbit(input)) { /* 01011011 */\r
3569                   return 58;\r
3570                 }\r
3571                 else { /* 01011010 */\r
3572                   return 57;\r
3573                 }\r
3574               }\r
3575               else { /* 0101100 */\r
3576                 if (getbit(input)) { /* 01011001 */\r
3577                   return 56;\r
3578                 }\r
3579                 else { /* 01011000 */\r
3580                   return 55;\r
3581                 }\r
3582               }\r
3583             }\r
3584           }\r
3585           else {      /* 01010 */\r
3586             if (getbit(input)) { /* 010101 */\r
3587               if (getbit(input)) { /* 0101011 */\r
3588                 return 25;\r
3589               }\r
3590               else {      /* 0101010 */\r
3591                 if (getbit(input)) { /* 01010101 */\r
3592                   return 52;\r
3593                 }\r
3594                 else { /* 01010100 */\r
3595                   return 51;\r
3596                 }\r
3597               }\r
3598             }\r
3599             else {      /* 010100 */\r
3600               if (getbit(input)) { /* 0101001 */\r
3601                 if (getbit(input)) { /* 01010011 */\r
3602                   return 50;\r
3603                 }\r
3604                 else { /* 01010010 */\r
3605                   return 49;\r
3606                 }\r
3607               }\r
3608               else {      /* 0101000 */\r
3609                 return 24;\r
3610               }\r
3611             }\r
3612           }\r
3613         }\r
3614         else {      /* 0100 */\r
3615           if (getbit(input)) {  /* 01001 */\r
3616             if (getbit(input)) { /* 010011 */\r
3617               if (getbit(input)) { /* 0100111 */\r
3618                 return 18;\r
3619               }\r
3620               else {      /* 0100110 */\r
3621                 if (getbit(input)) {  /* 01001101 */\r
3622                   if (getbit(input)) {  /* 010011011 */\r
3623                     return 1728;  /* make up */\r
3624                   }\r
3625                   else { /* 010011010 */\r
3626                     return 1600;  /* make up */\r
3627                   }\r
3628                 }\r
3629                 else { /* 01001100 */\r
3630                   if (getbit(input)) {  /* 010011001 */\r
3631                     return 1536;  /* make up */\r
3632                   }\r
3633                   else { /* 010011000 */\r
3634                     return 1472;  /* make up */\r
3635                   }\r
3636                 }\r
3637               }\r
3638             }\r
3639             else {      /* 010010 */\r
3640               if (getbit(input)) { /* 0100101 */\r
3641                 if (getbit(input)) { /* 01001011 */\r
3642                   return 60;\r
3643                 }\r
3644                 else { /* 01001010 */\r
3645                   return 59;\r
3646                 }\r
3647               }\r
3648               else {      /* 0100100 */\r
3649                 return 27;\r
3650               }\r
3651             }\r
3652           }\r
3653           else {      /* 01000 */\r
3654             return 11;\r
3655           }\r
3656         }\r
3657       }\r
3658     }\r
3659     else {      /* 00 */\r
3660       if (getbit(input)) {  /* 001 */\r
3661         if (getbit(input)) {  /* 0011 */\r
3662           if (getbit(input)) {  /* 00111 */\r
3663             return 10;\r
3664           }\r
3665           else {      /* 00110 */\r
3666             if (getbit(input)) { /* 001101 */\r
3667               if (getbit(input)) { /* 0011011 */\r
3668                 if (getbit(input)) {  /* 0110111 */\r
3669                   return 384; /* make up */\r
3670                 }\r
3671                 else { /* 0110110 */\r
3672                   return 320; /* make up */\r
3673                 }\r
3674               }\r
3675               else { /* 0011010 */\r
3676                 if (getbit(input)) { /* 00110101 */\r
3677                   return 0;\r
3678                 }\r
3679                 else { /* 00110100 */\r
3680                   return 63;\r
3681                 }\r
3682               }\r
3683             }\r
3684             else {      /* 001100 */\r
3685               if (getbit(input)) { /* 0011001 */\r
3686                 if (getbit(input)) { /* 00110011 */\r
3687                   return 62;\r
3688                 }\r
3689                 else { /* 00110010 */\r
3690                   return 61;\r
3691                 }\r
3692               }\r
3693               else {      /* 0011000 */\r
3694                 return 28;\r
3695               }\r
3696             }\r
3697           }\r
3698         }\r
3699         else {      /* 0010 */\r
3700           if (getbit(input)) { /* 00101 */\r
3701             if (getbit(input)) { /* 001011 */\r
3702               if (getbit(input)) { /* 0010111 */\r
3703                 return 21;\r
3704               }\r
3705               else {      /* 0010110 */\r
3706                 if (getbit(input)) { /* 00101101 */\r
3707                   return 44;\r
3708                 }\r
3709                 else { /* 00101100 */\r
3710                   return 43;\r
3711                 }\r
3712               }\r
3713             }\r
3714             else {      /* 001010 */\r
3715               if (getbit(input)) { /* 0010101 */\r
3716                 if (getbit(input)) { /* 00101011 */\r
3717                   return 42;\r
3718                 }\r
3719                 else { /* 00101010 */\r
3720                   return 41;\r
3721                 }\r
3722               }\r
3723               else { /* 0010100 */\r
3724                 if (getbit(input)) { /* 00101001 */\r
3725                   return 40;\r
3726                 }\r
3727                 else { /* 00101000 */\r
3728                   return 39;\r
3729                 }\r
3730               }\r
3731             }\r
3732           }\r
3733           else {      /* 00100 */\r
3734             if (getbit(input)) { /* 001001 */\r
3735               if (getbit(input)) { /* 0010011 */\r
3736                 return 26;\r
3737               }\r
3738               else {      /* 0010010 */\r
3739                 if (getbit(input)) { /* 00100101 */\r
3740                   return 54;\r
3741                 }\r
3742                 else { /* 00100100 */\r
3743                   return 53;\r
3744                 }\r
3745               }\r
3746             }\r
3747             else {      /* 001000 */\r
3748               return 12;\r
3749             }\r
3750           }\r
3751         }\r
3752       }\r
3753       else {    /* 000 */\r
3754         if (getbit(input)) {  /* 0001 */\r
3755           if (getbit(input)) {  /* 00011 */\r
3756             if (getbit(input)) { /* 000111 */\r
3757               return 1;\r
3758             }\r
3759             else {      /* 000110 */\r
3760               if (getbit(input)) { /* 0001101 */\r
3761                 if (getbit(input)) { /* 00011011 */\r
3762                   return 32;\r
3763                 }\r
3764                 else { /* 00011010 */\r
3765                   return 31;\r
3766                 }\r
3767               }\r
3768               else {    /* 0001100 */\r
3769                 return 19;\r
3770               }\r
3771             }\r
3772           }\r
3773           else {    /* 00010 */\r
3774             if (getbit(input)) { /* 000101 */\r
3775               if (getbit(input)) { /* 0001011 */\r
3776                 if (getbit(input)) { /* 00010111 */\r
3777                   return 38;\r
3778                 }\r
3779                 else { /* 00010110 */\r
3780                   return 37;\r
3781                 }\r
3782               }\r
3783               else { /* 0001010 */\r
3784                 if (getbit(input)) { /* 00010101 */\r
3785                   return 36;\r
3786                 }\r
3787                 else { /* 00010100 */\r
3788                   return 35;\r
3789                 }\r
3790               }\r
3791             }\r
3792             else {      /* 000100 */\r
3793               if (getbit(input)) { /* 0001001 */\r
3794                 if (getbit(input)) { /* 00010011 */\r
3795                   return 34;\r
3796                 }\r
3797                 else { /* 00010010 */\r
3798                   return 33;\r
3799                 }\r
3800               }\r
3801               else {      /* 0001000 */\r
3802                 return 20;\r
3803               }\r
3804             }\r
3805           }\r
3806         }\r
3807         else {    /* 0000 */\r
3808           if (getbit(input)) { /* 00001 */\r
3809             if (getbit(input)) { /* 000011 */\r
3810               return 13;\r
3811             }\r
3812             else {      /* 000010 */\r
3813               if (getbit(input)) { /* 0000101 */\r
3814                 if (getbit(input)) { /* 00001011 */\r
3815                   return 48;\r
3816                 }\r
3817                 else { /* 00001010 */\r
3818                   return 47;\r
3819                 }\r
3820               }\r
3821               else {      /* 0000100 */\r
3822                 return 23;\r
3823               }\r
3824             }\r
3825           }\r
3826           else {    /* 00000 */\r
3827             if (getbit(input)) { /* 000001 */\r
3828               if (getbit(input)) { /* 0000011 */\r
3829                 return 22;\r
3830               }\r
3831               else {      /* 0000010 */\r
3832                 if (getbit(input)) { /* 00000101 */\r
3833                   return 46;\r
3834                 }\r
3835                 else { /* 00000100 */\r
3836                   return 45;\r
3837                 }\r
3838               }\r
3839             }\r
3840             else {      /* 000000 */\r
3841               if (getbit(input)) { /* 0000001 */\r
3842                 if (getbit(input)) { /* 00000011 */\r
3843                   return 30;\r
3844                 }\r
3845                 else { /* 00000010 */\r
3846                   return 29;\r
3847                 }\r
3848               }\r
3849               else { /* 0000000 */\r
3850                 return commonmake(input); /* seven zeros */\r
3851               }\r
3852             }\r
3853           }\r
3854         }\r
3855       }\r
3856     }\r
3857   }\r
3858   showline(" Impossible white run\n", 1);\r
3859   return -1;  /* error */\r
3860 }\r
3861 \r
3862 /* Compiler screws up the following code if optimizations turned on */\r
3863 \r
3864 int blackzero (FILE *input)   /* black run code starts with four zeros */\r
3865 {\r
3866 #ifdef DEBUGTIFF\r
3867   if (traceflag) showline (" blackzero entry ", 0);\r
3868 #endif\r
3869   if (getbit(input)) { /* 00001 */\r
3870     if (getbit(input)) { /* 000011 */\r
3871       if (getbit(input)) { /* 0000111 */\r
3872         return 12;\r
3873       }\r
3874       else {      /* 0000110 */\r
3875         if (getbit(input)) {  /* 00001101 */\r
3876           if (getbit(input)) { /* 000011011 */\r
3877             if (getbit(input)) { /* 0000110111 */\r
3878               return 0;\r
3879             }\r
3880             else {      /* 0000110110 */\r
3881               if (getbit(input)) { /* 00001101101 */\r
3882                 if (getbit(input)) { /* 000011011011 */\r
3883                   return 43;\r
3884                 }\r
3885                 else {      /* 000011011010 */\r
3886                   return 42;\r
3887                 }\r
3888               }\r
3889               else {      /* 00001101100 */\r
3890                 return 21;\r
3891               }\r
3892             }\r
3893           }\r
3894           else {      /* 000011010 */\r
3895             if (getbit(input)) { /* 0000110101 */\r
3896               if (getbit(input)) { /* 00001101011 */\r
3897                 if (getbit(input)) { /* 000011010111 */\r
3898                   return 39;\r
3899                 }\r
3900                 else {      /* 000011010110 */\r
3901                   return 38;\r
3902                 }\r
3903               }\r
3904               else {      /* 00001101010 */\r
3905                 if (getbit(input)) { /* 000011010101 */\r
3906                   return 37;\r
3907                 }\r
3908                 else {      /* 000011010100 */\r
3909                   return 36;\r
3910                 }\r
3911               }\r
3912             }\r
3913             else {      /* 0000110100 */\r
3914               if (getbit(input)) { /* 00001101001 */\r
3915                 if (getbit(input)) { /* 000011010011 */\r
3916                   return 35;\r
3917                 }\r
3918                 else { /* 000011010010 */\r
3919                   return 34;\r
3920                 }\r
3921               }\r
3922               else {      /* 00001101000 */\r
3923                 return 20;\r
3924               }\r
3925             }\r
3926           }\r
3927         }\r
3928         else {      /* 00001100 */\r
3929           if (getbit(input)) {  /* 000011001 */\r
3930             if (getbit(input)) { /* 0000110011 */\r
3931               if (getbit(input)) { /* 00001100111 */\r
3932                 return 19;\r
3933               }\r
3934               else {      /* 00001100110 */\r
3935                 if (getbit(input)) { /* 000011001101 */\r
3936                   return 29;\r
3937                 }\r
3938                 else {      /* 000011001100 */\r
3939                   return 28;\r
3940                 }\r
3941               }\r
3942             }\r
3943             else {      /* 0000110010 */\r
3944               if (getbit(input)) { /* 00001100101 */\r
3945                 if (getbit(input)) { /* 000011001011 */\r
3946                   return 27;\r
3947                 }\r
3948                 else {      /* 000011001010 */\r
3949                   return 26;\r
3950                 }\r
3951               }\r
3952               else {      /* 00001100100 */\r
3953                 if (getbit(input)) { /* 000011001001 */\r
3954                   return 192; /* make up */\r
3955                 }\r
3956                 else {      /* 000011001000 */\r
3957                   return 128; /* make up */\r
3958                 }\r
3959               }\r
3960             }\r
3961           }\r
3962           else {      /* 000011000 */\r
3963             return 15;\r
3964           }\r
3965         }\r
3966       }\r
3967     }\r
3968     else {      /* 000010 */\r
3969       if (getbit(input)) { /* 0000101 */\r
3970         return 11;\r
3971       }\r
3972       else {      /* 0000100 */\r
3973         return 10;\r
3974       }\r
3975     }\r
3976   }\r
3977   else {    /* 00000 */\r
3978     if (getbit(input)) { /* 000001 */\r
3979       if (getbit(input)) { /* 0000011 */\r
3980         if (getbit(input)) {  /* 00000111 */\r
3981           return 14;\r
3982         }\r
3983         else {      /* 00000110 */\r
3984           if (getbit(input)) { /* 000001101 */\r
3985             if (getbit(input)) { /* 0000011011 */\r
3986               if (getbit(input)) { /* 00000110111 */\r
3987                 return 22;\r
3988               }\r
3989               else {      /* 00000110110 */\r
3990                 if (getbit(input)) { /* 000001101101 */\r
3991                   return 41;\r
3992                 }\r
3993                 else {      /* 000001101100 */\r
3994                   return 40;\r
3995                 }\r
3996               }\r
3997             }\r
3998             else {      /* 0000011010 */\r
3999               if (getbit(input)) {  /* 00000110101 */\r
4000                 if (getbit(input)) { /* 000001101011 */\r
4001                   return 33;\r
4002                 }\r
4003                 else {      /* 000001101010 */\r
4004                   return 32;\r
4005                 }\r
4006               }\r
4007               else {      /* 00000110100 */\r
4008                 if (getbit(input)) { /* 000001101001 */\r
4009                   return 31;\r
4010                 }\r
4011                 else {      /* 000001101000 */\r
4012                   return 30;\r
4013                 }\r
4014               }\r
4015             }\r
4016           }\r
4017           else {      /* 000001100 */\r
4018             if (getbit(input)) { /* 0000011001 */\r
4019               if (getbit(input)) { /* 00000110011 */\r
4020                 if (getbit(input)) { /* 000001100111 */\r
4021                   return 63;\r
4022                 }\r
4023                 else {      /* 000001100110 */\r
4024                   return 62;\r
4025                 }\r
4026               }\r
4027               else {      /* 00000110010 */\r
4028                 if (getbit(input)) { /* 000001100101 */\r
4029                   return 49;\r
4030                 }\r
4031                 else {      /* 000001100100 */\r
4032                   return 48;\r
4033                 }\r
4034               }\r
4035             }\r
4036             else {      /* 0000011000 */\r
4037               return 17;\r
4038             }\r
4039           }\r
4040         }\r
4041       }\r
4042       else {      /* 0000010 */\r
4043         if (getbit(input)) {  /* 00000101 */\r
4044           if (getbit(input)) { /* 000001011 */\r
4045             if (getbit(input)) { /* 0000010111 */\r
4046               return 16;\r
4047             }\r
4048             else {      /* 0000010110 */\r
4049               if (getbit(input)) { /* 00000101101 */\r
4050                 if (getbit(input)) { /* 000001011011 */\r
4051                   return 256;   /* make up */\r
4052                 }\r
4053                 else {      /* 000001011010 */\r
4054                   return 61;\r
4055                 }\r
4056               }\r
4057               else {      /* 00000101100 */\r
4058                 if (getbit(input)) { /* 000001011001 */\r
4059                   return 58;\r
4060                 }\r
4061                 else {      /* 000001011000 */\r
4062                   return 57;\r
4063                 }\r
4064               }\r
4065             }\r
4066           }\r
4067           else {      /* 000001010 */\r
4068             if (getbit(input)) { /* 0000010101 */\r
4069               if (getbit(input)) { /* 00000101011 */\r
4070                 if (getbit(input)) { /* 000001010111 */\r
4071                   return 47;\r
4072                 }\r
4073                 else {      /* 000001010110 */\r
4074                   return 46;\r
4075                 }\r
4076               }\r
4077               else {      /* 00000101010 */\r
4078                 if (getbit(input)) { /* 000001010101 */\r
4079                   return 45;\r
4080                 }\r
4081                 else {      /* 000001010100 */\r
4082                   return 44;\r
4083                 }\r
4084               }\r
4085             }\r
4086             else {      /* 0000010100 */\r
4087               if (getbit(input)) { /* 00000101001 */\r
4088                 if (getbit(input)) { /* 000001010011 */\r
4089                   return 51;\r
4090                 }\r
4091                 else {      /* 000001010010 */\r
4092                   return 50;\r
4093                 }\r
4094               }\r
4095               else {      /* 00000101000 */\r
4096                 return 23;\r
4097               }\r
4098             }\r
4099           }\r
4100         }\r
4101         else {      /* 00000100 */\r
4102           return 13;\r
4103         }\r
4104       }\r
4105     }\r
4106     else {      /* 000000 */\r
4107       if (getbit(input)) { /* 0000001 */\r
4108         if (getbit(input)) { /* 00000011 */\r
4109           if (getbit(input)) { /* 000000111 */\r
4110             if (getbit(input)) { /* 0000001111 */\r
4111               return 64;  /* make up */\r
4112             }\r
4113             else {      /* 0000001110 */\r
4114               if (getbit(input)) { /* 00000011101 */\r
4115                 if (getbit(input)) { /* 000000111011 */\r
4116                   if (getbit(input)) { /* 0000001110111 */\r
4117                     return 1216;\r
4118                   }\r
4119                   else {      /* 0000001110110 */\r
4120                     return 1152;\r
4121                   }\r
4122                 }\r
4123                 else {      /* 000000111010 */\r
4124                   if (getbit(input)) { /* 0000001110101 */\r
4125                     return 1088;\r
4126                   }\r
4127                   else {      /* 0000001110100 */\r
4128                     return 1024;\r
4129                   }\r
4130 \r
4131                 }\r
4132               }\r
4133               else {      /* 00000011100 */\r
4134                 if (getbit(input)) { /* 000000111001 */\r
4135                   if (getbit(input)) { /* 0000001110011 */\r
4136                     return 960;\r
4137                   }\r
4138                   else {      /* 0000001110010 */\r
4139                     return 896;\r
4140                   }\r
4141                 }\r
4142                 else {      /* 000000111000 */\r
4143                   return 54;\r
4144                 }\r
4145               }\r
4146             }\r
4147           }\r
4148           else {      /* 000000110 */\r
4149             if (getbit(input)) { /* 0000001101 */\r
4150               if (getbit(input)) { /* 00000011011 */\r
4151                 if (getbit(input)) { /* 000000110111 */\r
4152                   return 53;\r
4153                 }\r
4154                 else {      /* 000000110110 */\r
4155                   if (getbit(input)) { /* 0000001101101 */\r
4156                     return 576; /*make up */\r
4157                   }\r
4158                   else {      /* 0000001101100 */\r
4159                     return 512; /* make up */\r
4160                   }\r
4161                 }\r
4162               }\r
4163               else {      /* 00000011010 */\r
4164                 if (getbit(input)) { /* 000000110101 */\r
4165                   return 448; /* make up */\r
4166                 }\r
4167                 else {      /* 000000110100 */\r
4168                   return 384; /* make up */\r
4169                 }\r
4170               }\r
4171             }\r
4172             else {      /* 0000001100 */\r
4173               if (getbit(input)) { /* 00000011001 */\r
4174                 if (getbit(input)) { /* 000000110011 */\r
4175                   return 320; /* make up */\r
4176                 }\r
4177                 else {      /* 000000110010 */\r
4178                   if (getbit(input)) { /* 0000001100101 */\r
4179                     return 1728;\r
4180                   }\r
4181                   else {      /* 0000001100100 */\r
4182                     return 1664;\r
4183                   }\r
4184                 }\r
4185               }\r
4186               else {      /* 00000011000 */\r
4187                 return 25;\r
4188               }\r
4189             }\r
4190           }\r
4191         }\r
4192         else { /* 00000010 */\r
4193           if (getbit(input)) { /* 000000101 */\r
4194             if (getbit(input)) { /* 0000001011 */\r
4195               if (getbit(input)) { /* 00000010111 */\r
4196                 return 24;\r
4197               }\r
4198               else {      /* 00000010110 */\r
4199                 if (getbit(input)) { /* 000000101101 */\r
4200                   if (getbit(input)) { /* 0000001011011 */\r
4201                     return 1600;\r
4202                   }\r
4203                   else {      /* 0000001011010 */\r
4204                     return 1536;\r
4205                   }\r
4206                 }\r
4207                 else {      /* 000000101100 */\r
4208                   return 60;\r
4209                 }\r
4210               }\r
4211             }\r
4212             else {      /* 0000001010 */\r
4213               if (getbit(input)) { /* 00000010101 */\r
4214                 if (getbit(input)) { /* 000000101011 */\r
4215                   return 59;\r
4216                 }\r
4217                 else {      /* 000000101010 */\r
4218                   if (getbit(input)) { /* 0000001010101 */\r
4219                     return 1472;\r
4220                   }\r
4221                   else {      /* 0000001010100 */\r
4222                     return 1408;\r
4223                   }\r
4224                 }\r
4225               }\r
4226               else {      /* 00000010100 */\r
4227                 if (getbit(input)) { /* 000000101001 */\r
4228                   if (getbit(input)) { /* 0000001010011 */\r
4229                     return 1344;\r
4230                   }\r
4231                   else {      /* 0000001010010 */\r
4232                     return 1280;\r
4233                   }\r
4234                 }\r
4235                 else {      /* 000000101000 */\r
4236                   return 56;\r
4237                 }\r
4238               }\r
4239             }\r
4240           }\r
4241           else {      /* 000000100 */\r
4242             if (getbit(input)) { /* 0000001001 */\r
4243               if (getbit(input)) { /* 00000010011 */\r
4244                 if (getbit(input)) { /* 000000100111 */\r
4245                   return 55;\r
4246                 }\r
4247                 else {      /* 000000100110 */\r
4248                   if (getbit(input)) { /* 0000001001101 */\r
4249                     return 832;\r
4250                   }\r
4251                   else {      /* 0000001001100 */\r
4252                     return 768;\r
4253                   }\r
4254                 }\r
4255               }\r
4256               else {      /* 00000010010 */\r
4257                 if (getbit(input)) { /* 000000100101 */\r
4258                   if (getbit(input)) { /* 0000001001011 */\r
4259                     return 704;\r
4260                   }\r
4261                   else {      /* 0000001001010 */\r
4262                     return 640;\r
4263                   }\r
4264                 }\r
4265                 else {      /* 000000100100 */\r
4266                   return 52;\r
4267                 }\r
4268               }\r
4269             }\r
4270             else {      /* 0000001000 */\r
4271               return 18;\r
4272             }\r
4273           }\r
4274         }\r
4275       }\r
4276       else { /* 0000000 */\r
4277         return commonmake(input); /* seven zeros */\r
4278       }\r
4279     }\r
4280   }\r
4281   showline(" Impossible black run", 1);\r
4282   showline(" (starting with four zeros)\n", 1);\r
4283   return -1;  /* error */\r
4284 }\r
4285 \r
4286 /* blackrun may actually be OK with compiler optimizations turned on */\r
4287 \r
4288 int blackrun (FILE *input)\r
4289 {\r
4290 #ifdef DEBUGTIFF\r
4291   if (traceflag)\r
4292   {\r
4293     showline ("blackrun entry ", 0);\r
4294   }\r
4295 #endif\r
4296   if (getbit(input)) {  /* 1 */\r
4297     if (getbit(input)) {  /* 11 */\r
4298       return 2;\r
4299     }\r
4300     else {      /* 10 */\r
4301       return 3;\r
4302     }\r
4303   }\r
4304   else {      /* 0 */\r
4305     if (getbit(input)) {  /* 01 */\r
4306       if (getbit(input)) {  /* 011 */\r
4307         return 4;\r
4308       }\r
4309       else {      /* 010 */\r
4310         return 1;\r
4311       }\r
4312     }\r
4313     else {      /* 00 */\r
4314       if (getbit(input)) {  /* 001 */\r
4315         if (getbit(input)) {  /* 0011 */\r
4316           return 5;\r
4317         }\r
4318         else {      /* 0010 */\r
4319           return 6;\r
4320         }\r
4321       }\r
4322       else {    /* 000 */\r
4323         if (getbit(input)) {  /* 0001 */\r
4324           if (getbit(input)) {  /* 00011 */\r
4325             return 7;\r
4326           }\r
4327           else {    /* 00010 */\r
4328             if (getbit(input)) { /* 000101 */\r
4329               return 8;\r
4330             }\r
4331             else {      /* 000100 */\r
4332               return 9;\r
4333             }\r
4334           }\r
4335         }\r
4336         else {    /* 0000 */\r
4337           return blackzero(input);  /* four zeros */\r
4338         }\r
4339       }\r
4340     }\r
4341   }\r
4342   showline(" ERROR: Impossible black run", 1);\r
4343   showline("\n", 0);\r
4344   return -1;  /* error */\r
4345 }\r
4346 \r
4347 //#pragma optimize ("lge", on)\r
4348 \r
4349 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
4350 \r
4351 /* FOLLOWING IS EXPERIMENT 97/OCT/21 */\r
4352 \r
4353 //#pragma optimize ("lge", off)\r
4354 \r
4355 int index, bitinx;  /* index into row of bytes and bits within them */\r
4356 \r
4357 int total;      /* maybe long ? */\r
4358 \r
4359 /* Following could be speeded up some ... */\r
4360 \r
4361 int writewhite (unsigned char *lpBuffer, int run, int width)\r
4362 {\r
4363   if (run == 0) return 0;     /* nothing to do */\r
4364   if (run < 0) return -1;     /* hit invalid run */\r
4365   total += run;\r
4366 #ifdef DEBUGTIFF\r
4367   if (traceflag) {\r
4368     sprintf(logline, "run %d total %d\n", run, total);\r
4369     showline(logline, 0);\r
4370   }\r
4371 #endif\r
4372   if (total > width) return -1; /* error */\r
4373 /*  just advance pointers */\r
4374   while (run > 0) {\r
4375     if (bitinx == 0) {\r
4376       while (run >= 8) {  \r
4377         index++;\r
4378 #ifdef DEBUGTIFF\r
4379         if (traceflag) {\r
4380           sprintf(logline, "index %d run %d ", index, run);\r
4381           showline(logline, 0);\r
4382         }\r
4383 #endif\r
4384 /*        *(lpBuffer+index) = 0; */ /* already zeroed out */\r
4385         run -= 8;\r
4386       }\r
4387     }\r
4388     if (run > 0) {\r
4389       if (bitinx-- <=  0) {\r
4390         index++; bitinx = 7;\r
4391       }\r
4392 #ifdef DEBUGTIFF\r
4393       if (traceflag) {\r
4394         sprintf(logline, "index %d bitinx %d ", index, bitinx);\r
4395         showline(logline, 0);\r
4396       }\r
4397 #endif\r
4398 /*      *(lpBuffer + index) &= ~(1 << bitinx); */\r
4399       run--;\r
4400     }\r
4401   }\r
4402   if (total == width) return 1; /* EOL */\r
4403   else return 0;\r
4404 }\r
4405 \r
4406 int writeblack (unsigned char *lpBuffer, int run, int width)\r
4407 {\r
4408   if (run == 0) return 0;     /* nothing to do */\r
4409   if (run < 0) return -1;     /* hit invalid run */\r
4410   total += run;\r
4411 #ifdef DEBUGTIFF\r
4412   if (traceflag) {\r
4413     sprintf(logline, "run %d total %d\n", run, total);\r
4414     showline(logline, 0);\r
4415   }\r
4416 #endif\r
4417   if (total > width) return -1; /* error */\r
4418   while (run > 0) {\r
4419     if (bitinx == 0) {\r
4420       while (run >= 8) {  \r
4421         index++;\r
4422 #ifdef DEBUGTIFF\r
4423         if (traceflag) {\r
4424           sprintf(logline, "index %d run %d ", index, run);\r
4425           showline(logline, 0);\r
4426         }\r
4427 #endif\r
4428         *(lpBuffer+index) = 255;  /* write a byte at a time */\r
4429         run -= 8;\r
4430       }\r
4431     }\r
4432     if (run > 0) {\r
4433       if (bitinx-- <=  0) {\r
4434         index++; bitinx = 7;\r
4435       }\r
4436 #ifdef DEBUGTIFF\r
4437       if (traceflag) {\r
4438         sprintf(logline, "index %d bitinx %d ", index, bitinx);\r
4439         showline(logline, 0);\r
4440       }\r
4441 #endif\r
4442       *(lpBuffer + index) |= (1 << bitinx); /* write a bit at a time */\r
4443       run--;\r
4444     }\r
4445   }\r
4446   if (total == width) return 1; /* EOL */\r
4447   else return 0;\r
4448 }\r
4449 \r
4450 /* make width long ? */\r
4451 \r
4452 int huffmanrow (unsigned char *lpBuffer, FILE *input, int width)\r
4453 {\r
4454   int k, bytes;\r
4455   int run;\r
4456 /*  int total = 0; */             /* long total ? */\r
4457 \r
4458 /*  if (lpBuffer == NULL) {\r
4459     showline(" Bad buffer pointer\n", 1);\r
4460     return -1;\r
4461   } */\r
4462   total = 0;\r
4463   index = -1; bitinx = 0;   /* output buffering */\r
4464   bytex = 0; bitsleft = 0;    /* input buffering */\r
4465 \r
4466   bytes = (width + 7) / 8;  /* preset with zeros */\r
4467 #ifdef DEBUGTIFF\r
4468   if (traceflag) {\r
4469     sprintf(logline, "Cleaning out %d bytes\n", bytes);\r
4470     showline(logline, 0);\r
4471   }\r
4472 #endif\r
4473   for (k = 0; k < bytes; k++) lpBuffer[k] = 0;\r
4474 \r
4475   for (;;) {\r
4476 #ifdef DEBUGTIFF\r
4477     if (traceflag) {\r
4478       sprintf(logline, "Looking for white run\n");\r
4479       showline(logline, 0);\r
4480     }\r
4481 #endif\r
4482     while ((run = whiterun (input)) >= 64) {\r
4483 #ifdef DEBUGTIFF\r
4484       if (traceflag) {\r
4485         sprintf(logline, " W %d ", run);\r
4486         showline(logline, 0);\r
4487       }\r
4488 #endif\r
4489       if (writewhite(lpBuffer, run, width) < 0) break;\r
4490     }\r
4491     if (total >= width) break;\r
4492 #ifdef DEBUGTIFF\r
4493     if (traceflag) {\r
4494       sprintf(logline, " W %d\n", run);\r
4495       showline(logline, 0);\r
4496     }\r
4497 #endif\r
4498     if (writewhite(lpBuffer, run, width) != 0) break;  /* terminal run */\r
4499 \r
4500 #ifdef DEBUGTIFF\r
4501     if (traceflag) {\r
4502       sprintf(logline, "Looking for black run\n");\r
4503       showline(logline, 0);\r
4504     }\r
4505 #endif\r
4506     while ((run = blackrun (input)) >= 64) {\r
4507 #ifdef DEBUGTIFF\r
4508       if (traceflag) {\r
4509         sprintf(logline, " B %d ", run);\r
4510         showline(logline, 0);\r
4511       }\r
4512 #endif\r
4513       if (writeblack(lpBuffer, run, width) < 0) break;\r
4514     }\r
4515     if (total >= width) break;\r
4516 #ifdef DEBUGTIFF\r
4517     if (traceflag) {\r
4518       sprintf(logline, " B %d\n", run);\r
4519       showline(logline, 0);\r
4520     }\r
4521 #endif\r
4522     if (writeblack(lpBuffer, run, width) != 0) break;  /* terminal run */\r
4523   }\r
4524   if (total != width) {\r
4525     sprintf(logline, " Sum of runs %d not equal width %d\n", total, width);\r
4526     showline(logline, 1);\r
4527     return -1;\r
4528   }\r
4529 #ifdef DEBUGTIFF\r
4530   else if (traceflag ) {\r
4531     sprintf(logline, "Sum of runs equal to width %d\n", width);\r
4532     showline(logline, 0);\r
4533   }\r
4534 #endif\r
4535   return 0;\r
4536 }\r
4537 \r
4538 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
4539 \r
4540 //#pragma optimize ("lge", on)    /* experiment 2000 June 17 */\r
4541 \r
4542 /* Here is the code for LZW (compression scheme number 5) input side */\r
4543 \r
4544 char *StringByte=NULL;      /* contains last byte of string */\r
4545 \r
4546 char *StringFirst=NULL;     /* contains first byte of string */\r
4547                     /* to speed up processing ... */\r
4548 \r
4549 #ifdef USESHORTINT\r
4550 short int *StringPrevious=NULL; /* points to previous char of string */\r
4551 short int *StringLength=NULL;   /* length of string */\r
4552                     /* to speed up processing ... */\r
4553 #else\r
4554 int *StringPrevious=NULL;     /* points to previous char of string */\r
4555 int *StringLength=NULL;     /* length of string */\r
4556                     /* to speed up processing ... */\r
4557 #endif\r
4558 \r
4559 int TableIndex=FIRSTCODE;         /* index into above String Tables */\r
4560                     /* next available string entry */\r
4561 \r
4562 int CodeLength=9;           /* current code length INPUT */\r
4563 \r
4564 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
4565 \r
4566 /* following is never called ? now called from dvipsone.c when exiting */\r
4567 \r
4568 void DeAllocStringsIn (void)   /* remember to do this at end */\r
4569 {\r
4570 /*  if (Memory != NULL) {\r
4571     free(Memory); Memory = NULL;\r
4572   } */\r
4573   if (StringByte != NULL) {\r
4574     free(StringByte); StringByte = NULL;\r
4575   }\r
4576   if (StringFirst != NULL) {\r
4577     free(StringFirst); StringFirst = NULL;\r
4578   }\r
4579   if (StringPrevious != NULL) {\r
4580     free(StringPrevious); StringPrevious = NULL;\r
4581   }\r
4582   if (StringLength != NULL) {\r
4583     free(StringLength); StringLength = NULL;\r
4584   }\r
4585 }\r
4586 \r
4587 /* worry here about allocation in NT ? sizeof(int) */\r
4588 \r
4589 int AllocStringsIn (void)\r
4590 {\r
4591 /*  if (Memory == NULL) {\r
4592     Memory = (char *) malloc(INIMEMORY);\r
4593     MemorySize = INIMEMORY;\r
4594   } */ /* memory for strings in string table */\r
4595   if (StringByte == NULL) { /* allocate string table indeces */\r
4596     StringByte = (char *) malloc(MAXCODES * sizeof(char));\r
4597   }\r
4598   if (StringFirst == NULL) {  /* allocate string table indeces */\r
4599     StringFirst = (char *) malloc(MAXCODES * sizeof(char));\r
4600   }\r
4601 /*  should this be short int in NT ? */\r
4602 #ifdef USESHORTINT\r
4603   if (StringPrevious == NULL) { /* allocate string table lengths */\r
4604     StringPrevious = (short int *)\r
4605              malloc(MAXCODES * sizeof(short int));\r
4606   }\r
4607   if (StringLength == NULL) { /* allocate string table lengths */\r
4608     StringLength = (short int *)\r
4609              malloc(MAXCODES * sizeof(short int));\r
4610   }\r
4611 #else\r
4612   if (StringPrevious == NULL) { /* allocate string table lengths */\r
4613     StringPrevious = (int *) malloc(MAXCODES * sizeof(int));\r
4614   }\r
4615   if (StringLength == NULL) { /* allocate string table lengths */\r
4616     StringLength = (int *) malloc(MAXCODES * sizeof(int));\r
4617   }\r
4618 #endif\r
4619 /*  if (Memory == NULL || StringTable == NULL ||  StringLength == NULL) { */\r
4620   if (StringByte == NULL || StringFirst == NULL ||\r
4621     StringPrevious == NULL || StringLength == NULL) {\r
4622     showline("Unable to allocate memory\n", 1);\r
4623     checkexit(1);\r
4624 //    or more serious exit(1) ???\r
4625   }\r
4626   return 0;\r
4627 }\r
4628 \r
4629 void InitializeStringTable (void)  /* set up string table initially */\r
4630 {\r
4631   int k;\r
4632 \r
4633   AllocStringsIn();         /* grab memory for tables if needed */\r
4634 //  What if it failed ???\r
4635   for (k = 0; k < MAXCHR; k++) {  /* 256 single byte strings */\r
4636     StringByte[k] = (char) k;\r
4637     StringFirst[k] = (char) k;\r
4638     StringPrevious[k] = -1;   /* indicate beginning of string */\r
4639     StringLength[k] = 1;\r
4640   }\r
4641 /*  FreeIndex = MAXCHR; */\r
4642   TableIndex = FIRSTCODE;\r
4643   CodeLength = 9;         /* initial code length */\r
4644 }\r
4645 \r
4646 void ResetStringTable (int quietflag) /* clear string table */\r
4647 {\r
4648 /*  int k; */\r
4649 \r
4650 #ifdef DEBUGTIFF\r
4651   if (!quietflag)\r
4652   {\r
4653     if (traceflag) showline("CLEAR ", 0);\r
4654     if (traceflag) showline("\n", 0);\r
4655     if (traceflag && TableIndex > FIRSTCODE)\r
4656     {\r
4657 /*      printf("TableIndex %d FreeIndex %u CodeLength %d\n",\r
4658         TableIndex, FreeIndex, CodeLength); */\r
4659       sprintf(logline, "TableIndex %d CodeLength %d\n", TableIndex, CodeLength);\r
4660       showline(logline, 0);\r
4661     }\r
4662   } \r
4663 #endif\r
4664 /*  following not really needed */\r
4665 /*  for (k = FIRSTCODE; k < TableIndex; k++) {\r
4666     StringTable[k] = 0;\r
4667     StringLength[k] = 0;\r
4668   } */\r
4669 /*  FreeIndex = MAXCHR; */\r
4670   TableIndex = FIRSTCODE;\r
4671   CodeLength = 9;\r
4672 }\r
4673 \r
4674 #ifdef USESHORTINT\r
4675 void AddNewEntry (short int OldCode, short int Code)\r
4676 {\r
4677 #else\r
4678 void AddNewEntry (int OldCode, int Code)\r
4679 {\r
4680 #endif\r
4681 /*  char *s; */\r
4682 /*  char *t; */\r
4683 /*  int k; */\r
4684 \r
4685 #ifdef DEBUGLZW\r
4686   if (traceflag)\r
4687   {\r
4688     sprintf(logline, "Add string TableIndex %4d (%d)\n",\r
4689          TableIndex, StringLength[OldCode] + 1);\r
4690     showline(logline, 0);\r
4691   }\r
4692 #endif\r
4693 \r
4694 /*  This is where we enter new one in table */\r
4695 /*  StringTable[TableIndex] = FreeIndex; */\r
4696 /*  StringLength[TableIndex] = len; */\r
4697   StringByte[TableIndex] = StringFirst[Code];\r
4698   StringFirst[TableIndex] = StringFirst[OldCode];\r
4699   StringPrevious[TableIndex] = OldCode;\r
4700 #ifdef USESHORTINT\r
4701   StringLength[TableIndex] =\r
4702         (unsigned short int) (StringLength[OldCode] + 1);\r
4703 #else\r
4704   StringLength[TableIndex] = StringLength[OldCode] + 1;\r
4705 #endif\r
4706   TableIndex++;\r
4707 /*  s = Memory + FreeIndex; */\r
4708 /*  t = Memory + StringTable[OldCode]; */\r
4709 /*  for (k = 0; k < len-1; k++) *s++ = *t++; */\r
4710 /*  t = Memory + StringTable[Code];  */\r
4711 /*  *s = *t; */         /* last byte comes from next code string */\r
4712 /*  FreeIndex += len; */\r
4713 \r
4714   if (TableIndex == 511 || TableIndex == 1023 || TableIndex == 2047)\r
4715   {\r
4716     CodeLength++;\r
4717 #ifdef DEBUGTIFF\r
4718     if (traceflag)\r
4719     {\r
4720       sprintf(logline, "LENGTH %d (%d)\n", TableIndex, CodeLength);\r
4721       showline(logline, 0);\r
4722     }\r
4723 #endif\r
4724   }\r
4725 \r
4726   if (TableIndex > MAXCODES)\r
4727   {\r
4728     showline(" ERROR: Table overflow\n", 1);\r
4729     checkexit(1);\r
4730   }\r
4731 }\r
4732 \r
4733 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
4734 \r
4735 int IsInTable (int Code)  /* is code already in table ? */\r
4736 {\r
4737   return (Code >= 0 && Code < TableIndex);\r
4738 }\r
4739 \r
4740 /* copy string from table by code number */\r
4741 \r
4742 unsigned char *WriteString (unsigned char *buffer, int Code)\r
4743 {\r
4744 /*  int k; */\r
4745   int n, len=0;\r
4746   unsigned char *s;\r
4747   unsigned char *t;\r
4748 \r
4749 /*  s = buffer; */\r
4750 /*  t = Memory + StringTable[Code]; */\r
4751 //  if (Code < TableIndex)\r
4752   len = StringLength[Code];\r
4753   t = buffer + len;         /* byte after last one to copy */\r
4754   if (t > StripData + StripDataLen) {\r
4755 /*    special case kludge if terminates right after code length switch */\r
4756     if (((unsigned int) (buffer - StripData) == StripDataLen) &&\r
4757 // kludge to try and deal with lack of code length increase just before EOI\r
4758         ((Code == (EOD*2)) || (Code == (EOD*4))))  // 2000/Feb/4\r
4759     {\r
4760       return buffer;\r
4761     } /* 98/Sep/22 */\r
4762 /*    showline(" ERROR: ran off end of Strip Buffer\n", 1); */\r
4763     sprintf(logline, \r
4764       "ERROR: Strip Buffer len %d code %d EOD %d CodeLength %d TableIndex %d",\r
4765         len, Code, EOD, CodeLength, TableIndex);\r
4766     showline(logline, 0);\r
4767     if (traceflag) {\r
4768       sprintf(logline,\r
4769       "code %d len %d buffer %ld buffer + len %ld stripdatalen %ld\n",\r
4770          Code, len, buffer-StripData, t-StripData, StripDataLen);\r
4771       showline(logline, 0);\r
4772     }\r
4773     return buffer;\r
4774   }\r
4775   s = t - 1;              /* last byte to copy */\r
4776 /*  for (k = 0; k < len; k++) *s++ = *t++; */\r
4777   n = Code;\r
4778 /*  for (k = 0; k < len; k++) */\r
4779 /*  for (k = len; k > 0; k--) */\r
4780   while (n >= 0) {\r
4781 /*    if (k != StringLength[n])\r
4782       printf("k %d <> len %d ", k, StringLength[n]); */ /* check */\r
4783     *s-- = StringByte[n];           /* copy the byte */\r
4784 /*    if (StringPrevious[n] < 0 && k != 1)\r
4785       printf("k %d n %d Code %d ", k, n, Code); */\r
4786     n = StringPrevious[n];\r
4787 /*    if (n < 0) break; */            /* termination */\r
4788   }\r
4789   if ((s + 1) != buffer) {            /* sanity check */\r
4790     int err;\r
4791     if ((s+1) > buffer) err = (s+1) - buffer;\r
4792     else err = buffer - (s+1);\r
4793     sprintf(logline, "Off by %d (len %d Code %d)\n", err, len, Code);\r
4794     showline(logline, 1);\r
4795   }\r
4796 /*  s = buffer;\r
4797   while (s < t) {\r
4798     if (*s++ != 0) putc('1', stdout);\r
4799     else putc('0', stdout);\r
4800     if (counter++ % 1024 == 0) putc('\n', stdout);\r
4801   }\r
4802   return buffer; */                 /* TESTING HACK! */\r
4803   return t;\r
4804 }\r
4805 \r
4806 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
4807 \r
4808 unsigned long OldByte=0;    /* cadaver being eaten */\r
4809 int OldBitsLeft=0;        /* how many bits left in OldByte */\r
4810 \r
4811 #ifdef USESHORTINT\r
4812 short int GetNextCode (FILE *input) /* get next LZW code number from input  */\r
4813 {\r
4814 #else\r
4815 int GetNextCode (FILE *input) /* get next LZW code number from input  */\r
4816 {\r
4817 #endif\r
4818   int bits;\r
4819   int c;\r
4820   unsigned long k;\r
4821 \r
4822   bits = OldBitsLeft;         /*  how many bits do we have */\r
4823   k = OldByte;            /*  start with old bits */\r
4824 \r
4825   while (bits < CodeLength) {     /* need more bits ? */\r
4826     if (InStripLen-- <= 0) {    /* treat as EOD 96/Nov/17 */\r
4827       if (traceflag) {\r
4828         sprintf(logline, " No EOD at end of strip %d ", CurrentStrip);\r
4829         showline(logline, 1);\r
4830       }\r
4831       return EOD;\r
4832     }\r
4833     if ((c = getc(input)) == EOF)\r
4834     {\r
4835       sprintf(logline, " Unexpected EOF (%s)\n", "getnextcode");\r
4836       showline(logline, 1);\r
4837       checkexit(1);\r
4838 //      finish = -1;\r
4839 //      return -1;          /* EOF serious error ... */\r
4840     } \r
4841     k = (k << 8) | c;\r
4842     bits += 8;\r
4843   }\r
4844   OldByte = k;\r
4845   OldBitsLeft = bits - CodeLength;    /* extra bits not used */\r
4846 /*  OldByte = OldByte & ((1 << OldBitsLeft) - 1); *//* redundant */\r
4847   k = k >> OldBitsLeft;         /* shift out extra bits */\r
4848   k = k & ((1 << CodeLength) - 1);    /* mask out high order */\r
4849 #ifdef DEBUGLZW\r
4850   if (traceflag) {\r
4851     sprintf(logline, "CODE %4d ", k);\r
4852     showline(logline, 0);\r
4853   }\r
4854 #endif\r
4855 #ifdef USESHORTINT\r
4856   return (short int) k;\r
4857 #else\r
4858   return (int) k;\r
4859 #endif\r
4860 }\r
4861 \r
4862 void LZWdecompress (unsigned char *StripData, FILE *input)\r
4863 {\r
4864 #ifdef USESHORTINT\r
4865   short int Code, OldCode;\r
4866 #else\r
4867   int Code, OldCode;\r
4868 #endif\r
4869   unsigned int nlen;\r
4870   unsigned char *s = StripData;\r
4871 \r
4872   OldCode = 0;            /* to keep compiler happy */\r
4873 /*  InitializeStringTable(); */     /* assume already done once */\r
4874 /*  ResetStringTable(1); */       /* not needed - first code CLEAR */\r
4875   while ((Code = GetNextCode(input)) != EOD) {\r
4876     if (Code == -1) {       // error check only\r
4877       showline(" ERROR: Premature end of LZW", 1);\r
4878       showline("\n", 0);\r
4879       return;\r
4880     }\r
4881 // #ifdef DEBUGLZW\r
4882 //    if (traceflag) {\r
4883 //      sprintf(logline, "%4d ", Code);       /* debugging */\r
4884 //      showline(logline, 0);\r
4885 //    }\r
4886 // #endif\r
4887     if (Code == CLEAR) {\r
4888       ResetStringTable(0);\r
4889       Code = GetNextCode(input);\r
4890       if (traceflag) showline("\n", 0);\r
4891       if (Code == -1) {     // error check only\r
4892         showline(" ERROR: Premature end of LZW", 1);\r
4893         showline(" (after CLEAR)", 0);\r
4894         showline("\n", 0);\r
4895         return;\r
4896       }\r
4897       if (Code == EOD) break;\r
4898       s = WriteString(s, Code);\r
4899       OldCode = Code;\r
4900     }               /* end of CLEAR case */\r
4901     else {\r
4902 //      if (IsInTable(Code)) {\r
4903       if (Code >= 0 && Code < TableIndex) {\r
4904 /*        AddTableEntry(StringTable(OldCode)\r
4905           + FirstChar(StringFromCode(Code);)); */\r
4906         AddNewEntry(OldCode, Code);\r
4907         s = WriteString(s, Code);\r
4908         OldCode = Code;\r
4909       }             /* end of Code in Table case */\r
4910       else {            /* Code is *not* in table */\r
4911 /*        OutString = StringFromCode (OldCode) +\r
4912           + FirstChar(StringFromCode(Code);)); */\r
4913         if (Code > TableIndex) {\r
4914 // kludge to try and deal with lack of code length increase just before EOI\r
4915           Code = Code / 2;\r
4916           OldBitsLeft++;\r
4917 //          CodeLength--;\r
4918           if (traceflag) {\r
4919             sprintf(logline,\r
4920               " Code (%d) > TableIndex (%d) CodeLength %d ",\r
4921               Code, TableIndex, CodeLength);\r
4922             showline(logline, 1);\r
4923           }\r
4924 //          break;      /* ugh! */\r
4925         }         // error check only\r
4926 /*        strcpy(Omega, StringFromCode(OldCode));\r
4927         ConcatOneChar(Omega, StringFromCode(OldCode));\r
4928         WriteString(Omega, output);\r
4929         AddTableEntry(Omega); */\r
4930         AddNewEntry(OldCode, OldCode); \r
4931         s = WriteString(s, Code);\r
4932         OldCode = Code;\r
4933       } /* end of Code *not* in Table case */\r
4934     } /* end of *not* CLEAR case */\r
4935   } /* end of not EOD loop */\r
4936 \r
4937 /*  if (bExpandColor) nlen = StripDataLen / 3;\r
4938   else nlen = StripDataLen; */ /* ??? */\r
4939   if (traceflag) {  /*  NOTE: mismatch on last strip is OK */\r
4940     if (CurrentStrip < StripsPerImage-1) {        /* 96/Nov/17 */\r
4941       if (bExpandColor) nlen = StripDataLen / 3;\r
4942       else nlen = StripDataLen;\r
4943       if ((unsigned int) (s - StripData) != nlen) {\r
4944         sprintf(logline,\r
4945         " Strip data mismatch %u < %u bytes (Strip %d of %ld)\n",\r
4946             (s - StripData), nlen, CurrentStrip, StripsPerImage);\r
4947         showline(logline, 1);\r
4948       }\r
4949     }\r
4950   } \r
4951 \r
4952 /*  if (verboseflag) printf("EOD "); */\r
4953 /*  reset table for next one */\r
4954   ResetStringTable(0);\r
4955 #ifdef DEBUGTIFF\r
4956   if (traceflag)\r
4957   {\r
4958     sprintf(logline, "Now at byte %ld in file\n", ftell(input));\r
4959     showline(logline, 0);\r
4960   }\r
4961 #endif\r
4962 }\r
4963 \r
4964 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***  */\r
4965 \r
4966 /* Set up StripOffset & StripByteCount for strip number k */\r
4967 /* and go to start of data for strip number k */\r
4968 /* First one was already set up - don't disturb in case not indirect */\r
4969 /* In practice, strips are usually contiguous, but no guarantee... */\r
4970 \r
4971 long SetupStrip (FILE *input, int k)      /* 96/Nov/17 */\r
4972 {\r
4973   if (k > 0) {\r
4974     StripOffset = indirectvalue(StripOffsetsType, 1,\r
4975       StripOffsetsPtr + k * typesize[StripOffsetsType], input);\r
4976     StripByteCount = indirectvalue(StripByteCountsType, 1,\r
4977       StripByteCountsPtr + k * typesize[StripByteCountsType], input);\r
4978   }\r
4979 #ifdef DEBUGTIFF\r
4980   if (traceflag) {\r
4981     sprintf(logline, "Strip %d Offset %ld ByteCount %ld\n",\r
4982     k, StripOffset, StripByteCount);\r
4983     showline(logline, 0);\r
4984   }\r
4985 #endif\r
4986   if (fseek (input, StripOffset, SEEK_SET))\r
4987   {\r
4988     showline("Error in seek to StripOffset", 1);  /* ??? */\r
4989     finish = -1;\r
4990     return -1;\r
4991   }\r
4992   if (k == 0 && StripByteCount < 0)\r
4993     StripByteCount = 0XFFFFFF;    // kludge if missing 2000/Apr/13\r
4994   return StripByteCount;            /* 96/Nov/17 */\r
4995 }\r
4996 \r
4997 /* Copy a row from far space used by LZW to near space used for output */\r
4998 \r
4999 void CopyRow (unsigned char *lpBuffer, unsigned char *StripData,\r
5000     long InRowLength)\r
5001 {\r
5002   int k, n;\r
5003   unsigned char *s=lpBuffer;\r
5004   unsigned char *t=StripData;\r
5005   n = (int) InRowLength;    /* assuming row not longer than 32k */\r
5006 /*  if (InRowLength > BufferLength) { */ /* DEBUGGING 95/Nov/10 */\r
5007   if (InRowLength > BufferLength+1) {  /* DEBUGGING 95/Nov/10 */\r
5008     sprintf(logline, " ERROR: InRowLength %ld > BufferLength %ld\n",\r
5009         InRowLength, BufferLength);\r
5010     showline(logline, 1);\r
5011 /*    return; */\r
5012     n = (int) BufferLength;      /* prevent heap corruption */\r
5013   }\r
5014   for (k = 0; k < n; k++) *s++ = *t++; \r
5015 }\r
5016 \r
5017 /* A whole strip is treated as one unit for LZW encoding ... */\r
5018 /* So need to do once per strip and need memory for strip output */\r
5019 \r
5020 int DecodeLZW (FILE *output, FILE *input, unsigned char *lpBuffer)\r
5021 {\r
5022   int k, row = 0, i, j, n, m, flag = 0;\r
5023 /*  unsigned char *StripData; */\r
5024   long nlen;\r
5025 \r
5026   nlen = (long) BufferLength * RowsPerStrip;\r
5027 #ifdef IGNORED\r
5028 /*  is this 65535U limit still valid in NT ? malloc limitation ? */\r
5029   if (nlen > 65535U) {\r
5030     sprintf(logline, " Cannot handle Strip Buffer of %lu bytes\n", nlen);\r
5031     showline(logline, 1);\r
5032 /*    nlen = 30000U;  */        /* TESTING HACK! */\r
5033     checkexit(1); \r
5034   }\r
5035 #endif\r
5036   StripDataLen = (unsigned int) nlen;\r
5037 #ifdef DEBUGTIFF\r
5038   if (traceflag) {            /* debugging */\r
5039     sprintf(logline, " Allocating %u bytes for Strip Buffer\n", StripDataLen);\r
5040     showline(logline, 0);\r
5041   }\r
5042 #endif\r
5043   StripData = (unsigned char *) malloc(StripDataLen);\r
5044 /*    malloc((unsigned int) (InRowLength * RowsPerStrip)); */\r
5045 /*    malloc((unsigned int) (BufferLength * RowsPerStrip)); */\r
5046   if (StripData == NULL) {\r
5047 //    showline(" ", 0);\r
5048     showline(" Unable to allocate memory\n", 1);  /* 1995/July/15 */\r
5049     checkexit(1);\r
5050 //    or more serious exit(1) ???\r
5051   }\r
5052   InitializeStringTable(); \r
5053 /*  checkheap("AFTER INITIALIZE", 0); */  /* debugging only 1995/Nov/10 */\r
5054   row = 0;\r
5055   for (k = 0; k < StripsPerImage; k++) {\r
5056     CurrentStrip = k;         /* global for debug output */\r
5057 /*    SetupStrip(input, k); */\r
5058     InStripLen = SetupStrip(input, k);  /* save GetNextCode 96/Nov/17 */\r
5059     OldByte = 0;  OldBitsLeft = 0;\r
5060     ResetStringTable(1);      /* redundant ? */\r
5061     LZWdecompress(StripData, input);\r
5062     n = RowsPerStrip;\r
5063     if (row + n > ImageLength) n = (int) (ImageLength - row);\r
5064     for (i = 0; i < n; i++) {\r
5065       CopyRow(lpBuffer, StripData + i * InRowLength, InRowLength);\r
5066 /*      Following new 1996/Sep/9 */\r
5067       if (Predictor == 2) {   /* only applies to LZW images */\r
5068 /*        We will assume here that BitsPerSample == 8 ... */\r
5069 /*        if (SamplesPerPixel == 1) */      /* gray level */\r
5070         if (SamplesPerPixelX == 1) {      /* gray level */\r
5071           for (j = 1; j < InRowLength; j++)\r
5072 /*            lpBuffer[j] += lpBuffer[j-1]; */\r
5073             lpBuffer[j] = (unsigned char) (lpBuffer[j] + lpBuffer[j-1]);\r
5074         }\r
5075         else {                /* RGB (3) or CMYK (4) */\r
5076 /*          for (j = SamplesPerPixel; j < InRowLength; j++) */\r
5077           for (j = SamplesPerPixelX; j < InRowLength; j++)\r
5078 /*            lpBuffer[j] += lpBuffer[j-SamplesPerPixel]; */\r
5079             lpBuffer[j] =\r
5080 /*              (unsigned char) (lpBuffer[j] + lpBuffer[j-SamplesPerPixel]); */\r
5081               (unsigned char) (lpBuffer[j] + lpBuffer[j-SamplesPerPixelX]);\r
5082         }\r
5083       }   \r
5084       if (ExtraSamples > 0)\r
5085         (void) RemoveExtraSamples(lpBuffer, InRowLength); /* 99/May/10 */\r
5086 /*      if (ProcessRow (output, lpBuffer, InRowLength, BufferLength, */\r
5087       if (ProcessRow (output, lpBuffer, InRowLengthX, BufferLength,\r
5088         OutRowLength) != 0) break;  /* break if output error */\r
5089 /*      if (bCompressColor)\r
5090         compresscolorfar(StripData + i * BufferLength, InRowLength);\r
5091       if (writearowfar (output, StripData + i * BufferLength,\r
5092         OutRowLength) != 0) {\r
5093         flag = 1;\r
5094         break;\r
5095       }\r
5096       if (flag) break; */\r
5097     }\r
5098     row += n;\r
5099   }\r
5100   ResetStringTable(1);      /* redundant ? */\r
5101 #ifdef DEBUGTIFF\r
5102   if (traceflag) {          /* debugging */\r
5103     sprintf(logline, " Freeing %u bytes Strip Buffer\n", StripDataLen);\r
5104     showline(logline, 0);\r
5105   }\r
5106 #endif\r
5107   free(StripData);\r
5108   StripData = NULL;       /* debugging 95/Nov/10 */\r
5109   if (traceflag) { /* debugging code added */ /* should work also in NT */\r
5110     if ((m = _heapchk ()) != _HEAPOK) {     /* 1995/Nov/10 */\r
5111       sprintf(logline, " ERROR: heap corrupted (%d)\n", m);\r
5112 /*      sprintf(logline, " ERROR: __near heap corrupted (%d)\n", m); */\r
5113       showline(logline, 1);\r
5114 /*      checkexit(9); */\r
5115       exit(9);      /* terminate with extreme prejudice */\r
5116     }\r
5117   }\r
5118   return flag;\r
5119 }\r
5120 \r
5121 /* InitializeStringTable AllocString - may need to DeAllocString eventually */\r
5122 \r
5123 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
5124 \r
5125 /* change long => int where sensible */\r
5126 \r
5127 /* complain if samplesperpixel other than one */ /* no color support */\r
5128 /* quit early (before writing header) if 24 bit image */\r
5129 \r
5130 /* implement CCIT Huffman decompression also OK */\r
5131 /* implement LZW decompression also */ /* need Predictor also ? */\r
5132 \r
5133 /* implement gray scale response curve ? */ /* although ignored by some apps */\r
5134 \r
5135 /* II* or MM* followed by four byte offset to first IFD (often == 8) */\r
5136 \r
5137 /* IFD: 2 byte count of fields, followed by 12 byte tag fields */\r
5138 /* after that, four byte offset to next IFD (or zero) (or junk!) */\r
5139 \r
5140 /* Field entries sorted in ascending order on tag: */\r
5141 \r
5142 /* Byte 0 & 1: tag */\r
5143 /* Byte 2 & 3: type */\r
5144 /* Byte 4 - 7: `length' (better called `count') */\r
5145 /* Byte 8 -11: value offset -- always even  (or value itself if it fits) */\r
5146 \r
5147 /* if bAllowColor is false, maybe just use green component and `image' */\r
5148 \r
5149 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */\r
5150 \r
5151 BOOL bTIFFAllow=1;\r
5152 \r
5153 /* x * (numer / denom) 1995/Oct/12 */\r
5154 /* or use MulDiv ??? */\r
5155 \r
5156 long MulRatio (long x, unsigned long numer, unsigned long denom)\r
5157 {\r
5158   long result;\r
5159   if (denom == 0 || numer == 0) return 0;\r
5160   if ((numer % denom) == 0) {\r
5161     numer = numer / denom;\r
5162     denom = 1;\r
5163   }\r
5164   if ((denom % numer) == 0) {\r
5165     denom = denom / numer;\r
5166     numer = 1;\r
5167   }\r
5168   while (denom > 65536 || numer > 65536) {\r
5169     denom = denom >> 1;\r
5170     numer = numer >> 1;\r
5171   }\r
5172   result = x / denom * numer;\r
5173   return result;    \r
5174 }\r
5175 \r
5176 // long MulRatio (long x, unsigned long numer, unsigned long denom) {\r
5177 //  if (denom == 0 || numer == 0) return 0;\r
5178 //  else return(MulDiv(x, numer, denom));\r
5179 // }\r
5180 \r
5181 /* actually insert the TIFF figure here */\r
5182 /* negative nifd indicates figure missing - draw box and filename only */\r
5183 /* if dheight == 0 => calculate dheight from dwidth based on aspect ratio */\r
5184 /* if dwidth == 0 => calculate dwidth & dheight from xres and yres */\r
5185 \r
5186 /* actually insert the TIFF figure here */\r
5187 /* negative nifd indicates figure missing - draw box and filename only */\r
5188 /* if dheight == 0 => calculate dheight from dwidth based on aspect ratio */\r
5189 \r
5190 int showtiffhere (FILE *output, char *filename, long dwidth, long dheight,\r
5191          double xscale, double yscale,  int nifd)\r
5192 {\r
5193   int flag;\r
5194   if (bTIFFAllow != 0) {\r
5195 /*    if (dheight == 0) { */  /* need aspect ratio from TIFF file */\r
5196     if (dheight == 0 || dwidth == 0) {\r
5197       if (traceflag) {\r
5198         sprintf(logline, " Prescanning %s\n", filename);\r
5199         showline(logline, 0);\r
5200       }\r
5201       flag = readimagefile(output, filename, dwidth, dheight, nifd, 1);\r
5202 /*      if (flag < 0) return; */  /* was unable to find file 96/Dec/27 */\r
5203 /*      if (traceflag) printf("FLAG %d\n", flag); */\r
5204       if (flag == 0) {      /* 96/Dec/27 */\r
5205         if (dwidth == 0 && dheight == 0) {      /* fix 95/Oct/12 */\r
5206 /* convert information in image to scaled points */\r
5207 /*          dwidth = (ImageWidth * xresden / xresnum) << 16; */\r
5208 /*          dheight = (ImageLength * yresden / yresnum) << 16; */\r
5209 /*          if (traceflag)\r
5210             printf(" ImageWidth %ld (%lu / %lu) ImageLength %ld (%lu / %lu)\n",\r
5211             ImageWidth, xresnum, xresden, ImageLength, yresnum, yresden); */\r
5212           if (xresnum == 0 || yresnum == 0) {   /* 96/Apr/4 */\r
5213             sprintf(logline,\r
5214                 " xres %lu / %lu yres %lu / %lu unit %d\n",\r
5215                 xresnum, xresden, yresnum, yresden, ResolutionUnit);\r
5216             showline(logline, 1);\r
5217 /*            xresnum = yresnum = 72; */ /* 96/Apr/3 */\r
5218             xresnum = yresnum = nDefaultTIFFDPI;\r
5219 /*            return; */          /* 96/Apr/4 */\r
5220           }\r
5221 \r
5222 /*          dwidth = (ImageWidth << 16) / xresnum * xresden; */\r
5223           dwidth = MulRatio(ImageWidth << 16, xresden, xresnum);\r
5224 /*          dheight = (ImageLength << 16) / yresnum * yresden; */\r
5225           dheight = MulRatio(ImageLength << 16, yresden, yresnum);\r
5226 /*          if (traceflag)\r
5227             printf(" dwidth %ld dheight %ld\n", dwidth, dheight); */\r
5228           if (ResolutionUnit == 1) {      /* what to do ? */\r
5229             showline(" resolution == 1", 1);\r
5230           }\r
5231           else if (ResolutionUnit == 2) {   /* 72.27 pt per in */\r
5232             dwidth = dwidth / 100 * 7227;\r
5233             dheight = dheight / 100 * 7227;\r
5234           }\r
5235           else if (ResolutionUnit == 3) {   /* 28.45 pt per cm */\r
5236             dwidth = dwidth / 100 * 2845;\r
5237             dheight = dheight / 100 * 2845;\r
5238           }\r
5239         }\r
5240 /* adjusted order of mul and div to avoid potential overflow 94/Dec/16 */\r
5241 /* or use MulDiv ??? */ /* switched to MulRatio 98/Jul/9 */\r
5242         else if (dheight == 0) {\r
5243           if (ImageWidth != 0) \r
5244 /*            dheight = (ImageLength * dwidth) / ImageWidth; */\r
5245 /*            dheight = (dwidth / ImageWidth) * ImageLength;  */\r
5246             dheight = MulRatio(dwidth, ImageLength, ImageWidth);\r
5247         }\r
5248         else if (dwidth == 0) {\r
5249           if (ImageLength != 0)\r
5250 /*            dwidth = (ImageWidth * dheight) / ImageLength; */\r
5251 /*            dwidth = (dheight / ImageLength) * ImageWidth; */\r
5252             dwidth = MulRatio(dheight, ImageWidth, ImageLength); \r
5253         }\r
5254 /*      added 99/July/2 */\r
5255         if (xscale != 0.0) dwidth = (long) ((double) dwidth * xscale);\r
5256         if (yscale != 0.0) dheight = (long) ((double) dheight * yscale);\r
5257 #ifdef DEBUGTIFF\r
5258         if (traceflag) {\r
5259           sprintf(logline, " dwidth %ld dheight %ld", dwidth, dheight);\r
5260           showline(logline, 0);\r
5261         }\r
5262 #endif\r
5263     }\r
5264 /*    xll = mapx(dvi_h); yll = mapy(dvi_v); */\r
5265 /*    xll = dvi_h; yll = dvi_v; */\r
5266 /*    xur = mapx(dvi_h + dwidth); yur = mapy(dvi_v - dheight); */\r
5267 /*    xur = dvi_h + dwidth; yur = dvi_v - dheight; */\r
5268     }     /* 96/Dec/27 */\r
5269 /*    if (nifd >= 0) readimagefile(output, filename, dwidth, dheight, nifd, 1); */\r
5270     if (nifd >= 0)\r
5271       flag = readimagefile(output, filename, dwidth, dheight, nifd, 0);\r
5272     \r
5273   }\r
5274   return 0;\r
5275 }\r
5276 \r
5277 /* have the \special in line at this point - entry point from dvispeci.c */\r
5278 \r
5279 /*  else if (strcmp(line, "textcolor") == 0 ||\r
5280     strcmp(line, "rulecolor") == 0 ||\r
5281     strcmp(line, "figurecolor") == 0 ||\r
5282     strcmp(line, "reversevideo") == 0 ||\r
5283     strcmp(line, "button") == 0 ||\r
5284     strcmp(line, "mark") == 0 ||      \r
5285     strcmp(line, "viewrule") == 0 ||\r
5286     strcmp(line, "viewtext") == 0 ||\r
5287     strcmp(line, "insertimage") == 0) { */\r
5288 \r
5289 /* made common to save string space */\r
5290 \r
5291 void dontunderline (void)\r
5292 {\r
5293 //  showline(" ERROR: don't understand ", 1);\r
5294 //  showline(line, 1);\r
5295   sprintf(logline, " ERROR: don't understand: %s", line);\r
5296   showline(logline, 1);\r
5297 }\r
5298 \r
5299 /* name => buffer convert \ to / and change : to / and so on */\r
5300 \r
5301 void platformindependent (char *buffer, char *name) { /* 96/Mar/3 */\r
5302   char *s;\r
5303   strcpy(buffer, name);\r
5304 /*  avoid trouble with file names that contain spaces - truncate 'em! */\r
5305   if ((s = strchr(buffer, ' ')) != NULL) *s = '\0';\r
5306 /*  if ((s = strchr(buffer, ':')) != NULL) { */\r
5307   if ((s = strchr(buffer, ':')) != NULL &&\r
5308     *(s+1) != '\\' && *(s+1) != '/') {      /* 98/Jun/30 */\r
5309     *s = '/';\r
5310     memmove(buffer+1, buffer, strlen(buffer)+1);\r
5311     *buffer = '/';\r
5312   }\r
5313 /*  which is not really much use unless it is a relative file name ... */\r
5314 /*  while ((s = strchr(buffer, '\\')) != NULL) *s = '/'; */\r
5315   s = buffer;           /* now convert \ to / */\r
5316   while ((s = strchr(s, '\\')) != NULL) *s = '/';\r
5317 }\r
5318 \r
5319 /* clean up hyper-text mark name for PostScript Distiller 95/Feb/25 */\r
5320 \r
5321 /* Remove characters from name to make it valid PS name */\r
5322 /* Valid name may not contain white space or delimiters (pgs 30, 27 PS bible) */\r
5323 /* White space is null (0), tab (9), linefeed (10), formfeed (12), */\r
5324 /* return (13), and space (32) */\r
5325 /* Delimiters are () <> [] {} / % */\r
5326 /* Note: some question about allowing \ here, since in a *string* */\r
5327 /* backslash is used as an escape - so if name converted to string ... */\r
5328 \r
5329 /* Implementation limit on name length is 127 (Appendix B.1 in PS reference) */\r
5330 /* Implementation limit on file name length is 100 */\r
5331 \r
5332 /* #define MAXPSNAME 32 */  /* old limit */\r
5333 #define MAXPSNAME 63  /* 98/Jul/16 */\r
5334 \r
5335 /* This removes punctuation also . , : ; ! ? etc  NOT ANYMORE! 97/Feb/23 */\r
5336 /* Removes white space and delimiters - limits to MAXPSNAME char */\r
5337 /* NOTE: must use cleanupname *both* in mark: and button: */\r
5338 /* and URL calls with named destinations 97/Feb/23 ! */\r
5339 \r
5340 /* what if the string is quoted ? */ /* \b is not strictly forbidden */\r
5341 \r
5342 /* what about #?  not allowed in PDF name. but we want to pass it here? */\r
5343 \r
5344 /* char *badcharinname=" \t\n\r\f()<>[]{}/%"; */\r
5345 char *badcharinname=" \b\t\n\f\r()<>[]{}/%";\r
5346 \r
5347 void cleanupname (char *name)\r
5348 {\r
5349   char *s;\r
5350 #ifdef DEBUGCLEANUP\r
5351   if (traceflag)\r
5352   {\r
5353     sprintf(logline, " CLEANUPNAME: %s", name);     /* debugging */\r
5354     showline(logline, 0);\r
5355   }\r
5356 #endif\r
5357   if (*name == '\0')\r
5358   {\r
5359     showline(" ERROR: empty mark or button", 1);\r
5360   }\r
5361   s = name;\r
5362   while ((s = strpbrk(s, badcharinname)) != NULL)\r
5363     strcpy(s, s+1);\r
5364   if (strlen(name) > MAXPSNAME) *(name+MAXPSNAME) = '\0'; /* 96/Aug/12 */\r
5365 #ifdef DEBUGCLEANUP\r
5366   if (traceflag)\r
5367   {\r
5368     sprintf(logline, " CLEANEXIT: %s", name);   /* debugging */\r
5369     showline(logline, 0);\r
5370   }\r
5371 #endif\r
5372   if (*name == '\0') showline(" ERROR: empty mark or button", 1);\r
5373 }\r
5374 \r
5375 /* support for old textcolor / rulecolor specials */\r
5376 \r
5377 int oldcolor (FILE *output, FILE  *input)\r
5378 {\r
5379   char *s;\r
5380   int n;\r
5381 /*  old text color support */\r
5382   if (strcmp(line, "textcolor") == 0) {\r
5383     (void) scanspecial (input, line, MAXLINE);\r
5384     if (traceflag) {\r
5385       sprintf(logline, " %s ", line);\r
5386       showline(logline, 0);\r
5387     }\r
5388     if (!bKeepBlack) {\r
5389       if (strstr(line, "revert") != NULL) {\r
5390         textred = 0.0; textgreen = 0.0; textblue = 0.0;\r
5391 //        fputs("\nblack\n", output);\r
5392         PSputs("\nblack\n", output);\r
5393         bTextColor = 0;\r
5394       }\r
5395       else if (sscanf(line, "%lg %lg %lg",\r
5396             &textred, &textgreen, &textblue) == 3) {\r
5397 /*        see whether floating point or not */\r
5398         if ((s = strchr(line, '.')) == NULL || *(s+1) < '0') {\r
5399           textred = textred / 255.0;\r
5400           textgreen = textgreen / 255.0;\r
5401           textblue = textblue / 255.0;\r
5402         }\r
5403         if (textred == 0.0 && textgreen == 0.0 && textblue == 0.0) {\r
5404 //          fputs("\nblack\n", output);\r
5405           PSputs("\nblack\n", output);\r
5406           bTextColor = 0;\r
5407         }   /* treat 0 0 0 same as revert ? */\r
5408         else {\r
5409           sprintf(logline, "\n%lg %lg %lg rgb\n",\r
5410               textred, textgreen, textblue);\r
5411           PSputs(logline, output);\r
5412           bTextColor = 1;\r
5413         }\r
5414       }\r
5415       else {\r
5416         dontunderline();\r
5417         return 1;\r
5418       }\r
5419 //      fprintf(output, "\n%lg %lg %lg setrgbcolor\n",\r
5420     }\r
5421     return 1;\r
5422   }\r
5423   /*  old rule color support */\r
5424   else if (strcmp(line, "rulecolor") == 0) {\r
5425     (void) scanspecial (input, line, MAXLINE);\r
5426 #ifdef DEBUGTIFF\r
5427     if (traceflag) {\r
5428       sprintf(logline, " %s ", line);\r
5429       showline(logline, 0);\r
5430     }\r
5431 #endif\r
5432     if (!bKeepBlack) {\r
5433       if (strstr(line, "revert") != NULL) {\r
5434         rulered = 0.0; rulegreen = 0.0; ruleblue = 0.0;\r
5435         bRuleColor = 0;\r
5436       }\r
5437       else if (sscanf(line, "%lg %lg %lg", &rulered, &rulegreen, &ruleblue) == 3) {\r
5438 /* see whether floating point or not */\r
5439         if ((s = strchr(line, '.')) == NULL || *(s+1) < '0') {\r
5440           rulered = rulered / 255.0;\r
5441           rulegreen = rulegreen / 255.0;\r
5442           ruleblue = ruleblue / 255.0;\r
5443         }\r
5444         if (rulered == 0.0 && rulegreen == 0.0 && ruleblue == 0.0)\r
5445           bRuleColor = 0;\r
5446         else bRuleColor = 1; \r
5447       }\r
5448       else {\r
5449         dontunderline();\r
5450         return 1;\r
5451       }\r
5452     }\r
5453     return 1;\r
5454   }\r
5455 /*  old figurecolor support */\r
5456   else if (strcmp(line, "figurecolor") == 0) {\r
5457     (void) scanspecial (input, line, MAXLINE);\r
5458 #ifdef DEBUGTIFF\r
5459     if (traceflag) {\r
5460       sprintf(logline, " %s ", line);\r
5461       showline(logline, 0);\r
5462     }\r
5463 #endif\r
5464     if (!bKeepBlack) {\r
5465       if (strstr(line, "revert") != NULL) {\r
5466         figurered = 0.0; figuregreen = 0.0; figureblue = 0.0;\r
5467         backred = 1.0; backgreen = 1.0; backblue = 1.0;\r
5468         bFigureColor = 0;\r
5469       }\r
5470       else if ((n = sscanf(line, "%lg %lg %lg %lg %lg %lg",\r
5471                &figurered, &figuregreen, &figureblue,\r
5472                &backred, &backgreen, &backblue)) >= 3) {\r
5473         bFigureColor = 1;\r
5474 /* see whether floating point or not */\r
5475         if ((s = strchr(line, '.')) == NULL || *(s+1) < '0') {\r
5476           figurered = figurered / 255.0;\r
5477           figuregreen = figuregreen / 255.0;\r
5478           figureblue = figureblue / 255.0;\r
5479           if (n == 6) {\r
5480             backred = backred / 255.0;\r
5481             backgreen = backgreen / 255.0;\r
5482             backblue = backblue / 255.0;\r
5483           }\r
5484         }\r
5485         if (n < 6) {      /* default background color */\r
5486           backred = 1.0; backgreen = 1.0; backblue = 1.0;\r
5487         }\r
5488 \r
5489         if (figurered == 0.0 && figuregreen == 0.0 && figureblue == 0.0 \r
5490           && backred == 1.0 && backgreen == 1.0 && backblue == 1.0) \r
5491           bFigureColor = 0; \r
5492         else bFigureColor = 1;\r
5493       }       /* end of three or more numbers found case */\r
5494       else {\r
5495         dontunderline();\r
5496         return 1;\r
5497       }\r
5498     }\r
5499     return 1;\r
5500   }\r
5501 /*  old reverse video support */\r
5502   else if (strcmp(line, "reversevideo") == 0) {\r
5503     (void) scanspecial (input, line, MAXLINE);\r
5504 #ifdef DEBUGTIFF\r
5505     if (traceflag) {\r
5506       sprintf(logline, " %s ", line);\r
5507       showline(logline, 0);\r
5508     }\r
5509 #endif\r
5510     if (!bKeepBlack) {\r
5511       if (strstr(line, "on") != NULL) bReverseVideo = 1;\r
5512       else if (strstr(line, "off") != NULL) bReverseVideo = 0;\r
5513       else if (strstr(line, "toggle") != NULL)\r
5514       bReverseVideo = ~bReverseVideo;\r
5515 /*        ignore reversevideo for the moment ??? */\r
5516       if (bReverseVideo) {\r
5517 //        fputs("{1 exch sub} settransfer\n", output);\r
5518         PSputs("{1 exch sub} settransfer\n", output);\r
5519       }\r
5520       else {\r
5521 //        fputs("{} settransfer\n", output);\r
5522         PSputs("{} settransfer\n", output);\r
5523       }\r
5524     }\r
5525     return 1;\r
5526   }\r
5527   else dontunderline();\r
5528   return 0;\r
5529 }\r
5530 \r
5531 /* new to allow quoted file names with spaces 98/Jul/9 */\r
5532 \r
5533 char *scaninsert(char *line, char *filename)\r
5534 {\r
5535   char *s = line;\r
5536   char *t = filename;\r
5537 \r
5538   *filename = '\0';\r
5539 \r
5540   while (*s <= ' ' && *s != '\0') s++;  /* step over white space */\r
5541 \r
5542   if (*s == '\0') return 0;\r
5543 \r
5544   if (*s == '\"') {     /* is it quoted file name ? */\r
5545     s++;          /* step over initial " */\r
5546     while (*s != '\"' && *s != '\0') *t++ = *s++;\r
5547     if (*s != '\0') s++;          /* step over final " */\r
5548   }\r
5549   else {            /* normal file name */\r
5550     while (*s > ' ' && *s != '\0') *t++ = *s++;\r
5551   }\r
5552   *t = '\0';\r
5553   if (*s <= ' ' && *s != '\0') s++; /* step over white space after name */\r
5554 /*  special hack to convert ## to # */\r
5555   if ((t = strstr(filename, "##")) != NULL) strcpy(t, t+1);\r
5556   if (traceflag) {\r
5557     sprintf(logline, "line: %s filename: %s\n",\r
5558               line, filename);\r
5559     showline(logline, 0);\r
5560   }\r
5561   return s;\r
5562 }\r
5563 \r
5564 /* returns zero if *not* one of our DVIWindo \specials */\r
5565 \r
5566 int newspecials (FILE *output, FILE *input)\r
5567 {\r
5568   int nifd=1;\r
5569   long dheight, dwidth;\r
5570   char filename[FILENAME_MAX];\r
5571   char *sname=NULL;\r
5572   char *sfile=NULL;\r
5573   char *slaunch=NULL;\r
5574   char *sparams=NULL;\r
5575   char *spage=NULL;           /* 96/May/4 */\r
5576   char *s, *t;\r
5577   int npage=0, noffset=0;         /* 96/May/4 */\r
5578   int n, np=0;\r
5579   int URLflag=0;              /* 97/Jan/7 */\r
5580   double xscale, yscale;\r
5581 \r
5582 #ifdef DEBUGTIFF\r
5583   if (traceflag)\r
5584   {\r
5585     sprintf(logline, " %s:", line);\r
5586     showline(logline, 0);\r
5587   }\r
5588 #endif\r
5589 \r
5590 /*  insert TIFF or BMP image */\r
5591   if (strcmp(line, "insertimage") == 0)\r
5592   {\r
5593 /*    (void) scanspecial (input, line, MAXLINE); */\r
5594     (void) scanspecialraw (input, line, MAXLINE);\r
5595 #ifdef DEBUGTIFF\r
5596     if (traceflag)\r
5597     {\r
5598       sprintf(logline, " %s ", line);\r
5599       showline(logline, 0);\r
5600     }\r
5601 #endif\r
5602     nifd = 1;         /* n-th (sub-)image in TIFF file */\r
5603     dwidth = dheight = 0;   /* NEW - use all info from file */\r
5604     xscale = yscale = 0.0;    /* 99/July/2 */\r
5605 /*    if (sscanf(line, "%s %ld %ld %d", filename, &dwidth, &dheight, &nifd) */\r
5606     s = scaninsert(line, filename);\r
5607     if ((t = strstr(s, "scaled")) == NULL)\r
5608     {\r
5609       sscanf(s, "%ld %ld %d", &dwidth, &dheight, &nifd);  /* normal */\r
5610     }\r
5611     else {  /* new case 99/July/2 */\r
5612       sscanf(t+7, "%lg %lg", &xscale, &yscale);\r
5613       if (xscale > 33.33) xscale = xscale / 1000.0;\r
5614       if (yscale > 33.33) yscale = yscale / 1000.0;\r
5615       if (xscale != 0.0 && yscale == 0.0) yscale = xscale;\r
5616       if (xscale == 0.0) xscale = 1.0;\r
5617       if (yscale == 0.0) yscale = 1.0;\r
5618     }\r
5619     if (*filename != '\0') {  /* need at least file name */\r
5620 //      clock_t sclock, eclock;\r
5621 //      sclock = clock();\r
5622       hptagflag = 0;\r
5623       showtiffhere(output, filename, dwidth, dheight, xscale, yscale, nifd);\r
5624 //      eclock = clock();\r
5625 //      sprintf(logline, " TIFF %lg sec\n", (double) (eclock - sclock) / CLOCKS_PER_SEC);\r
5626 //      showline(logline, 0); // debugging only\r
5627     }\r
5628     else dontunderline();\r
5629     return 1;\r
5630   }\r
5631 \r
5632 /*  old textcolor, rulecolor \specials{...}s */\r
5633   else if (strstr(line, "color") != NULL ||\r
5634        strstr(line, "video") != NULL)\r
5635     return oldcolor(output, input);\r
5636 \r
5637 /*  mark: name --- mark: "<File Open>" */ /* turn into named destination */\r
5638   else if (strcmp(line, "mark") == 0) {\r
5639     if (bPDFmarks == 0) {\r
5640       flushspecial(input);\r
5641       return 1;   /* we recognize it, but ignore it */\r
5642     }\r
5643 /*    (void) scanspecial (input, line, MAXLINE);  */\r
5644     (void) scanspecialraw (input, line, MAXLINE); /* fix 97/Nov/11 */\r
5645     if (traceflag) {\r
5646       sprintf(logline, " %s ", line);\r
5647       showline(logline, 0);\r
5648     }\r
5649 /*    deal with <FOO BAR> style --- flush all < and > and ' ' in string */\r
5650     if (usealtGoToR == 0)\r
5651       cleanupname(line);    /* should only contain mark name */\r
5652                   /* and nothing after the mark */\r
5653 //    putc('\n', output);   /* ??? */\r
5654     PSputc('\n', output);   /* ??? */\r
5655     if (*line < ' ') {\r
5656       showline(" ERROR: empty destination %s ", 1);\r
5657       showline(line, 1);\r
5658     }\r
5659 /*    need alternate form of /Dest ? */\r
5660 /*    fprintf(stdout, "[ /Dest /%s\n", line); */\r
5661     sprintf(logline, "[ /Dest /%s\n", line);\r
5662     PSputs(logline, output);\r
5663 /*    need to find current position in *default* user space */\r
5664 /*    move up 20 point, ignore x component --- i.e. keep the old x (null) */\r
5665 /*    keep original zoom (null) */ /* 20 point is arbitrary */\r
5666 //    fputs(\r
5667     PSputs(\r
5668 "  /View [ /XYZ gsave revscl currentpoint grestore 20 add exch pop null exch null]\n",\r
5669         output);  /* revscl ? */\r
5670 //    fputs("/DEST pdfmark\n", output);\r
5671     PSputs("/DEST pdfmark\n", output);\r
5672     return 1;\r
5673   }\r
5674 \r
5675 /*  button: <width> <height> name --- button: 1138360 433848 "<DVIfile>" */\r
5676 /*  we are ignoring for the moment file: ... and launch: ... */\r
5677   else if (strcmp(line, "button") == 0) {\r
5678     if (bPDFmarks == 0) {\r
5679       flushspecial(input);\r
5680       return 1;   /* we recognize it, but ignore it */\r
5681     }\r
5682 /*    (void) scanspecial (input, line, MAXLINE); */\r
5683     (void) scanspecialraw (input, line, MAXLINE); \r
5684     if (traceflag) {\r
5685       sprintf(logline, " %s ", line);\r
5686       showline(logline, 0);\r
5687     }\r
5688     if (sscanf(line, "%ld %ld%n", &dwidth, &dheight, &n) < 2) {\r
5689       showline(" ERROR: button ", 1); /* error output */\r
5690       showline(line, 1);\r
5691       flushspecial(input);\r
5692       return 1;   /* it does not have required width and height ! */\r
5693     }\r
5694 /*    if (strstr(line, "launch:") != NULL) {\r
5695       flushspecial(input);\r
5696       return 1;\r
5697     } */\r
5698     sname = line + n;         /* now after width and height */\r
5699     while (*sname == ' ') sname++;    /* step over white space */\r
5700 /*    catch case where no mark given, only file: , launch: or page: ... */\r
5701 /*    if ((strncmp(sname, "file:", 5) == 0)) sname = NULL; */\r
5702 /*    if ((strncmp(sname, "launch:", 7) == 0)) sname = NULL; */\r
5703 /*    if (strncmp(sname, "file:", 5) == 0 || */ /* avoid file://... */\r
5704     if ((strncmp(sname, "file:", 5) == 0 && *(sname+5) != '/') ||\r
5705       strncmp(sname, "launch:", 7) == 0 ||\r
5706       strncmp(sname, "execute:", 8) == 0 ||\r
5707       strncmp(sname, "page:", 5) == 0) sname = NULL;\r
5708 /*    check whether page number is given 96/May/12 */\r
5709     if ((spage = strstr(line, "page:")) != NULL) {\r
5710       noffset = 0;\r
5711       npage = 0;\r
5712       if (sscanf(spage+5, "%d+%d", &npage, &noffset) < 2) {\r
5713         if (sscanf(spage+5, "%d", &npage) < 1) {\r
5714           sprintf(logline, " ERROR: %s ", spage); /* error output */\r
5715           showline(logline, 1);\r
5716         }\r
5717       }\r
5718 /*      if (traceflag)  printf("npage %d noffset %d spage-line %d\n",\r
5719            npage, noffset, spage-line); */\r
5720     }\r
5721 /*    check whether file: given */\r
5722 /*    if ((sfile = strstr(line, "file:")) != NULL) { */ /* avoid file:// */\r
5723     if ((sfile = strstr(line, "file:")) != NULL && *(sfile+5) != '/') {\r
5724       sfile = sfile+5;\r
5725       while (*sfile == ' ') sfile++;\r
5726 /*      if (traceflag) printf("sfile-line %d\n", sfile-line); */\r
5727       if (sscanf(sfile, "-p=%d%n", &np, &n) == 1) { /* 98/Dec/8 */\r
5728         spage = sfile+3;\r
5729 /*        what if npage has already been set ? */\r
5730         npage = np;\r
5731         sfile += n;\r
5732         while (*sfile == ' ') sfile++;  \r
5733 /*        if (traceflag)\r
5734           printf("npage %d sfile-line %d\n", npage, sfile-line); */\r
5735       }\r
5736     }\r
5737 /*    check whether launch: given */\r
5738     if ((slaunch = strstr(line, "launch:")) != NULL) {\r
5739       slaunch = slaunch+7;\r
5740       while (*slaunch == ' ') slaunch++;\r
5741     }\r
5742     if (sfile != NULL) slaunch = NULL;    /* can do only one ??? */\r
5743 //    putc('\n', output);   /* ??? */\r
5744     PSputc('\n', output);   /* ??? */\r
5745 //    fprintf(output,\r
5746     sprintf(logline,\r
5747         "[ /Rect [currentpoint 2 copy exch %ld add exch %ld sub]\n",\r
5748         dwidth, dheight);\r
5749     PSputs(logline, output);\r
5750 /*    Note: default is /Action /GoTo */\r
5751     if (sname != NULL) {    /* was a named destination given ? */\r
5752       if ((s = strchr(sname, ',')) != NULL) *s = '\0';\r
5753 /*      should we make a new case for this http: action: PDF: ? */\r
5754 /*      special case `named destination' http:// ... */\r
5755 /*      This form of URL link supported under Acrobat 2.1 and later */\r
5756 /*      use http://www.adobe.com/test.pdf#name for named destination */\r
5757       if (strncmp(sname, "http:", 5) == 0 ||\r
5758         strncmp(sname, "ftp:", 4) == 0 ||\r
5759         strncmp(sname, "news:", 5) == 0 ||\r
5760         strncmp(sname, "mailto:", 7) == 0 ||\r
5761 /*        strncmp(sname, "file://localhost", 16) == 0 || */\r
5762 /*        strncmp(sname, "file:///|c/...", 16) == 0 || */\r
5763         strncmp(sname, "file://", 7) == 0 ||\r
5764         strncmp(sname, "gopher:", 7) == 0\r
5765          ) {  /* 1996/July/4 */\r
5766 /*  Now deal with *relative* URL given as http: pdf_from.pdf e.g. 97/May/3 */\r
5767 /*  Assumes base URL set via \special{PDF: base http://www.YandY.com}% */\r
5768         if ((s = strchr(sname, ':')) != NULL && *(s+1) == ' ') {\r
5769           sname = s+1;\r
5770           while (*sname == ' ') sname++;\r
5771         }\r
5772 /*        TeX changes # => ## so change back ## => # 97/Jan/8 */\r
5773         if ((s = strstr(sname, "##")) != NULL) strcpy(s, s+1);\r
5774         if ((s = strchr(sname, '#')) != NULL) { /* 97/Feb/23 */\r
5775           if (usealtGoToR == 0)\r
5776             cleanupname(s+1); /* clean up named destination */\r
5777         }\r
5778         sprintf(logline, "  /Action << /Subtype /URI /URI (%s) >>\n",\r
5779             sname);\r
5780         PSputs(logline, output);\r
5781       }\r
5782       else {          /* not a URL type of thing */\r
5783 /*  terminate the mark name - in case file: after - 97/Apr/23 */\r
5784 /*  but avoid truncating a destination that happens to include a : */\r
5785         if ((s = strchr(sname, ':')) != NULL) {\r
5786           while (s > sname && *s > ' ') s--;\r
5787           if (s > sname)      /* fix 97/Nov/11 */\r
5788             *s = '\0';      /* terminate the mark name */\r
5789         }\r
5790         if (usealtGoToR == 0)\r
5791           cleanupname(sname);   /* clean up the destination */\r
5792         if (*sname < ' ') {\r
5793           sprintf(logline, " ERROR: empty destination %s ", sname);\r
5794           showline(logline, 1);\r
5795         }\r
5796 /*        fprintf(stdout, "  /Dest /%s\n", sname); */\r
5797         if (! usealtGoToR) {\r
5798           sprintf(logline, "  /Dest /%s\n", sname);\r
5799           PSputs(logline, output);\r
5800         }\r
5801       }\r
5802     } /* end of named destination given */\r
5803 /*    97/Jan/7 Acrobat 3.0 wants page number in GoToR ? 97/Jan/7 */\r
5804     if (sfile != NULL && spage == NULL) {\r
5805       npage = 1; noffset = 0; /* go to page 1 as default */\r
5806       spage = sfile;      /* pretend there was a number */\r
5807     }\r
5808     if (spage != NULL) {    /* was a page number given ? 96/May/12 */\r
5809       if (noffset != 0) npage += noffset;\r
5810 /*      fprintf(output, "  /Page %d\n", npage + nPDFoffset); */\r
5811       sprintf(logline, "  /Page %d\n", npage);\r
5812       PSputs(logline, output);\r
5813 //      fputs("  /View [ /XYZ -4 PageHeight 4 add null]\n", output);\r
5814       PSputs("  /View [ /XYZ -4 PageHeight 4 add null]\n", output);\r
5815     }\r
5816 /*    case where a file or URL is specified */\r
5817     if (sfile != NULL) {\r
5818       URLflag = 0;\r
5819 /*      check whether the `file' specified is a URL */\r
5820       if (strncmp(sfile, "http:", 5) == 0 ||\r
5821         strncmp(sfile, "ftp:", 4) == 0 ||\r
5822         strncmp(sfile, "news:", 5) == 0 ||\r
5823         strncmp(sfile, "mailto:", 7) == 0 ||\r
5824 /*        strncmp(sfile, "file://localhost", 16) == 0 || */\r
5825 /*        strncmp(sfile, "file:///|c/...", 16) == 0 || */\r
5826         strncmp(sfile, "file://", 7) == 0 ||\r
5827         strncmp(sfile, "gopher:", 7) == 0\r
5828          ) URLflag=1; /* treat URL style things different 97/Jan/7 */\r
5829       if (usealtGoToR == 0) {     /* for now */\r
5830 //        fputs("  /Action /GoToR\n", output);\r
5831         PSputs("  /Action /GoToR\n", output);\r
5832         if ((s = strchr(sfile, ',')) != NULL) *s = '\0';  /* 96/May/4 */\r
5833         if (URLflag == 0) {   /* don't mess with extension if URL ? */ \r
5834 /*          remove extension if any (typically .dvi) use .pdf instead */\r
5835 /*          be  careful about ../foo if there is no extension 97/Jan/7 */\r
5836           if ((s = strrchr(sfile, '.')) != NULL &&\r
5837             ((t = strrchr(sfile, '/')) == NULL || s > t) &&\r
5838             ((t = strrchr(sfile, '\\')) == NULL || s > t))\r
5839             *s = '\0';\r
5840           strcat(sfile, ".pdf");  /* default extension in PS output */\r
5841         } /* end of if URLflag == 0 */\r
5842 /*        massage into Acrobat `platform independent' format */\r
5843         platformindependent (filename, sfile);  /* reuse filename */\r
5844         sprintf(logline, "  /File (%s)\n", filename);\r
5845         PSputs(logline, output);\r
5846 //        fprintf(output, "  /DosFile (%s)\n", sfile); \r
5847         sprintf(logline, "  /DOSFile (%s)\n", sfile); /* 98/Jun/20 */\r
5848         PSputs(logline, output);\r
5849       }\r
5850       else {  /* use alternative format */\r
5851         sprintf(logline, " /Action << /S /GoToR /D (%s) /F (%s) >>/n",\r
5852             sname, sfile);  /* ??? 98/Jun/30 */\r
5853         PSputs(logline, output);\r
5854       }\r
5855     }\r
5856     if (slaunch != NULL) {\r
5857       if ((s = strchr(slaunch, ',')) != NULL) *s = '\0';\r
5858 //      fputs("  /Action /Launch\n", output);\r
5859       PSputs("  /Action /Launch\n", output);\r
5860 /*      massage into Acrobat `platform independent' format */\r
5861       platformindependent (filename, slaunch);\r
5862 /*      do special things for Windows call ... */\r
5863       sprintf(logline, "  /File (%s)\n", filename);\r
5864       PSputs(logline, output);\r
5865       if ((s = strchr(slaunch, ' ')) != NULL) {\r
5866         *s = '\0';\r
5867         sparams = s+1;\r
5868       }\r
5869 /*      Acrobat Reader uses Windows ShellExecute(...) */\r
5870       sprintf(logline, "  /WinFile (%s)\n", slaunch);\r
5871       PSputs(logline, output);\r
5872       if (sparams != NULL) {\r
5873         sprintf(logline, "  /Params (%s)\n", sparams);\r
5874         PSputs(logline, output);\r
5875       }\r
5876 /*      optional key /Dir (current directory) */\r
5877 /*      optional key /Op  (open or print) */\r
5878     }\r
5879 \r
5880 /*    Default border is [0 0 1] - we want it to be invisible instead */\r
5881 //    fputs("  /Border [ 0 0 0]\n", output);\r
5882     PSputs("  /Border [ 0 0 0]\n", output);\r
5883 //    fputs("  /Subtype /Link\n", output);\r
5884     PSputs("  /Subtype /Link\n", output);\r
5885 //    fputs("/ANN pdfmark\n", output);\r
5886     PSputs("/ANN pdfmark\n", output);\r
5887     return 1;\r
5888   }\r
5889   else if (strcmp(line, "viewrule") == 0 || /* 95/Mar/27 */\r
5890        strcmp(line, "viewtext") == 0) { /* 95/Mar/27 */\r
5891      flushspecial(input);\r
5892      return 1;    /* we recognize it, but ignore it */\r
5893   }\r
5894 #ifdef DEBUGTIFF\r
5895   else if (traceflag) showline(line, 1);\r
5896 #endif\r
5897   return 0;       /* not a DVIWindo special */\r
5898 }\r
5899 \r
5900 #endif\r
5901 \r
5902 /* proper support for figurecolor \special / bilevel images 1994/March/14 */\r
5903 \r
5904 /* \special{tiff:/mount/mktpub_d1/users/temp_jobs/59625100nl/procroms.tif\r
5905    lib=control.glb xmag=1 ymag=1 hleft vhigh  bclip=0.000000 lclip=0.000000\r
5906    rclip=0.000000 tclip=0.000000 nostrip */\r
5907 /* New stuff for HPTAG */ /* 95/Oct/12 */\r
5908 \r
5909 int dohptag (FILE *output, FILE *input)\r
5910 {\r
5911 /*  double bclip=0, lclip=0, rclip=0, tclip=0; */\r
5912 /*  int hleft=1, hright=0, vhigh=1, vlow=0; */\r
5913 /*  double xmag=1, ymag=1; */\r
5914 /*  int nostrip=1; */\r
5915   char *s, *t;\r
5916   char filename[FILENAME_MAX];\r
5917 \r
5918   (void) scanspecial (input, line, MAXLINE);\r
5919   if ((s = strchr(line, ' ')) != NULL) *s = '\0';\r
5920   if ((t = strrchr(line, '/')) != NULL) strcpy(filename, t+1);\r
5921   else if (strlen(line) < sizeof(filename)) strcpy(filename, line);\r
5922   else return 0;              /* failure */\r
5923 /*  now analyze the rest of the line starting at s+1 */\r
5924 /*  showtiffhere(output, filename, dwidth, dheight, 0, 0, nifd); */\r
5925   hptagflag = 1;\r
5926   BMPflag = 0;\r
5927   showtiffhere(output, filename, 0, 0, 0, 0, 1);\r
5928   return 1;               /* success */\r
5929 }\r
5930 \r
5931 /* for setting hyper-text buttons we want the *real* underlying PS */\r
5932 /* (not what we would have seen had mag = 1000 */\r
5933 /* hence use revscl, *not* revsclx */\r
5934 \r
5935 /* #pragma optimize ("lge", on) */\r
5936 \r
5937 /* END OF EXPERIMENT */\r
5938 \r
5939 /* int WINAPI MulDiv(int nNumber, int nNumerator, int nDenominator); */\r