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