xref: /libtiff-4.0.7/tools/tiffdump.c (revision 7f67da5d)
1 /* $Id: tiffdump.c,v 1.25 2011-04-02 20:54:09 bfriesen Exp $ */
2 
3 /*
4  * Copyright (c) 1988-1997 Sam Leffler
5  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that (i) the above copyright notices and this permission notice appear in
10  * all copies of the software and related documentation, and (ii) the names of
11  * Sam Leffler and Silicon Graphics may not be used in any advertising or
12  * publicity relating to the software without the specific, prior written
13  * permission of Sam Leffler and Silicon Graphics.
14  *
15  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24  * OF THIS SOFTWARE.
25  */
26 
27 #include "tif_config.h"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 
37 #ifdef HAVE_FCNTL_H
38 # include <fcntl.h>
39 #endif
40 
41 #ifdef HAVE_SYS_TYPES_H
42 # include <sys/types.h>
43 #endif
44 
45 #ifdef HAVE_IO_H
46 # include <io.h>
47 #endif
48 
49 #ifdef NEED_LIBPORT
50 # include "libport.h"
51 #endif
52 
53 #ifndef HAVE_GETOPT
54 extern int getopt(int, char**, char*);
55 #endif
56 
57 #include "tiffio.h"
58 
59 #ifndef O_BINARY
60 # define O_BINARY	0
61 #endif
62 
63 static union
64 {
65 	TIFFHeaderClassic classic;
66 	TIFFHeaderBig big;
67 	TIFFHeaderCommon common;
68 } hdr;
69 char* appname;
70 char* curfile;
71 int swabflag;
72 int bigendian;
73 int bigtiff;
74 uint32 maxitems = 24;   /* maximum indirect data items to print */
75 
76 const char* bytefmt = "%s%#02x";	/* BYTE */
77 const char* sbytefmt = "%s%d";		/* SBYTE */
78 const char* shortfmt = "%s%u";		/* SHORT */
79 const char* sshortfmt = "%s%d";		/* SSHORT */
80 const char* longfmt = "%s%lu";		/* LONG */
81 const char* slongfmt = "%s%ld";		/* SLONG */
82 const char* ifdfmt = "%s%#04lx";	/* IFD offset */
83 #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
84 const char* long8fmt = "%s%I64u";	/* LONG8 */
85 const char* slong8fmt = "%s%I64d";	/* SLONG8 */
86 const char* ifd8fmt = "%s%#08I64x";	/* IFD offset8*/
87 #else
88 const char* long8fmt = "%s%llu";	/* LONG8 */
89 const char* slong8fmt = "%s%lld";	/* SLONG8 */
90 const char* ifd8fmt = "%s%#08llx";	/* IFD offset8*/
91 #endif
92 const char* rationalfmt = "%s%g";	/* RATIONAL */
93 const char* srationalfmt = "%s%g";	/* SRATIONAL */
94 const char* floatfmt = "%s%g";		/* FLOAT */
95 const char* doublefmt = "%s%g";		/* DOUBLE */
96 
97 static void dump(int, uint64);
98 extern int optind;
99 extern char* optarg;
100 
101 void
102 usage()
103 {
104 	fprintf(stderr, "usage: %s [-h] [-o offset] [-m maxitems] file.tif ...\n", appname);
105 	exit(-1);
106 }
107 
108 int
109 main(int argc, char* argv[])
110 {
111 	int one = 1, fd;
112 	int multiplefiles = (argc > 1);
113 	int c;
114 	uint64 diroff = 0;
115 	bigendian = (*(char *)&one == 0);
116 
117 	appname = argv[0];
118 	while ((c = getopt(argc, argv, "m:o:h")) != -1) {
119 		switch (c) {
120 		case 'h':			/* print values in hex */
121 			shortfmt = "%s%#x";
122 			sshortfmt = "%s%#x";
123 			longfmt = "%s%#lx";
124 			slongfmt = "%s%#lx";
125 			break;
126 		case 'o':
127 			diroff = (uint64) strtoul(optarg, NULL, 0);
128 			break;
129 		case 'm':
130 			maxitems = strtoul(optarg, NULL, 0);
131 			break;
132 		default:
133 			usage();
134 		}
135 	}
136 	if (optind >= argc)
137 		usage();
138 	for (; optind < argc; optind++) {
139 		fd = open(argv[optind], O_RDONLY|O_BINARY, 0);
140 		if (fd < 0) {
141 			perror(argv[0]);
142 			return (-1);
143 		}
144 		if (multiplefiles)
145 			printf("%s:\n", argv[optind]);
146 		curfile = argv[optind];
147 		swabflag = 0;
148 		bigtiff = 0;
149 		dump(fd, diroff);
150 		close(fd);
151 	}
152 	return (0);
153 }
154 
155 #define ord(e) ((int)e)
156 
157 static uint64 ReadDirectory(int, unsigned, uint64);
158 static void ReadError(char*);
159 static void Error(const char*, ...);
160 static void Fatal(const char*, ...);
161 
162 static void
163 dump(int fd, uint64 diroff)
164 {
165 	unsigned i;
166 
167 	lseek(fd, (off_t) 0, 0);
168 	if (read(fd, (char*) &hdr, sizeof (TIFFHeaderCommon)) != sizeof (TIFFHeaderCommon))
169 		ReadError("TIFF header");
170 	if (hdr.common.tiff_magic != TIFF_BIGENDIAN
171 	    && hdr.common.tiff_magic != TIFF_LITTLEENDIAN &&
172 #if HOST_BIGENDIAN
173 	    /* MDI is sensitive to the host byte order, unlike TIFF */
174 	    MDI_BIGENDIAN != hdr.common.tiff_magic
175 #else
176 	    MDI_LITTLEENDIAN != hdr.common.tiff_magic
177 #endif
178 	   ) {
179 		Fatal("Not a TIFF or MDI file, bad magic number %u (%#x)",
180 		    hdr.common.tiff_magic, hdr.common.tiff_magic);
181 	}
182 	if (hdr.common.tiff_magic == TIFF_BIGENDIAN
183 	    || hdr.common.tiff_magic == MDI_BIGENDIAN)
184 		swabflag = !bigendian;
185 	else
186 		swabflag = bigendian;
187 	if (swabflag)
188 		TIFFSwabShort(&hdr.common.tiff_version);
189 	if (hdr.common.tiff_version==42)
190 	{
191 		if (read(fd, (char*) &hdr.classic.tiff_diroff, 4) != 4)
192 			ReadError("TIFF header");
193 		if (swabflag)
194 			TIFFSwabLong(&hdr.classic.tiff_diroff);
195 		printf("Magic: %#x <%s-endian> Version: %#x <%s>\n",
196 		    hdr.classic.tiff_magic,
197 		    hdr.classic.tiff_magic == TIFF_BIGENDIAN ? "big" : "little",
198 		    42,"ClassicTIFF");
199 		if (diroff == 0)
200 			diroff = hdr.classic.tiff_diroff;
201 	}
202 	else if (hdr.common.tiff_version==43)
203 	{
204 		if (read(fd, (char*) &hdr.big.tiff_offsetsize, 12) != 12)
205 			ReadError("TIFF header");
206 		if (swabflag)
207 		{
208 			TIFFSwabShort(&hdr.big.tiff_offsetsize);
209 			TIFFSwabShort(&hdr.big.tiff_unused);
210 			TIFFSwabLong8(&hdr.big.tiff_diroff);
211 		}
212 		printf("Magic: %#x <%s-endian> Version: %#x <%s>\n",
213 		    hdr.big.tiff_magic,
214 		    hdr.big.tiff_magic == TIFF_BIGENDIAN ? "big" : "little",
215 		    43,"BigTIFF");
216 		printf("OffsetSize: %#x Unused: %#x\n",
217 		    hdr.big.tiff_offsetsize,hdr.big.tiff_unused);
218 		if (diroff == 0)
219 			diroff = hdr.big.tiff_diroff;
220 		bigtiff = 1;
221 	}
222 	else
223 		Fatal("Not a TIFF file, bad version number %u (%#x)",
224 		    hdr.common.tiff_version, hdr.common.tiff_version);
225 	for (i = 0; diroff != 0; i++) {
226 		if (i > 0)
227 			putchar('\n');
228 		diroff = ReadDirectory(fd, i, diroff);
229 	}
230 }
231 
232 static const int datawidth[] = {
233 	0, /* 00 = undefined */
234 	1, /* 01 = TIFF_BYTE */
235 	1, /* 02 = TIFF_ASCII */
236 	2, /* 03 = TIFF_SHORT */
237 	4, /* 04 = TIFF_LONG */
238 	8, /* 05 = TIFF_RATIONAL */
239 	1, /* 06 = TIFF_SBYTE */
240 	1, /* 07 = TIFF_UNDEFINED */
241 	2, /* 08 = TIFF_SSHORT */
242 	4, /* 09 = TIFF_SLONG */
243 	8, /* 10 = TIFF_SRATIONAL */
244 	4, /* 11 = TIFF_FLOAT */
245 	8, /* 12 = TIFF_DOUBLE */
246 	4, /* 13 = TIFF_IFD */
247 	0, /* 14 = undefined */
248 	0, /* 15 = undefined */
249 	8, /* 16 = TIFF_LONG8 */
250 	8, /* 17 = TIFF_SLONG8 */
251 	8, /* 18 = TIFF_IFD8 */
252 };
253 #define NWIDTHS (sizeof (datawidth) / sizeof (datawidth[0]))
254 static void PrintTag(FILE*, uint16);
255 static void PrintType(FILE*, uint16);
256 static void PrintData(FILE*, uint16, uint32, unsigned char*);
257 
258 /*
259  * Read the next TIFF directory from a file
260  * and convert it to the internal format.
261  * We read directories sequentially.
262  */
263 static uint64
264 ReadDirectory(int fd, unsigned int ix, uint64 off)
265 {
266 	uint16 dircount;
267 	uint32 direntrysize;
268 	void* dirmem = NULL;
269 	uint64 nextdiroff;
270 	uint32 n;
271 	uint8* dp;
272 
273 	if (off == 0)			/* no more directories */
274 		goto done;
275 #if defined(__WIN32__) && defined(_MSC_VER)
276 	if (_lseeki64(fd, (__int64)off, SEEK_SET) != (__int64)off) {
277 #else
278 	if (lseek(fd, (off_t)off, SEEK_SET) != (off_t)off) {
279 #endif
280 		Fatal("Seek error accessing TIFF directory");
281 		goto done;
282 	}
283 	if (!bigtiff) {
284 		if (read(fd, (char*) &dircount, sizeof (uint16)) != sizeof (uint16)) {
285 			ReadError("directory count");
286 			goto done;
287 		}
288 		if (swabflag)
289 			TIFFSwabShort(&dircount);
290 		direntrysize = 12;
291 	} else {
292 		uint64 dircount64;
293 		if (read(fd, (char*) &dircount64, sizeof (uint64)) != sizeof (uint64)) {
294 			ReadError("directory count");
295 			goto done;
296 		}
297 		if (swabflag)
298 			TIFFSwabLong8(&dircount64);
299 		if (dircount64>0xFFFF) {
300 			Error("Sanity check on directory count failed");
301 			goto done;
302 		}
303 		dircount = (uint16)dircount64;
304 		direntrysize = 20;
305 	}
306 	dirmem = _TIFFmalloc(dircount * direntrysize);
307 	if (dirmem == NULL) {
308 		Fatal("No space for TIFF directory");
309 		goto done;
310 	}
311 	n = read(fd, (char*) dirmem, dircount*direntrysize);
312 	if (n != dircount*direntrysize) {
313 		n /= direntrysize;
314 		Error(
315 #if defined(__WIN32__) && defined(_MSC_VER)
316 	    "Could only read %lu of %u entries in directory at offset %#I64x",
317 		      (unsigned long)n, dircount, (unsigned __int64) off);
318 #else
319 	    "Could only read %lu of %u entries in directory at offset %#llx",
320 		      (unsigned long)n, dircount, (unsigned long long) off);
321 #endif
322 		dircount = n;
323 		nextdiroff = 0;
324 	} else {
325 		if (!bigtiff) {
326 			uint32 nextdiroff32;
327 			if (read(fd, (char*) &nextdiroff32, sizeof (uint32)) != sizeof (uint32))
328 				nextdiroff32 = 0;
329 			if (swabflag)
330 				TIFFSwabLong(&nextdiroff32);
331 			nextdiroff = nextdiroff32;
332 		} else {
333 			if (read(fd, (char*) &nextdiroff, sizeof (uint64)) != sizeof (uint64))
334 				nextdiroff = 0;
335 			if (swabflag)
336 				TIFFSwabLong8(&nextdiroff);
337 		}
338 	}
339 #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
340 	printf("Directory %u: offset %I64u (%#I64x) next %I64u (%#I64x)\n", ix,
341 	    (unsigned __int64)off, (unsigned __int64)off,
342 	    (unsigned __int64)nextdiroff, (unsigned __int64)nextdiroff);
343 #else
344 	printf("Directory %u: offset %llu (%#llx) next %llu (%#llx)\n", ix,
345 	    (unsigned long long)off, (unsigned long long)off,
346 	    (unsigned long long)nextdiroff, (unsigned long long)nextdiroff);
347 #endif
348 	for (dp = (uint8*)dirmem, n = dircount; n > 0; n--) {
349 		uint16 tag;
350 		uint16 type;
351 		uint16 typewidth;
352 		uint64 count;
353 		uint64 datasize;
354 		int datafits;
355 		void* datamem;
356 		uint64 dataoffset;
357 		int datatruncated;
358 		tag = *(uint16*)dp;
359 		if (swabflag)
360 			TIFFSwabShort(&tag);
361 		dp += sizeof(uint16);
362 		type = *(uint16*)dp;
363 		dp += sizeof(uint16);
364 		if (swabflag)
365 			TIFFSwabShort(&type);
366 		PrintTag(stdout, tag);
367 		putchar(' ');
368 		PrintType(stdout, type);
369 		putchar(' ');
370 		if (!bigtiff)
371 		{
372 			uint32 count32;
373 			count32 = *(uint32*)dp;
374 			if (swabflag)
375 				TIFFSwabLong(&count32);
376 			dp += sizeof(uint32);
377 			count = count32;
378 		}
379 		else
380 		{
381 			count = *(uint64*)dp;
382 			if (swabflag)
383 				TIFFSwabLong8(&count);
384 			dp += sizeof(uint64);
385 		}
386 #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__))
387 		printf("%I64u<", (unsigned __int64)count);
388 #else
389 		printf("%llu<", (unsigned long long)count);
390 #endif
391 		if (type >= NWIDTHS)
392 			typewidth = 0;
393 		else
394 			typewidth = datawidth[type];
395 		datasize = count*typewidth;
396 		datafits = 1;
397 		datamem = dp;
398 		dataoffset = 0;
399 		datatruncated = 0;
400 		if (!bigtiff)
401 		{
402 			if (datasize>4)
403 			{
404 				uint32 dataoffset32;
405 				datafits = 0;
406 				datamem = NULL;
407 				dataoffset32 = *(uint32*)dp;
408 				if (swabflag)
409 					TIFFSwabLong(&dataoffset32);
410 				dataoffset = dataoffset32;
411 			}
412 			dp += sizeof(uint32);
413 		}
414 		else
415 		{
416 			if (datasize>8)
417 			{
418 				datafits = 0;
419 				datamem = NULL;
420 				dataoffset = *(uint64*)dp;
421 				if (swabflag)
422 					TIFFSwabLong8(&dataoffset);
423 			}
424 			dp += sizeof(uint64);
425 		}
426 		if (datasize>0x10000)
427 		{
428 			datatruncated = 1;
429 			count = 0x10000/typewidth;
430 			datasize = count*typewidth;
431 		}
432 		if (count>maxitems)
433 		{
434 			datatruncated = 1;
435 			count = maxitems;
436 			datasize = count*typewidth;
437 		}
438 		if (!datafits)
439 		{
440 			datamem = _TIFFmalloc((uint32)datasize);
441 			if (datamem) {
442 #if defined(__WIN32__) && defined(_MSC_VER)
443 				if (_lseeki64(fd, (__int64)dataoffset, SEEK_SET)
444 				    != (__int64)dataoffset)
445 #else
446 				if (lseek(fd, (off_t)dataoffset, 0) !=
447 				    (off_t)dataoffset)
448 #endif
449 				{
450 					Error(
451 				"Seek error accessing tag %u value", tag);
452 					_TIFFfree(datamem);
453 					datamem = NULL;
454 				}
455 				if (read(fd, datamem, (size_t)datasize) != (TIFF_SSIZE_T)datasize)
456 				{
457 					Error(
458 				"Read error accessing tag %u value", tag);
459 					_TIFFfree(datamem);
460 					datamem = NULL;
461 				}
462 			} else
463 				Error("No space for data for tag %u",tag);
464 		}
465 		if (datamem)
466 		{
467 			if (swabflag)
468 			{
469 				switch (type)
470 				{
471 					case TIFF_BYTE:
472 					case TIFF_ASCII:
473 					case TIFF_SBYTE:
474 					case TIFF_UNDEFINED:
475 						break;
476 					case TIFF_SHORT:
477 					case TIFF_SSHORT:
478 						TIFFSwabArrayOfShort((uint16*)datamem,(tmsize_t)count);
479 						break;
480 					case TIFF_LONG:
481 					case TIFF_SLONG:
482 					case TIFF_FLOAT:
483 					case TIFF_IFD:
484 						TIFFSwabArrayOfLong((uint32*)datamem,(tmsize_t)count);
485 						break;
486 					case TIFF_RATIONAL:
487 					case TIFF_SRATIONAL:
488 						TIFFSwabArrayOfLong((uint32*)datamem,(tmsize_t)count*2);
489 						break;
490 					case TIFF_DOUBLE:
491 					case TIFF_LONG8:
492 					case TIFF_SLONG8:
493 					case TIFF_IFD8:
494 						TIFFSwabArrayOfLong8((uint64*)datamem,(tmsize_t)count);
495 						break;
496 				}
497 			}
498 			PrintData(stdout,type,(uint32)count,datamem);
499 			if (datatruncated)
500 				printf(" ...");
501 			if (!datafits)
502 				_TIFFfree(datamem);
503 		}
504 		printf(">\n");
505 	}
506 done:
507 	if (dirmem)
508 		_TIFFfree((char *)dirmem);
509 	return (nextdiroff);
510 }
511 
512 static const struct tagname {
513 	uint16 tag;
514 	const char* name;
515 } tagnames[] = {
516     { TIFFTAG_SUBFILETYPE,	"SubFileType" },
517     { TIFFTAG_OSUBFILETYPE,	"OldSubFileType" },
518     { TIFFTAG_IMAGEWIDTH,	"ImageWidth" },
519     { TIFFTAG_IMAGELENGTH,	"ImageLength" },
520     { TIFFTAG_BITSPERSAMPLE,	"BitsPerSample" },
521     { TIFFTAG_COMPRESSION,	"Compression" },
522     { TIFFTAG_PHOTOMETRIC,	"Photometric" },
523     { TIFFTAG_THRESHHOLDING,	"Threshholding" },
524     { TIFFTAG_CELLWIDTH,	"CellWidth" },
525     { TIFFTAG_CELLLENGTH,	"CellLength" },
526     { TIFFTAG_FILLORDER,	"FillOrder" },
527     { TIFFTAG_DOCUMENTNAME,	"DocumentName" },
528     { TIFFTAG_IMAGEDESCRIPTION,	"ImageDescription" },
529     { TIFFTAG_MAKE,		"Make" },
530     { TIFFTAG_MODEL,		"Model" },
531     { TIFFTAG_STRIPOFFSETS,	"StripOffsets" },
532     { TIFFTAG_ORIENTATION,	"Orientation" },
533     { TIFFTAG_SAMPLESPERPIXEL,	"SamplesPerPixel" },
534     { TIFFTAG_ROWSPERSTRIP,	"RowsPerStrip" },
535     { TIFFTAG_STRIPBYTECOUNTS,	"StripByteCounts" },
536     { TIFFTAG_MINSAMPLEVALUE,	"MinSampleValue" },
537     { TIFFTAG_MAXSAMPLEVALUE,	"MaxSampleValue" },
538     { TIFFTAG_XRESOLUTION,	"XResolution" },
539     { TIFFTAG_YRESOLUTION,	"YResolution" },
540     { TIFFTAG_PLANARCONFIG,	"PlanarConfig" },
541     { TIFFTAG_PAGENAME,		"PageName" },
542     { TIFFTAG_XPOSITION,	"XPosition" },
543     { TIFFTAG_YPOSITION,	"YPosition" },
544     { TIFFTAG_FREEOFFSETS,	"FreeOffsets" },
545     { TIFFTAG_FREEBYTECOUNTS,	"FreeByteCounts" },
546     { TIFFTAG_GRAYRESPONSEUNIT,	"GrayResponseUnit" },
547     { TIFFTAG_GRAYRESPONSECURVE,"GrayResponseCurve" },
548     { TIFFTAG_GROUP3OPTIONS,	"Group3Options" },
549     { TIFFTAG_GROUP4OPTIONS,	"Group4Options" },
550     { TIFFTAG_RESOLUTIONUNIT,	"ResolutionUnit" },
551     { TIFFTAG_PAGENUMBER,	"PageNumber" },
552     { TIFFTAG_COLORRESPONSEUNIT,"ColorResponseUnit" },
553     { TIFFTAG_TRANSFERFUNCTION,	"TransferFunction" },
554     { TIFFTAG_SOFTWARE,		"Software" },
555     { TIFFTAG_DATETIME,		"DateTime" },
556     { TIFFTAG_ARTIST,		"Artist" },
557     { TIFFTAG_HOSTCOMPUTER,	"HostComputer" },
558     { TIFFTAG_PREDICTOR,	"Predictor" },
559     { TIFFTAG_WHITEPOINT,	"Whitepoint" },
560     { TIFFTAG_PRIMARYCHROMATICITIES,"PrimaryChromaticities" },
561     { TIFFTAG_COLORMAP,		"Colormap" },
562     { TIFFTAG_HALFTONEHINTS,	"HalftoneHints" },
563     { TIFFTAG_TILEWIDTH,	"TileWidth" },
564     { TIFFTAG_TILELENGTH,	"TileLength" },
565     { TIFFTAG_TILEOFFSETS,	"TileOffsets" },
566     { TIFFTAG_TILEBYTECOUNTS,	"TileByteCounts" },
567     { TIFFTAG_BADFAXLINES,	"BadFaxLines" },
568     { TIFFTAG_CLEANFAXDATA,	"CleanFaxData" },
569     { TIFFTAG_CONSECUTIVEBADFAXLINES, "ConsecutiveBadFaxLines" },
570     { TIFFTAG_SUBIFD,		"SubIFD" },
571     { TIFFTAG_INKSET,		"InkSet" },
572     { TIFFTAG_INKNAMES,		"InkNames" },
573     { TIFFTAG_NUMBEROFINKS,	"NumberOfInks" },
574     { TIFFTAG_DOTRANGE,		"DotRange" },
575     { TIFFTAG_TARGETPRINTER,	"TargetPrinter" },
576     { TIFFTAG_EXTRASAMPLES,	"ExtraSamples" },
577     { TIFFTAG_SAMPLEFORMAT,	"SampleFormat" },
578     { TIFFTAG_SMINSAMPLEVALUE,	"SMinSampleValue" },
579     { TIFFTAG_SMAXSAMPLEVALUE,	"SMaxSampleValue" },
580     { TIFFTAG_JPEGPROC,		"JPEGProcessingMode" },
581     { TIFFTAG_JPEGIFOFFSET,	"JPEGInterchangeFormat" },
582     { TIFFTAG_JPEGIFBYTECOUNT,	"JPEGInterchangeFormatLength" },
583     { TIFFTAG_JPEGRESTARTINTERVAL,"JPEGRestartInterval" },
584     { TIFFTAG_JPEGLOSSLESSPREDICTORS,"JPEGLosslessPredictors" },
585     { TIFFTAG_JPEGPOINTTRANSFORM,"JPEGPointTransform" },
586     { TIFFTAG_JPEGTABLES,       "JPEGTables" },
587     { TIFFTAG_JPEGQTABLES,	"JPEGQTables" },
588     { TIFFTAG_JPEGDCTABLES,	"JPEGDCTables" },
589     { TIFFTAG_JPEGACTABLES,	"JPEGACTables" },
590     { TIFFTAG_YCBCRCOEFFICIENTS,"YCbCrCoefficients" },
591     { TIFFTAG_YCBCRSUBSAMPLING,	"YCbCrSubsampling" },
592     { TIFFTAG_YCBCRPOSITIONING,	"YCbCrPositioning" },
593     { TIFFTAG_REFERENCEBLACKWHITE, "ReferenceBlackWhite" },
594     { TIFFTAG_REFPTS,		"IgReferencePoints (Island Graphics)" },
595     { TIFFTAG_REGIONTACKPOINT,	"IgRegionTackPoint (Island Graphics)" },
596     { TIFFTAG_REGIONWARPCORNERS,"IgRegionWarpCorners (Island Graphics)" },
597     { TIFFTAG_REGIONAFFINE,	"IgRegionAffine (Island Graphics)" },
598     { TIFFTAG_MATTEING,		"OBSOLETE Matteing (Silicon Graphics)" },
599     { TIFFTAG_DATATYPE,		"OBSOLETE DataType (Silicon Graphics)" },
600     { TIFFTAG_IMAGEDEPTH,	"ImageDepth (Silicon Graphics)" },
601     { TIFFTAG_TILEDEPTH,	"TileDepth (Silicon Graphics)" },
602     { 32768,			"OLD BOGUS Matteing tag" },
603     { TIFFTAG_COPYRIGHT,	"Copyright" },
604     { TIFFTAG_ICCPROFILE,	"ICC Profile" },
605     { TIFFTAG_JBIGOPTIONS,	"JBIG Options" },
606     { TIFFTAG_STONITS,		"StoNits" },
607 };
608 #define	NTAGS	(sizeof (tagnames) / sizeof (tagnames[0]))
609 
610 static void
611 PrintTag(FILE* fd, uint16 tag)
612 {
613 	const struct tagname *tp;
614 
615 	for (tp = tagnames; tp < &tagnames[NTAGS]; tp++)
616 		if (tp->tag == tag) {
617 			fprintf(fd, "%s (%u)", tp->name, tag);
618 			return;
619 		}
620 	fprintf(fd, "%u (%#x)", tag, tag);
621 }
622 
623 static void
624 PrintType(FILE* fd, uint16 type)
625 {
626 	static const char *typenames[] = {
627 	    "0",
628 	    "BYTE",
629 	    "ASCII",
630 	    "SHORT",
631 	    "LONG",
632 	    "RATIONAL",
633 	    "SBYTE",
634 	    "UNDEFINED",
635 	    "SSHORT",
636 	    "SLONG",
637 	    "SRATIONAL",
638 	    "FLOAT",
639 	    "DOUBLE",
640 	    "IFD",
641 	    "14",
642 	    "15",
643 	    "LONG8",
644 	    "SLONG8",
645 	    "IFD8"
646 	};
647 #define	NTYPES	(sizeof (typenames) / sizeof (typenames[0]))
648 
649 	if (type < NTYPES)
650 		fprintf(fd, "%s (%u)", typenames[type], type);
651 	else
652 		fprintf(fd, "%u (%#x)", type, type);
653 }
654 #undef	NTYPES
655 
656 #include <ctype.h>
657 
658 static void
659 PrintASCII(FILE* fd, uint32 cc, const unsigned char* cp)
660 {
661 	for (; cc > 0; cc--, cp++) {
662 		const char* tp;
663 
664 		if (isprint(*cp)) {
665 			fputc(*cp, fd);
666 			continue;
667 		}
668 		for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++)
669 			if (*tp++ == *cp)
670 				break;
671 		if (*tp)
672 			fprintf(fd, "\\%c", *tp);
673 		else if (*cp)
674 			fprintf(fd, "\\%03o", *cp);
675 		else
676 			fprintf(fd, "\\0");
677 	}
678 }
679 
680 static void
681 PrintData(FILE* fd, uint16 type, uint32 count, unsigned char* data)
682 {
683 	char* sep = "";
684 
685 	switch (type) {
686 	case TIFF_BYTE:
687 		while (count-- > 0)
688 			fprintf(fd, bytefmt, sep, *data++), sep = " ";
689 		break;
690 	case TIFF_SBYTE:
691 		while (count-- > 0)
692 			fprintf(fd, sbytefmt, sep, *(char *)data++), sep = " ";
693 		break;
694 	case TIFF_UNDEFINED:
695 		while (count-- > 0)
696 			fprintf(fd, bytefmt, sep, *data++), sep = " ";
697 		break;
698 	case TIFF_ASCII:
699 		PrintASCII(fd, count, data);
700 		break;
701 	case TIFF_SHORT: {
702 		uint16 *wp = (uint16*)data;
703 		while (count-- > 0)
704 			fprintf(fd, shortfmt, sep, *wp++), sep = " ";
705 		break;
706 	}
707 	case TIFF_SSHORT: {
708 		int16 *wp = (int16*)data;
709 		while (count-- > 0)
710 			fprintf(fd, sshortfmt, sep, *wp++), sep = " ";
711 		break;
712 	}
713 	case TIFF_LONG: {
714 		uint32 *lp = (uint32*)data;
715 		while (count-- > 0) {
716 			fprintf(fd, longfmt, sep, (unsigned long) *lp++);
717 			sep = " ";
718 		}
719 		break;
720 	}
721 	case TIFF_SLONG: {
722 		int32 *lp = (int32*)data;
723 		while (count-- > 0)
724 			fprintf(fd, slongfmt, sep, (long) *lp++), sep = " ";
725 		break;
726 	}
727 	case TIFF_LONG8: {
728 		uint64 *llp = (uint64*)data;
729 		while (count-- > 0) {
730 #if defined(__WIN32__) && defined(_MSC_VER)
731 			fprintf(fd, long8fmt, sep, (unsigned __int64) *llp++);
732 #else
733 			fprintf(fd, long8fmt, sep, (unsigned long long) *llp++);
734 #endif
735 			sep = " ";
736 		}
737 		break;
738 	}
739 	case TIFF_SLONG8: {
740 		int64 *llp = (int64*)data;
741 		while (count-- > 0)
742 #if defined(__WIN32__) && defined(_MSC_VER)
743 			fprintf(fd, slong8fmt, sep, (__int64) *llp++), sep = " ";
744 #else
745 			fprintf(fd, slong8fmt, sep, (long long) *llp++), sep = " ";
746 #endif
747 		break;
748 	}
749 	case TIFF_RATIONAL: {
750 		uint32 *lp = (uint32*)data;
751 		while (count-- > 0) {
752 			if (lp[1] == 0)
753 				fprintf(fd, "%sNan (%lu/%lu)", sep,
754 				    (unsigned long) lp[0],
755 				    (unsigned long) lp[1]);
756 			else
757 				fprintf(fd, rationalfmt, sep,
758 				    (double)lp[0] / (double)lp[1]);
759 			sep = " ";
760 			lp += 2;
761 		}
762 		break;
763 	}
764 	case TIFF_SRATIONAL: {
765 		int32 *lp = (int32*)data;
766 		while (count-- > 0) {
767 			if (lp[1] == 0)
768 				fprintf(fd, "%sNan (%ld/%ld)", sep,
769 				    (long) lp[0], (long) lp[1]);
770 			else
771 				fprintf(fd, srationalfmt, sep,
772 				    (double)lp[0] / (double)lp[1]);
773 			sep = " ";
774 			lp += 2;
775 		}
776 		break;
777 	}
778 	case TIFF_FLOAT: {
779 		float *fp = (float *)data;
780 		while (count-- > 0)
781 			fprintf(fd, floatfmt, sep, *fp++), sep = " ";
782 		break;
783 	}
784 	case TIFF_DOUBLE: {
785 		double *dp = (double *)data;
786 		while (count-- > 0)
787 			fprintf(fd, doublefmt, sep, *dp++), sep = " ";
788 		break;
789 	}
790 	case TIFF_IFD: {
791 		uint32 *lp = (uint32*)data;
792 		while (count-- > 0) {
793 			fprintf(fd, ifdfmt, sep, (unsigned long) *lp++);
794 			sep = " ";
795 		}
796 		break;
797 	}
798 	case TIFF_IFD8: {
799 		uint64 *llp = (uint64*)data;
800 		while (count-- > 0) {
801 #if defined(__WIN32__) && defined(_MSC_VER)
802 			fprintf(fd, ifd8fmt, sep, (unsigned __int64) *llp++);
803 #else
804 			fprintf(fd, ifd8fmt, sep, (unsigned long long) *llp++);
805 #endif
806 			sep = " ";
807 		}
808 		break;
809 	}
810 	}
811 }
812 
813 static void
814 ReadError(char* what)
815 {
816 	Fatal("Error while reading %s", what);
817 }
818 
819 #include <stdarg.h>
820 
821 static void
822 vError(FILE* fd, const char* fmt, va_list ap)
823 {
824 	fprintf(fd, "%s: ", curfile);
825 	vfprintf(fd, fmt, ap);
826 	fprintf(fd, ".\n");
827 }
828 
829 static void
830 Error(const char* fmt, ...)
831 {
832 	va_list ap;
833 	va_start(ap, fmt);
834 	vError(stderr, fmt, ap);
835 	va_end(ap);
836 }
837 
838 static void
839 Fatal(const char* fmt, ...)
840 {
841 	va_list ap;
842 	va_start(ap, fmt);
843 	vError(stderr, fmt, ap);
844 	va_end(ap);
845 	exit(-1);
846 }
847 
848 /* vim: set ts=8 sts=8 sw=8 noet: */
849 /*
850  * Local Variables:
851  * mode: c
852  * c-basic-offset: 8
853  * fill-column: 78
854  * End:
855  */
856