1 /* $Id: tiffinfo.c,v 1.26 2016-12-03 14:18:49 erouault 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_STRINGS_H
34 # include <strings.h>
35 #endif
36 
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 
41 #ifdef NEED_LIBPORT
42 # include "libport.h"
43 #endif
44 
45 #include "tiffiop.h"
46 
47 static TIFFErrorHandler old_error_handler = 0;
48 static int status = 0;                  /* exit status */
49 static int showdata = 0;		/* show data */
50 static int rawdata = 0;			/* show raw/decoded data */
51 static int showwords = 0;		/* show data as bytes/words */
52 static int readdata = 0;		/* read data in file */
53 static int stoponerr = 1;		/* stop on first read error */
54 
55 static	void usage(void);
56 static	void tiffinfo(TIFF*, uint16, long, int);
57 
58 static void
PrivateErrorHandler(const char * module,const char * fmt,va_list ap)59 PrivateErrorHandler(const char* module, const char* fmt, va_list ap)
60 {
61         if (old_error_handler)
62                 (*old_error_handler)(module,fmt,ap);
63 	status = 1;
64 }
65 
66 int
main(int argc,char * argv[])67 main(int argc, char* argv[])
68 {
69 	int dirnum = -1, multiplefiles, c;
70 	uint16 order = 0;
71 	TIFF* tif;
72 #if !HAVE_DECL_OPTARG
73 	extern int optind;
74 	extern char* optarg;
75 #endif
76 	long flags = 0;
77 	uint64 diroff = 0;
78 	int chopstrips = 0;		/* disable strip chopping */
79 
80 	while ((c = getopt(argc, argv, "f:o:cdDSjilmrsvwz0123456789")) != -1)
81 		switch (c) {
82 		case '0': case '1': case '2': case '3':
83 		case '4': case '5': case '6': case '7':
84 		case '8': case '9':
85 			dirnum = atoi(&argv[optind-1][1]);
86 			break;
87 		case 'd':
88 			showdata++;
89 			/* fall thru... */
90 		case 'D':
91 			readdata++;
92 			break;
93 		case 'c':
94 			flags |= TIFFPRINT_COLORMAP | TIFFPRINT_CURVES;
95 			break;
96 		case 'f':		/* fill order */
97 			if (streq(optarg, "lsb2msb"))
98 				order = FILLORDER_LSB2MSB;
99 			else if (streq(optarg, "msb2lsb"))
100 				order = FILLORDER_MSB2LSB;
101 			else
102 				usage();
103 			break;
104 		case 'i':
105 			stoponerr = 0;
106 			break;
107 		case 'o':
108 			diroff = strtoul(optarg, NULL, 0);
109 			break;
110 		case 'j':
111 			flags |= TIFFPRINT_JPEGQTABLES |
112 				 TIFFPRINT_JPEGACTABLES |
113 				 TIFFPRINT_JPEGDCTABLES;
114 			break;
115 		case 'r':
116 			rawdata = 1;
117 			break;
118 		case 's':
119 			flags |= TIFFPRINT_STRIPS;
120 			break;
121 		case 'w':
122 			showwords = 1;
123 			break;
124 		case 'z':
125 			chopstrips = 1;
126 			break;
127 		case '?':
128 			usage();
129 			/*NOTREACHED*/
130 		}
131 	if (optind >= argc)
132 		usage();
133 
134 	old_error_handler = TIFFSetErrorHandler(PrivateErrorHandler);
135 
136 	multiplefiles = (argc - optind > 1);
137 	for (; optind < argc; optind++) {
138 		if (multiplefiles)
139 			printf("%s:\n", argv[optind]);
140 		tif = TIFFOpen(argv[optind], chopstrips ? "rC" : "rc");
141 		if (tif != NULL) {
142 			if (dirnum != -1) {
143 				if (TIFFSetDirectory(tif, (tdir_t) dirnum))
144 					tiffinfo(tif, order, flags, 1);
145 			} else if (diroff != 0) {
146 				if (TIFFSetSubDirectory(tif, diroff))
147 					tiffinfo(tif, order, flags, 1);
148 			} else {
149 				do {
150 					toff_t offset=0;
151 
152 					tiffinfo(tif, order, flags, 1);
153 					if (TIFFGetField(tif, TIFFTAG_EXIFIFD,
154 							 &offset)) {
155 						if (TIFFReadEXIFDirectory(tif, offset)) {
156 							tiffinfo(tif, order, flags, 0);
157 						}
158 					}
159 				} while (TIFFReadDirectory(tif));
160 			}
161 			TIFFClose(tif);
162 		}
163 	}
164 	return (status);
165 }
166 
167 char* stuff[] = {
168 "usage: tiffinfo [options] input...",
169 "where options are:",
170 " -D		read data",
171 " -i		ignore read errors",
172 " -c		display data for grey/color response curve or colormap",
173 " -d		display raw/decoded image data",
174 " -f lsb2msb	force lsb-to-msb FillOrder for input",
175 " -f msb2lsb	force msb-to-lsb FillOrder for input",
176 " -j		show JPEG tables",
177 " -o offset	set initial directory offset",
178 " -r		read/display raw image data instead of decoded data",
179 " -s		display strip offsets and byte counts",
180 " -w		display raw data in words rather than bytes",
181 " -z		enable strip chopping",
182 " -#		set initial directory (first directory is # 0)",
183 NULL
184 };
185 
186 static void
usage(void)187 usage(void)
188 {
189 	char buf[BUFSIZ];
190 	int i;
191 
192 	setbuf(stderr, buf);
193         fprintf(stderr, "%s\n\n", TIFFGetVersion());
194 	for (i = 0; stuff[i] != NULL; i++)
195 		fprintf(stderr, "%s\n", stuff[i]);
196 	exit(-1);
197 }
198 
199 static void
ShowStrip(tstrip_t strip,unsigned char * pp,uint32 nrow,tsize_t scanline)200 ShowStrip(tstrip_t strip, unsigned char* pp, uint32 nrow, tsize_t scanline)
201 {
202 	register tsize_t cc;
203 
204 	printf("Strip %lu:\n", (unsigned long) strip);
205 	while (nrow-- > 0) {
206 		for (cc = 0; cc < scanline; cc++) {
207 			printf(" %02x", *pp++);
208 			if (((cc+1) % 24) == 0)
209 				putchar('\n');
210 		}
211 		putchar('\n');
212 	}
213 }
214 
215 void
TIFFReadContigStripData(TIFF * tif)216 TIFFReadContigStripData(TIFF* tif)
217 {
218 	unsigned char *buf;
219 	tsize_t scanline = TIFFScanlineSize(tif);
220 
221 	buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
222 	if (buf) {
223 		uint32 row, h=0;
224 		uint32 rowsperstrip = (uint32)-1;
225 
226 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
227 		TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
228 		for (row = 0; row < h; row += rowsperstrip) {
229 			uint32 nrow = (row+rowsperstrip > h ?
230 			    h-row : rowsperstrip);
231 			tstrip_t strip = TIFFComputeStrip(tif, row, 0);
232 			if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
233 				if (stoponerr)
234 					break;
235 			} else if (showdata)
236 				ShowStrip(strip, buf, nrow, scanline);
237 		}
238 		_TIFFfree(buf);
239 	}
240 }
241 
242 void
TIFFReadSeparateStripData(TIFF * tif)243 TIFFReadSeparateStripData(TIFF* tif)
244 {
245 	unsigned char *buf;
246 	tsize_t scanline = TIFFScanlineSize(tif);
247 
248 	buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
249 	if (buf) {
250 		uint32 row, h=0;
251 		uint32 rowsperstrip = (uint32)-1;
252 		tsample_t s, samplesperpixel=0;
253 
254 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
255 		TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
256 		TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
257 		for (row = 0; row < h; row += rowsperstrip) {
258 			for (s = 0; s < samplesperpixel; s++) {
259 				uint32 nrow = (row+rowsperstrip > h ?
260 				    h-row : rowsperstrip);
261 				tstrip_t strip = TIFFComputeStrip(tif, row, s);
262 				if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
263 					if (stoponerr)
264 						break;
265 				} else if (showdata)
266 					ShowStrip(strip, buf, nrow, scanline);
267 			}
268 		}
269 		_TIFFfree(buf);
270 	}
271 }
272 
273 static void
ShowTile(uint32 row,uint32 col,tsample_t sample,unsigned char * pp,uint32 nrow,tsize_t rowsize)274 ShowTile(uint32 row, uint32 col, tsample_t sample,
275     unsigned char* pp, uint32 nrow, tsize_t rowsize)
276 {
277 	uint32 cc;
278 
279 	printf("Tile (%lu,%lu", (unsigned long) row, (unsigned long) col);
280 	if (sample != (tsample_t) -1)
281 		printf(",%u", sample);
282 	printf("):\n");
283 	while (nrow-- > 0) {
284 	  for (cc = 0; cc < (uint32) rowsize; cc++) {
285 			printf(" %02x", *pp++);
286 			if (((cc+1) % 24) == 0)
287 				putchar('\n');
288 		}
289 		putchar('\n');
290 	}
291 }
292 
293 void
TIFFReadContigTileData(TIFF * tif)294 TIFFReadContigTileData(TIFF* tif)
295 {
296 	unsigned char *buf;
297 	tmsize_t rowsize = TIFFTileRowSize(tif);
298         tmsize_t tilesize = TIFFTileSize(tif);
299 
300 	buf = (unsigned char *)_TIFFmalloc(tilesize);
301 	if (buf) {
302 		uint32 tw=0, th=0, w=0, h=0;
303 		uint32 row, col;
304 
305 		TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
306 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
307 		TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
308 		TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
309                 if ( rowsize == 0 || th > (size_t) (tilesize / rowsize) )
310         {
311             fprintf(stderr, "Cannot display data: th * rowsize > tilesize\n");
312             _TIFFfree(buf);
313             return;
314         }
315 		for (row = 0; row < h; row += th) {
316 			for (col = 0; col < w; col += tw) {
317 				if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0) {
318 					if (stoponerr)
319 						break;
320 				} else if (showdata)
321 					ShowTile(row, col, (tsample_t) -1, buf, th, rowsize);
322 			}
323 		}
324 		_TIFFfree(buf);
325 	}
326 }
327 
328 void
TIFFReadSeparateTileData(TIFF * tif)329 TIFFReadSeparateTileData(TIFF* tif)
330 {
331 	unsigned char *buf;
332         tmsize_t rowsize = TIFFTileRowSize(tif);
333         tmsize_t tilesize = TIFFTileSize(tif);
334 
335 	buf = (unsigned char *)_TIFFmalloc(tilesize);
336 	if (buf) {
337 		uint32 tw=0, th=0, w=0, h=0;
338 		uint32 row, col;
339 		tsample_t s, samplesperpixel=0;
340 
341 		TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
342 		TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
343 		TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
344 		TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
345 		TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
346                 if ( rowsize == 0 || th > (size_t) (tilesize / rowsize) )
347         {
348             fprintf(stderr, "Cannot display data: th * rowsize > tilesize\n");
349             _TIFFfree(buf);
350             return;
351         }
352 		for (row = 0; row < h; row += th) {
353 			for (col = 0; col < w; col += tw) {
354 				for (s = 0; s < samplesperpixel; s++) {
355 					if (TIFFReadTile(tif, buf, col, row, 0, s) < 0) {
356 						if (stoponerr)
357 							break;
358 					} else if (showdata)
359 						ShowTile(row, col, s, buf, th, rowsize);
360 				}
361 			}
362 		}
363 		_TIFFfree(buf);
364 	}
365 }
366 
367 void
TIFFReadData(TIFF * tif)368 TIFFReadData(TIFF* tif)
369 {
370 	uint16 config = PLANARCONFIG_CONTIG;
371 
372 	TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
373 	if (TIFFIsTiled(tif)) {
374 		if (config == PLANARCONFIG_CONTIG)
375 			TIFFReadContigTileData(tif);
376 		else
377 			TIFFReadSeparateTileData(tif);
378 	} else {
379 		if (config == PLANARCONFIG_CONTIG)
380 			TIFFReadContigStripData(tif);
381 		else
382 			TIFFReadSeparateStripData(tif);
383 	}
384 }
385 
386 static void
ShowRawBytes(unsigned char * pp,uint32 n)387 ShowRawBytes(unsigned char* pp, uint32 n)
388 {
389 	uint32 i;
390 
391 	for (i = 0; i < n; i++) {
392 		printf(" %02x", *pp++);
393 		if (((i+1) % 24) == 0)
394 			printf("\n ");
395 	}
396 	putchar('\n');
397 }
398 
399 static void
ShowRawWords(uint16 * pp,uint32 n)400 ShowRawWords(uint16* pp, uint32 n)
401 {
402 	uint32 i;
403 
404 	for (i = 0; i < n; i++) {
405 		printf(" %04x", *pp++);
406 		if (((i+1) % 15) == 0)
407 			printf("\n ");
408 	}
409 	putchar('\n');
410 }
411 
412 void
TIFFReadRawData(TIFF * tif,int bitrev)413 TIFFReadRawData(TIFF* tif, int bitrev)
414 {
415 	tstrip_t nstrips = TIFFNumberOfStrips(tif);
416 	const char* what = TIFFIsTiled(tif) ? "Tile" : "Strip";
417 	uint64* stripbc=NULL;
418 
419 	TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbc);
420 	if (stripbc != NULL && nstrips > 0) {
421 		uint32 bufsize = (uint32) stripbc[0];
422 		tdata_t buf = _TIFFmalloc(bufsize);
423 		tstrip_t s;
424 
425 		for (s = 0; s < nstrips; s++) {
426 			if (stripbc[s] > bufsize) {
427 				buf = _TIFFrealloc(buf, (tmsize_t)stripbc[s]);
428 				bufsize = (uint32) stripbc[s];
429 			}
430 			if (buf == NULL) {
431 				fprintf(stderr,
432 				   "Cannot allocate buffer to read strip %lu\n",
433 				    (unsigned long) s);
434 				break;
435 			}
436 			if (TIFFReadRawStrip(tif, s, buf, (tmsize_t) stripbc[s]) < 0) {
437 				fprintf(stderr, "Error reading strip %lu\n",
438 				    (unsigned long) s);
439 				if (stoponerr)
440 					break;
441 			} else if (showdata) {
442 				if (bitrev) {
443 					TIFFReverseBits(buf, (tmsize_t)stripbc[s]);
444 					printf("%s %lu: (bit reversed)\n ",
445 					    what, (unsigned long) s);
446 				} else
447 					printf("%s %lu:\n ", what,
448 					    (unsigned long) s);
449 				if (showwords)
450 					ShowRawWords((uint16*) buf, (uint32) stripbc[s]>>1);
451 				else
452 					ShowRawBytes((unsigned char*) buf, (uint32) stripbc[s]);
453 			}
454 		}
455 		if (buf != NULL)
456 			_TIFFfree(buf);
457 	}
458 }
459 
460 static void
tiffinfo(TIFF * tif,uint16 order,long flags,int is_image)461 tiffinfo(TIFF* tif, uint16 order, long flags, int is_image)
462 {
463 	TIFFPrintDirectory(tif, stdout, flags);
464 	if (!readdata || !is_image)
465 		return;
466 	if (rawdata) {
467 		if (order) {
468 			uint16 o;
469 			TIFFGetFieldDefaulted(tif,
470 			    TIFFTAG_FILLORDER, &o);
471 			TIFFReadRawData(tif, o != order);
472 		} else
473 			TIFFReadRawData(tif, 0);
474 	} else {
475 		if (order)
476 			TIFFSetField(tif, TIFFTAG_FILLORDER, order);
477 		TIFFReadData(tif);
478 	}
479 }
480 
481 /* vim: set ts=8 sts=8 sw=8 noet: */
482 /*
483  * Local Variables:
484  * mode: c
485  * c-basic-offset: 8
486  * fill-column: 78
487  * End:
488  */
489