1 /*
2  * Copyright (c) 1988-1997 Sam Leffler
3  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that (i) the above copyright notices and this permission notice appear in
8  * all copies of the software and related documentation, and (ii) the names of
9  * Sam Leffler and Silicon Graphics may not be used in any advertising or
10  * publicity relating to the software without the specific, prior written
11  * permission of Sam Leffler and Silicon Graphics.
12  *
13  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
18  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22  * OF THIS SOFTWARE.
23  */
24 
25 #include "tif_config.h"
26 #include "libport.h"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #ifdef HAVE_STRINGS_H
33 # include <strings.h>
34 #endif
35 
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 
40 #include "tiffiop.h"
41 
42 #ifndef EXIT_SUCCESS
43 #define EXIT_SUCCESS 0
44 #endif
45 #ifndef EXIT_FAILURE
46 #define EXIT_FAILURE 1
47 #endif
48 
49 static TIFFErrorHandler old_error_handler = 0;
50 static int status = EXIT_SUCCESS;       /* exit status */
51 static int showdata = 0;		/* show data */
52 static int rawdata = 0;			/* show raw/decoded data */
53 static int showwords = 0;		/* show data as bytes/words */
54 static int readdata = 0;		/* read data in file */
55 static int stoponerr = 1;		/* stop on first read error */
56 
57 static	void usage(int);
58 static	void tiffinfo(TIFF*, uint16_t, long, int);
59 
60 static void
PrivateErrorHandler(const char * module,const char * fmt,va_list ap)61 PrivateErrorHandler(const char* module, const char* fmt, va_list ap)
62 {
63         if (old_error_handler)
64                 (*old_error_handler)(module,fmt,ap);
65 	status = EXIT_FAILURE;
66 }
67 
68 int
main(int argc,char * argv[])69 main(int argc, char* argv[])
70 {
71 	int dirnum = -1, multiplefiles, c;
72 	uint16_t order = 0;
73 	TIFF* tif;
74 #if !HAVE_DECL_OPTARG
75 	extern int optind;
76 	extern char* optarg;
77 #endif
78 	long flags = 0;
79 	uint64_t diroff = 0;
80 	int chopstrips = 0;		/* disable strip chopping */
81 
82 	while ((c = getopt(argc, argv, "f:o:cdDSjilmrsvwz0123456789h")) != -1)
83 		switch (c) {
84 		case '0': case '1': case '2': case '3':
85 		case '4': case '5': case '6': case '7':
86 		case '8': case '9':
87 			dirnum = atoi(&argv[optind-1][1]);
88 			break;
89 		case 'd':
90 			showdata++;
91 			/* fall through... */
92 		case 'D':
93 			readdata++;
94 			break;
95 		case 'c':
96 			flags |= TIFFPRINT_COLORMAP | TIFFPRINT_CURVES;
97 			break;
98 		case 'f':		/* fill order */
99 			if (streq(optarg, "lsb2msb"))
100 				order = FILLORDER_LSB2MSB;
101 			else if (streq(optarg, "msb2lsb"))
102 				order = FILLORDER_MSB2LSB;
103 			else
104 				usage(EXIT_FAILURE);
105 			break;
106 		case 'i':
107 			stoponerr = 0;
108 			break;
109 		case 'o':
110 			diroff = strtoul(optarg, NULL, 0);
111 			break;
112 		case 'j':
113 			flags |= TIFFPRINT_JPEGQTABLES |
114 				 TIFFPRINT_JPEGACTABLES |
115 				 TIFFPRINT_JPEGDCTABLES;
116 			break;
117 		case 'r':
118 			rawdata = 1;
119 			break;
120 		case 's':
121 			flags |= TIFFPRINT_STRIPS;
122 			break;
123 		case 'w':
124 			showwords = 1;
125 			break;
126 		case 'z':
127 			chopstrips = 1;
128 			break;
129 		case 'h':
130 			usage(EXIT_SUCCESS);
131                         /*NOTREACHED*/
132                         break;
133 		case '?':
134 			usage(EXIT_FAILURE);
135 			/*NOTREACHED*/
136                         break;
137 		}
138 	if (optind >= argc)
139 		usage(EXIT_FAILURE);
140 
141 	old_error_handler = TIFFSetErrorHandler(PrivateErrorHandler);
142 
143 	multiplefiles = (argc - optind > 1);
144 	for (; optind < argc; optind++) {
145 		if (multiplefiles)
146 			printf("%s:\n", argv[optind]);
147 		tif = TIFFOpen(argv[optind], chopstrips ? "rC" : "rc");
148 		if (tif != NULL) {
149 			if (dirnum != -1) {
150 				if (TIFFSetDirectory(tif, (tdir_t) dirnum))
151 					tiffinfo(tif, order, flags, 1);
152 			} else if (diroff != 0) {
153 				if (TIFFSetSubDirectory(tif, diroff))
154 					tiffinfo(tif, order, flags, 1);
155 			} else {
156 				do {
157 					toff_t offset=0;
158 
159 					tiffinfo(tif, order, flags, 1);
160 					if (TIFFGetField(tif, TIFFTAG_EXIFIFD,
161 							 &offset)) {
162 						if (TIFFReadEXIFDirectory(tif, offset)) {
163 							tiffinfo(tif, order, flags, 0);
164 						}
165 					}
166 				} while (TIFFReadDirectory(tif));
167 			}
168 			TIFFClose(tif);
169 		}
170 	}
171 	return (status);
172 }
173 
174 static const char usage_info[] =
175 "Display information about TIFF files\n\n"
176 "usage: tiffinfo [options] input...\n"
177 "where options are:\n"
178 " -D		read data\n"
179 " -i		ignore read errors\n"
180 " -c		display data for grey/color response curve or colormap\n"
181 " -d		display raw/decoded image data\n"
182 " -f lsb2msb	force lsb-to-msb FillOrder for input\n"
183 " -f msb2lsb	force msb-to-lsb FillOrder for input\n"
184 " -j		show JPEG tables\n"
185 " -o offset	set initial directory offset\n"
186 " -r		read/display raw image data instead of decoded data\n"
187 " -s		display strip offsets and byte counts\n"
188 " -w		display raw data in words rather than bytes\n"
189 " -z		enable strip chopping\n"
190 " -#		set initial directory (first directory is # 0)\n"
191 ;
192 
193 static void
usage(int code)194 usage(int code)
195 {
196 	FILE * out = (code == EXIT_SUCCESS) ? stdout : stderr;
197 
198         fprintf(out, "%s\n\n", TIFFGetVersion());
199         fprintf(out, "%s", usage_info);
200 	exit(code);
201 }
202 
203 static void
ShowStrip(tstrip_t strip,unsigned char * pp,uint32_t nrow,tsize_t scanline)204 ShowStrip(tstrip_t strip, unsigned char* pp, uint32_t nrow, tsize_t scanline)
205 {
206 	register tsize_t cc;
207 
208 	printf("Strip %"PRIu32":\n", strip);
209 	while (nrow-- > 0) {
210 		for (cc = 0; cc < scanline; cc++) {
211 			printf(" %02x", *pp++);
212 			if (((cc+1) % 24) == 0)
213 				putchar('\n');
214 		}
215 		putchar('\n');
216 	}
217 }
218 
219 void
TIFFReadContigStripData(TIFF * tif)220 TIFFReadContigStripData(TIFF* tif)
221 {
222 	unsigned char *buf;
223 	tsize_t scanline = TIFFScanlineSize(tif);
224 
225 	buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
226 	if (buf) {
227 		uint32_t row, h=0;
228 		uint32_t rowsperstrip = (uint32_t)-1;
229 
230 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
231 		TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
232 		for (row = 0; row < h; row += rowsperstrip) {
233 			uint32_t nrow = (row + rowsperstrip > h ?
234 			    h-row : rowsperstrip);
235 			tstrip_t strip = TIFFComputeStrip(tif, row, 0);
236 			if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
237 				if (stoponerr)
238 					break;
239 			} else if (showdata)
240 				ShowStrip(strip, buf, nrow, scanline);
241 		}
242 		_TIFFfree(buf);
243 	}
244 }
245 
246 void
TIFFReadSeparateStripData(TIFF * tif)247 TIFFReadSeparateStripData(TIFF* tif)
248 {
249 	unsigned char *buf;
250 	tsize_t scanline = TIFFScanlineSize(tif);
251 
252 	buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
253 	if (buf) {
254 		uint32_t row, h=0;
255 		uint32_t rowsperstrip = (uint32_t)-1;
256 		tsample_t s, samplesperpixel=0;
257 
258 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
259 		TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
260 		TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
261 		for (row = 0; row < h; row += rowsperstrip) {
262 			for (s = 0; s < samplesperpixel; s++) {
263 				uint32_t nrow = (row + rowsperstrip > h ?
264 				    h-row : rowsperstrip);
265 				tstrip_t strip = TIFFComputeStrip(tif, row, s);
266 				if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
267 					if (stoponerr)
268 						break;
269 				} else if (showdata)
270 					ShowStrip(strip, buf, nrow, scanline);
271 			}
272 		}
273 		_TIFFfree(buf);
274 	}
275 }
276 
277 static void
ShowTile(uint32_t row,uint32_t col,tsample_t sample,unsigned char * pp,uint32_t nrow,tsize_t rowsize)278 ShowTile(uint32_t row, uint32_t col, tsample_t sample,
279          unsigned char* pp, uint32_t nrow, tsize_t rowsize)
280 {
281 	uint32_t cc;
282 
283 	printf("Tile (%" PRIu32 ",%" PRIu32 "", row, col);
284 	if (sample != (tsample_t) -1)
285 		printf(",%" PRIu16, sample);
286 	printf("):\n");
287 	while (nrow-- > 0) {
288 	  for (cc = 0; cc < (uint32_t) rowsize; cc++) {
289 			printf(" %02x", *pp++);
290 			if (((cc+1) % 24) == 0)
291 				putchar('\n');
292 		}
293 		putchar('\n');
294 	}
295 }
296 
297 void
TIFFReadContigTileData(TIFF * tif)298 TIFFReadContigTileData(TIFF* tif)
299 {
300 	unsigned char *buf;
301 	tmsize_t rowsize = TIFFTileRowSize(tif);
302         tmsize_t tilesize = TIFFTileSize(tif);
303 
304 	buf = (unsigned char *)_TIFFmalloc(tilesize);
305 	if (buf) {
306 		uint32_t tw=0, th=0, w=0, h=0;
307 		uint32_t row, col;
308 
309 		TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
310 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
311 		TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
312 		TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
313                 if ( rowsize == 0 || th > (size_t) (tilesize / rowsize) )
314         {
315             fprintf(stderr, "Cannot display data: th * rowsize > tilesize\n");
316             _TIFFfree(buf);
317             return;
318         }
319 		for (row = 0; row < h; row += th) {
320 			for (col = 0; col < w; col += tw) {
321 				if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0) {
322 					if (stoponerr)
323 						break;
324 				} else if (showdata)
325 					ShowTile(row, col, (tsample_t) -1, buf, th, rowsize);
326 			}
327 		}
328 		_TIFFfree(buf);
329 	}
330 }
331 
332 void
TIFFReadSeparateTileData(TIFF * tif)333 TIFFReadSeparateTileData(TIFF* tif)
334 {
335 	unsigned char *buf;
336         tmsize_t rowsize = TIFFTileRowSize(tif);
337         tmsize_t tilesize = TIFFTileSize(tif);
338 
339 	buf = (unsigned char *)_TIFFmalloc(tilesize);
340 	if (buf) {
341 		uint32_t tw=0, th=0, w=0, h=0;
342 		uint32_t row, col;
343 		tsample_t s, samplesperpixel=0;
344 
345 		TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
346 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
347 		TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
348 		TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
349 		TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
350                 if ( rowsize == 0 || th > (size_t) (tilesize / rowsize) )
351         {
352             fprintf(stderr, "Cannot display data: th * rowsize > tilesize\n");
353             _TIFFfree(buf);
354             return;
355         }
356 		for (row = 0; row < h; row += th) {
357 			for (col = 0; col < w; col += tw) {
358 				for (s = 0; s < samplesperpixel; s++) {
359 					if (TIFFReadTile(tif, buf, col, row, 0, s) < 0) {
360 						if (stoponerr)
361 							break;
362 					} else if (showdata)
363 						ShowTile(row, col, s, buf, th, rowsize);
364 				}
365 			}
366 		}
367 		_TIFFfree(buf);
368 	}
369 }
370 
371 void
TIFFReadData(TIFF * tif)372 TIFFReadData(TIFF* tif)
373 {
374 	uint16_t config = PLANARCONFIG_CONTIG;
375 
376 	TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
377 	if (TIFFIsTiled(tif)) {
378 		if (config == PLANARCONFIG_CONTIG)
379 			TIFFReadContigTileData(tif);
380 		else
381 			TIFFReadSeparateTileData(tif);
382 	} else {
383 		if (config == PLANARCONFIG_CONTIG)
384 			TIFFReadContigStripData(tif);
385 		else
386 			TIFFReadSeparateStripData(tif);
387 	}
388 }
389 
390 static void
ShowRawBytes(unsigned char * pp,uint32_t n)391 ShowRawBytes(unsigned char* pp, uint32_t n)
392 {
393 	uint32_t i;
394 
395 	for (i = 0; i < n; i++) {
396 		printf(" %02x", *pp++);
397 		if (((i+1) % 24) == 0)
398 			printf("\n ");
399 	}
400 	putchar('\n');
401 }
402 
403 static void
ShowRawWords(uint16_t * pp,uint32_t n)404 ShowRawWords(uint16_t* pp, uint32_t n)
405 {
406 	uint32_t i;
407 
408 	for (i = 0; i < n; i++) {
409 		printf(" %04" PRIx16, *pp++);
410 		if (((i+1) % 15) == 0)
411 			printf("\n ");
412 	}
413 	putchar('\n');
414 }
415 
416 static void
TIFFReadRawDataStriped(TIFF * tif,int bitrev)417 TIFFReadRawDataStriped(TIFF* tif, int bitrev)
418 {
419 	tstrip_t nstrips = TIFFNumberOfStrips(tif);
420 	const char* what = "Strip";
421 	uint64_t* stripbc=NULL;
422 
423 	TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbc);
424 	if (stripbc != NULL && nstrips > 0) {
425 		uint32_t bufsize = (uint32_t) stripbc[0];
426 		tdata_t buf = _TIFFmalloc(bufsize);
427 		tstrip_t s;
428 
429 		for (s = 0; s < nstrips; s++) {
430 			if (stripbc[s] > bufsize) {
431 				buf = _TIFFrealloc(buf, (tmsize_t)stripbc[s]);
432 				bufsize = (uint32_t) stripbc[s];
433 			}
434 			if (buf == NULL) {
435 				fprintf(stderr,
436 				   "Cannot allocate buffer to read strip %"PRIu32"\n",
437 				    s);
438 				break;
439 			}
440 			if (TIFFReadRawStrip(tif, s, buf, (tmsize_t) stripbc[s]) < 0) {
441 				fprintf(stderr, "Error reading strip %"PRIu32"\n",
442 				    s);
443 				if (stoponerr)
444 					break;
445 			} else if (showdata) {
446 				if (bitrev) {
447 					TIFFReverseBits(buf, (tmsize_t)stripbc[s]);
448 					printf("%s %"PRIu32": (bit reversed)\n ",
449 					    what, s);
450 				} else
451 					printf("%s %"PRIu32":\n ", what,
452 					    s);
453 				if (showwords)
454 					ShowRawWords((uint16_t*) buf, (uint32_t) stripbc[s] >> 1);
455 				else
456 					ShowRawBytes((unsigned char*) buf, (uint32_t) stripbc[s]);
457 			}
458 		}
459 		if (buf != NULL)
460 			_TIFFfree(buf);
461 	}
462 }
463 
464 static void
TIFFReadRawDataTiled(TIFF * tif,int bitrev)465 TIFFReadRawDataTiled(TIFF* tif, int bitrev)
466 {
467 	const char* what = "Tile";
468 	uint32_t ntiles = TIFFNumberOfTiles(tif);
469 	uint64_t *tilebc;
470 
471 	TIFFGetField(tif, TIFFTAG_TILEBYTECOUNTS, &tilebc);
472 	if (tilebc != NULL && ntiles > 0) {
473 		uint64_t bufsize = 0;
474 		tdata_t buf = NULL;
475 		uint32_t t;
476 
477 		for (t = 0; t < ntiles; t++) {
478 			if (buf == NULL || tilebc[t] > bufsize) {
479 				buf = _TIFFrealloc(buf, (tmsize_t)tilebc[t]);
480 				bufsize = tilebc[t];
481 			}
482 			if (buf == NULL) {
483 				fprintf(stderr,
484 				   "Cannot allocate buffer to read tile %"PRIu32"\n",
485 				    t);
486 				break;
487 			}
488 			if (TIFFReadRawTile(tif, t, buf, (tmsize_t)tilebc[t]) < 0) {
489 				fprintf(stderr, "Error reading tile %"PRIu32"\n",
490 				    t);
491 				if (stoponerr)
492 					break;
493 			} else if (showdata) {
494 				if (bitrev) {
495 					TIFFReverseBits(buf, (tmsize_t)tilebc[t]);
496 					printf("%s %"PRIu32": (bit reversed)\n ",
497 					    what, t);
498 				} else {
499 					printf("%s %"PRIu32":\n ", what,
500 					    t);
501 				}
502 				if (showwords) {
503 					ShowRawWords((uint16_t*) buf, (uint32_t)(tilebc[t] >> 1));
504 				} else {
505 					ShowRawBytes((unsigned char*) buf, (uint32_t) tilebc[t]);
506 				}
507 			}
508 		}
509 		if (buf != NULL)
510 			_TIFFfree(buf);
511 	}
512 }
513 
514 void
TIFFReadRawData(TIFF * tif,int bitrev)515 TIFFReadRawData(TIFF* tif, int bitrev)
516 {
517 	if (TIFFIsTiled(tif)) {
518 		TIFFReadRawDataTiled(tif, bitrev);
519 	} else {
520 		TIFFReadRawDataStriped(tif, bitrev);
521 	}
522 }
523 
524 static void
tiffinfo(TIFF * tif,uint16_t order,long flags,int is_image)525 tiffinfo(TIFF* tif, uint16_t order, long flags, int is_image)
526 {
527 	TIFFPrintDirectory(tif, stdout, flags);
528 	if (!readdata || !is_image)
529 		return;
530 	if (rawdata) {
531 		if (order) {
532 			uint16_t o;
533 			TIFFGetFieldDefaulted(tif,
534 			    TIFFTAG_FILLORDER, &o);
535 			TIFFReadRawData(tif, o != order);
536 		} else
537 			TIFFReadRawData(tif, 0);
538 	} else {
539 		if (order)
540 			TIFFSetField(tif, TIFFTAG_FILLORDER, order);
541 		TIFFReadData(tif);
542 	}
543 }
544 
545 /* vim: set ts=8 sts=8 sw=8 noet: */
546 /*
547  * Local Variables:
548  * mode: c
549  * c-basic-offset: 8
550  * fill-column: 78
551  * End:
552  */
553