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