xref: /libtiff-4.0.7/tools/tiffcmp.c (revision d21d2b30)
1 /* $Id: tiffcmp.c,v 1.18 2015-06-21 01:09:10 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 #include <math.h>
33 
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 
38 #ifdef NEED_LIBPORT
39 # include "libport.h"
40 #endif
41 
42 #include "tiffio.h"
43 
44 #ifndef HAVE_GETOPT
45 extern int getopt(int, char**, char*);
46 #endif
47 
48 static	int stopondiff = 1;
49 static	int stoponfirsttag = 1;
50 static	uint16 bitspersample = 1;
51 static	uint16 samplesperpixel = 1;
52 static	uint16 sampleformat = SAMPLEFORMAT_UINT;
53 static	uint32 imagewidth;
54 static	uint32 imagelength;
55 
56 static	void usage(void);
57 static	int tiffcmp(TIFF*, TIFF*);
58 static	int cmptags(TIFF*, TIFF*);
59 static	int ContigCompare(int, uint32, unsigned char*, unsigned char*, tsize_t);
60 static	int SeparateCompare(int, int, uint32, unsigned char*, unsigned char*);
61 static	void PrintIntDiff(uint32, int, uint32, uint32, uint32);
62 static	void PrintFloatDiff(uint32, int, uint32, double, double);
63 
64 static	void leof(const char*, uint32, int);
65 
66 int
main(int argc,char * argv[])67 main(int argc, char* argv[])
68 {
69 	TIFF *tif1, *tif2;
70 	int c, dirnum;
71 #if !HAVE_DECL_OPTARG
72 	extern int optind;
73 	extern char* optarg;
74 #endif
75 
76 	while ((c = getopt(argc, argv, "ltz:")) != -1)
77 		switch (c) {
78 		case 'l':
79 			stopondiff = 0;
80 			break;
81 		case 'z':
82 			stopondiff = atoi(optarg);
83 			break;
84 		case 't':
85 			stoponfirsttag = 0;
86 			break;
87 		case '?':
88 			usage();
89 			/*NOTREACHED*/
90 		}
91 	if (argc - optind < 2)
92 		usage();
93 	tif1 = TIFFOpen(argv[optind], "r");
94 	if (tif1 == NULL)
95 		return (-1);
96 	tif2 = TIFFOpen(argv[optind+1], "r");
97 	if (tif2 == NULL)
98 		return (-2);
99 	dirnum = 0;
100 	while (tiffcmp(tif1, tif2)) {
101 		if (!TIFFReadDirectory(tif1)) {
102 			if (!TIFFReadDirectory(tif2))
103 				break;
104 			printf("No more directories for %s\n",
105 			    TIFFFileName(tif1));
106 			return (1);
107 		} else if (!TIFFReadDirectory(tif2)) {
108 			printf("No more directories for %s\n",
109 			    TIFFFileName(tif2));
110 			return (1);
111 		}
112 		printf("Directory %d:\n", ++dirnum);
113 	}
114 
115 	TIFFClose(tif1);
116 	TIFFClose(tif2);
117 	return (0);
118 }
119 
120 char* stuff[] = {
121 "usage: tiffcmp [options] file1 file2",
122 "where options are:",
123 " -l		list each byte of image data that differs between the files",
124 " -z #		list specified number of bytes that differs between the files",
125 " -t		ignore any differences in directory tags",
126 NULL
127 };
128 
129 static void
usage(void)130 usage(void)
131 {
132 	char buf[BUFSIZ];
133 	int i;
134 
135 	setbuf(stderr, buf);
136         fprintf(stderr, "%s\n\n", TIFFGetVersion());
137 	for (i = 0; stuff[i] != NULL; i++)
138 		fprintf(stderr, "%s\n", stuff[i]);
139 	exit(-1);
140 }
141 
142 #define	checkEOF(tif, row, sample) { \
143 	leof(TIFFFileName(tif), row, sample); \
144 	goto bad; \
145 }
146 
147 static	int CheckShortTag(TIFF*, TIFF*, int, char*);
148 static	int CheckShort2Tag(TIFF*, TIFF*, int, char*);
149 static	int CheckShortArrayTag(TIFF*, TIFF*, int, char*);
150 static	int CheckLongTag(TIFF*, TIFF*, int, char*);
151 static	int CheckFloatTag(TIFF*, TIFF*, int, char*);
152 static	int CheckStringTag(TIFF*, TIFF*, int, char*);
153 
154 static int
tiffcmp(TIFF * tif1,TIFF * tif2)155 tiffcmp(TIFF* tif1, TIFF* tif2)
156 {
157 	uint16 config1, config2;
158 	tsize_t size1;
159 	uint32 row;
160 	tsample_t s;
161 	unsigned char *buf1, *buf2;
162 
163 	if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample"))
164 		return (0);
165 	if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel"))
166 		return (0);
167 	if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth"))
168 		return (0);
169 	if (!cmptags(tif1, tif2))
170 		return (1);
171 	(void) TIFFGetField(tif1, TIFFTAG_BITSPERSAMPLE, &bitspersample);
172 	(void) TIFFGetField(tif1, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
173 	(void) TIFFGetField(tif1, TIFFTAG_SAMPLEFORMAT, &sampleformat);
174 	(void) TIFFGetField(tif1, TIFFTAG_IMAGEWIDTH, &imagewidth);
175 	(void) TIFFGetField(tif1, TIFFTAG_IMAGELENGTH, &imagelength);
176 	(void) TIFFGetField(tif1, TIFFTAG_PLANARCONFIG, &config1);
177 	(void) TIFFGetField(tif2, TIFFTAG_PLANARCONFIG, &config2);
178 	buf1 = (unsigned char *)_TIFFmalloc(size1 = TIFFScanlineSize(tif1));
179 	buf2 = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2));
180 	if (buf1 == NULL || buf2 == NULL) {
181 		fprintf(stderr, "No space for scanline buffers\n");
182 		exit(-1);
183 	}
184 	if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) {
185 		fprintf(stderr,
186 "Can't handle different planar configuration w/ different bits/sample\n");
187 		goto bad;
188 	}
189 #define	pack(a,b)	((a)<<8)|(b)
190 	switch (pack(config1, config2)) {
191 	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG):
192 		for (row = 0; row < imagelength; row++) {
193 			if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
194 				checkEOF(tif2, row, -1)
195 			for (s = 0; s < samplesperpixel; s++) {
196 				if (TIFFReadScanline(tif1, buf1, row, s) < 0)
197 					checkEOF(tif1, row, s)
198 				if (SeparateCompare(1, s, row, buf2, buf1) < 0)
199 					goto bad1;
200 			}
201 		}
202 		break;
203 	case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE):
204 		for (row = 0; row < imagelength; row++) {
205 			if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
206 				checkEOF(tif1, row, -1)
207 			for (s = 0; s < samplesperpixel; s++) {
208 				if (TIFFReadScanline(tif2, buf2, row, s) < 0)
209 					checkEOF(tif2, row, s)
210 				if (SeparateCompare(0, s, row, buf1, buf2) < 0)
211 					goto bad1;
212 			}
213 		}
214 		break;
215 	case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE):
216 		for (s = 0; s < samplesperpixel; s++)
217 			for (row = 0; row < imagelength; row++) {
218 				if (TIFFReadScanline(tif1, buf1, row, s) < 0)
219 					checkEOF(tif1, row, s)
220 				if (TIFFReadScanline(tif2, buf2, row, s) < 0)
221 					checkEOF(tif2, row, s)
222 				if (ContigCompare(s, row, buf1, buf2, size1) < 0)
223 					goto bad1;
224 			}
225 		break;
226 	case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG):
227 		for (row = 0; row < imagelength; row++) {
228 			if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
229 				checkEOF(tif1, row, -1)
230 			if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
231 				checkEOF(tif2, row, -1)
232 			if (ContigCompare(-1, row, buf1, buf2, size1) < 0)
233 				goto bad1;
234 		}
235 		break;
236 	}
237 	if (buf1) _TIFFfree(buf1);
238 	if (buf2) _TIFFfree(buf2);
239 	return (1);
240 bad:
241 	if (stopondiff)
242 		exit(1);
243 bad1:
244 	if (buf1) _TIFFfree(buf1);
245 	if (buf2) _TIFFfree(buf2);
246 	return (0);
247 }
248 
249 #define	CmpShortField(tag, name) \
250 	if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
251 #define	CmpShortField2(tag, name) \
252 	if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
253 #define	CmpLongField(tag, name) \
254 	if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
255 #define	CmpFloatField(tag, name) \
256 	if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
257 #define	CmpStringField(tag, name) \
258 	if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
259 #define	CmpShortArrayField(tag, name) \
260 	if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
261 
262 static int
cmptags(TIFF * tif1,TIFF * tif2)263 cmptags(TIFF* tif1, TIFF* tif2)
264 {
265 	uint16 compression1, compression2;
266 	CmpLongField(TIFFTAG_SUBFILETYPE,	"SubFileType");
267 	CmpLongField(TIFFTAG_IMAGEWIDTH,	"ImageWidth");
268 	CmpLongField(TIFFTAG_IMAGELENGTH,	"ImageLength");
269 	CmpShortField(TIFFTAG_BITSPERSAMPLE,	"BitsPerSample");
270 	CmpShortField(TIFFTAG_COMPRESSION,	"Compression");
271 	CmpShortField(TIFFTAG_PREDICTOR,	"Predictor");
272 	CmpShortField(TIFFTAG_PHOTOMETRIC,	"PhotometricInterpretation");
273 	CmpShortField(TIFFTAG_THRESHHOLDING,	"Thresholding");
274 	CmpShortField(TIFFTAG_FILLORDER,	"FillOrder");
275 	CmpShortField(TIFFTAG_ORIENTATION,	"Orientation");
276 	CmpShortField(TIFFTAG_SAMPLESPERPIXEL,	"SamplesPerPixel");
277 	CmpShortField(TIFFTAG_MINSAMPLEVALUE,	"MinSampleValue");
278 	CmpShortField(TIFFTAG_MAXSAMPLEVALUE,	"MaxSampleValue");
279 	CmpShortField(TIFFTAG_SAMPLEFORMAT,	"SampleFormat");
280 	CmpFloatField(TIFFTAG_XRESOLUTION,	"XResolution");
281 	CmpFloatField(TIFFTAG_YRESOLUTION,	"YResolution");
282 	if( TIFFGetField(tif1, TIFFTAG_COMPRESSION, &compression1) &&
283 		compression1 == COMPRESSION_CCITTFAX3 &&
284 		TIFFGetField(tif2, TIFFTAG_COMPRESSION, &compression2) &&
285 		compression2 == COMPRESSION_CCITTFAX3 )
286 	{
287 		CmpLongField(TIFFTAG_GROUP3OPTIONS,	"Group3Options");
288 	}
289 	if( TIFFGetField(tif1, TIFFTAG_COMPRESSION, &compression1) &&
290 		compression1 == COMPRESSION_CCITTFAX4 &&
291 		TIFFGetField(tif2, TIFFTAG_COMPRESSION, &compression2) &&
292 		compression2 == COMPRESSION_CCITTFAX4 )
293 	{
294 		CmpLongField(TIFFTAG_GROUP4OPTIONS,	"Group4Options");
295 	}
296 	CmpShortField(TIFFTAG_RESOLUTIONUNIT,	"ResolutionUnit");
297 	CmpShortField(TIFFTAG_PLANARCONFIG,	"PlanarConfiguration");
298 	CmpLongField(TIFFTAG_ROWSPERSTRIP,	"RowsPerStrip");
299 	CmpFloatField(TIFFTAG_XPOSITION,	"XPosition");
300 	CmpFloatField(TIFFTAG_YPOSITION,	"YPosition");
301 	CmpShortField(TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit");
302 	CmpShortField(TIFFTAG_COLORRESPONSEUNIT, "ColorResponseUnit");
303 #ifdef notdef
304 	{ uint16 *graycurve;
305 	  CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve);
306 	}
307 	{ uint16 *red, *green, *blue;
308 	  CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue);
309 	}
310 	{ uint16 *red, *green, *blue;
311 	  CmpField3(TIFFTAG_COLORMAP, red, green, blue);
312 	}
313 #endif
314 	CmpShortField2(TIFFTAG_PAGENUMBER,	"PageNumber");
315 	CmpStringField(TIFFTAG_ARTIST,		"Artist");
316 	CmpStringField(TIFFTAG_IMAGEDESCRIPTION,"ImageDescription");
317 	CmpStringField(TIFFTAG_MAKE,		"Make");
318 	CmpStringField(TIFFTAG_MODEL,		"Model");
319 	CmpStringField(TIFFTAG_SOFTWARE,	"Software");
320 	CmpStringField(TIFFTAG_DATETIME,	"DateTime");
321 	CmpStringField(TIFFTAG_HOSTCOMPUTER,	"HostComputer");
322 	CmpStringField(TIFFTAG_PAGENAME,	"PageName");
323 	CmpStringField(TIFFTAG_DOCUMENTNAME,	"DocumentName");
324 	CmpShortField(TIFFTAG_MATTEING,		"Matteing");
325 	CmpShortArrayField(TIFFTAG_EXTRASAMPLES,"ExtraSamples");
326 	return (1);
327 }
328 
329 static int
ContigCompare(int sample,uint32 row,unsigned char * p1,unsigned char * p2,tsize_t size)330 ContigCompare(int sample, uint32 row,
331 	      unsigned char* p1, unsigned char* p2, tsize_t size)
332 {
333     uint32 pix;
334     int ppb = 8 / bitspersample;
335     int	 samples_to_test;
336 
337     if (memcmp(p1, p2, size) == 0)
338         return 0;
339 
340     samples_to_test = (sample == -1) ? samplesperpixel : 1;
341 
342     switch (bitspersample) {
343       case 1: case 2: case 4: case 8:
344       {
345           unsigned char *pix1 = p1, *pix2 = p2;
346 
347           for (pix = 0; pix < imagewidth; pix += ppb) {
348               int		s;
349 
350               for(s = 0; s < samples_to_test; s++) {
351                   if (*pix1 != *pix2) {
352                       if( sample == -1 )
353                           PrintIntDiff(row, s, pix, *pix1, *pix2);
354                       else
355                           PrintIntDiff(row, sample, pix, *pix1, *pix2);
356                   }
357 
358                   pix1++;
359                   pix2++;
360               }
361           }
362           break;
363       }
364       case 16:
365       {
366           uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2;
367 
368           for (pix = 0; pix < imagewidth; pix++) {
369               int	s;
370 
371               for(s = 0; s < samples_to_test; s++) {
372                   if (*pix1 != *pix2)
373                       PrintIntDiff(row, sample, pix, *pix1, *pix2);
374 
375                   pix1++;
376                   pix2++;
377               }
378           }
379           break;
380       }
381       case 32:
382 	if (sampleformat == SAMPLEFORMAT_UINT
383 	    || sampleformat == SAMPLEFORMAT_INT) {
384 		uint32 *pix1 = (uint32 *)p1, *pix2 = (uint32 *)p2;
385 
386 		for (pix = 0; pix < imagewidth; pix++) {
387 			int	s;
388 
389 			for(s = 0; s < samples_to_test; s++) {
390 				if (*pix1 != *pix2) {
391 					PrintIntDiff(row, sample, pix,
392 						     *pix1, *pix2);
393 				}
394 
395 				pix1++;
396 				pix2++;
397 			}
398 		}
399 	} else if (sampleformat == SAMPLEFORMAT_IEEEFP) {
400 		float *pix1 = (float *)p1, *pix2 = (float *)p2;
401 
402 		for (pix = 0; pix < imagewidth; pix++) {
403 			int	s;
404 
405 			for(s = 0; s < samples_to_test; s++) {
406 				if (fabs(*pix1 - *pix2) < 0.000000000001) {
407 					PrintFloatDiff(row, sample, pix,
408 						       *pix1, *pix2);
409 				}
410 
411 				pix1++;
412 				pix2++;
413 			}
414 		}
415 	} else {
416 		  fprintf(stderr, "Sample format %d is not supported.\n",
417 			  sampleformat);
418 		  return -1;
419 	}
420         break;
421       default:
422 	fprintf(stderr, "Bit depth %d is not supported.\n", bitspersample);
423 	return -1;
424     }
425 
426     return 0;
427 }
428 
429 static void
PrintIntDiff(uint32 row,int sample,uint32 pix,uint32 w1,uint32 w2)430 PrintIntDiff(uint32 row, int sample, uint32 pix, uint32 w1, uint32 w2)
431 {
432 	if (sample < 0)
433 		sample = 0;
434 	switch (bitspersample) {
435 	case 1:
436 	case 2:
437 	case 4:
438 	    {
439 		int32 mask1, mask2, s;
440 
441 		mask1 =  ~((-1) << bitspersample);
442 		s = (8 - bitspersample);
443 		mask2 = mask1 << s;
444 		for (; mask2 && pix < imagewidth;
445 		     mask2 >>= bitspersample, s -= bitspersample, pix++) {
446 			if ((w1 & mask2) ^ (w2 & mask2)) {
447 				printf(
448 			"Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
449 	    				(unsigned long) row,
450 					(unsigned long) pix,
451 					sample,
452 					(unsigned int)((w1 >> s) & mask1),
453 					(unsigned int)((w2 >> s) & mask1));
454 				if (--stopondiff == 0)
455 					exit(1);
456 			}
457 		}
458 		break;
459 	    }
460 	case 8:
461 		printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
462 		       (unsigned long) row, (unsigned long) pix, sample,
463 		       (unsigned int) w1, (unsigned int) w2);
464 		if (--stopondiff == 0)
465 			exit(1);
466 		break;
467 	case 16:
468 		printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
469 		    (unsigned long) row, (unsigned long) pix, sample,
470 		    (unsigned int) w1, (unsigned int) w2);
471 		if (--stopondiff == 0)
472 			exit(1);
473 		break;
474 	case 32:
475 		printf("Scanline %lu, pixel %lu, sample %d: %08x %08x\n",
476 		    (unsigned long) row, (unsigned long) pix, sample,
477 		    (unsigned int) w1, (unsigned int) w2);
478 		if (--stopondiff == 0)
479 			exit(1);
480 		break;
481 	default:
482 		break;
483 	}
484 }
485 
486 static void
PrintFloatDiff(uint32 row,int sample,uint32 pix,double w1,double w2)487 PrintFloatDiff(uint32 row, int sample, uint32 pix, double w1, double w2)
488 {
489 	if (sample < 0)
490 		sample = 0;
491 	switch (bitspersample) {
492 	case 32:
493 		printf("Scanline %lu, pixel %lu, sample %d: %g %g\n",
494 		    (long) row, (long) pix, sample, w1, w2);
495 		if (--stopondiff == 0)
496 			exit(1);
497 		break;
498 	default:
499 		break;
500 	}
501 }
502 
503 static int
SeparateCompare(int reversed,int sample,uint32 row,unsigned char * cp1,unsigned char * p2)504 SeparateCompare(int reversed, int sample, uint32 row,
505 		unsigned char* cp1, unsigned char* p2)
506 {
507 	uint32 npixels = imagewidth;
508 	int pixel;
509 
510 	cp1 += sample;
511 	for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++) {
512 		if (*cp1 != *p2) {
513 			printf("Scanline %lu, pixel %lu, sample %ld: ",
514 			    (long) row, (long) pixel, (long) sample);
515 			if (reversed)
516 				printf("%02x %02x\n", *p2, *cp1);
517 			else
518 				printf("%02x %02x\n", *cp1, *p2);
519 			if (--stopondiff == 0)
520 				exit(1);
521 		}
522 	}
523 
524 	return 0;
525 }
526 
527 static int
checkTag(TIFF * tif1,TIFF * tif2,int tag,char * name,void * p1,void * p2)528 checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2)
529 {
530 
531 	if (TIFFGetField(tif1, tag, p1)) {
532 		if (!TIFFGetField(tif2, tag, p2)) {
533 			printf("%s tag appears only in %s\n",
534 			    name, TIFFFileName(tif1));
535 			return (0);
536 		}
537 		return (1);
538 	} else if (TIFFGetField(tif2, tag, p2)) {
539 		printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
540 		return (0);
541 	}
542 	return (-1);
543 }
544 
545 #define	CHECK(cmp, fmt) {				\
546 	switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) {	\
547 	case 1:	if (cmp)				\
548 	case -1:	return (1);			\
549 		printf(fmt, name, v1, v2);		\
550 	}						\
551 	return (0);					\
552 }
553 
554 static int
CheckShortTag(TIFF * tif1,TIFF * tif2,int tag,char * name)555 CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
556 {
557 	uint16 v1, v2;
558 	CHECK(v1 == v2, "%s: %u %u\n");
559 }
560 
561 static int
CheckShort2Tag(TIFF * tif1,TIFF * tif2,int tag,char * name)562 CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name)
563 {
564 	uint16 v11, v12, v21, v22;
565 
566 	if (TIFFGetField(tif1, tag, &v11, &v12)) {
567 		if (!TIFFGetField(tif2, tag, &v21, &v22)) {
568 			printf("%s tag appears only in %s\n",
569 			    name, TIFFFileName(tif1));
570 			return (0);
571 		}
572 		if (v11 == v21 && v12 == v22)
573 			return (1);
574 		printf("%s: <%u,%u> <%u,%u>\n", name, v11, v12, v21, v22);
575 	} else if (TIFFGetField(tif2, tag, &v21, &v22))
576 		printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
577 	else
578 		return (1);
579 	return (0);
580 }
581 
582 static int
CheckShortArrayTag(TIFF * tif1,TIFF * tif2,int tag,char * name)583 CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
584 {
585 	uint16 n1, *a1;
586 	uint16 n2, *a2;
587 
588 	if (TIFFGetField(tif1, tag, &n1, &a1)) {
589 		if (!TIFFGetField(tif2, tag, &n2, &a2)) {
590 			printf("%s tag appears only in %s\n",
591 			    name, TIFFFileName(tif1));
592 			return (0);
593 		}
594 		if (n1 == n2) {
595 			char* sep;
596 			uint16 i;
597 
598 			if (memcmp(a1, a2, n1 * sizeof(uint16)) == 0)
599 				return (1);
600 			printf("%s: value mismatch, <%u:", name, n1);
601 			sep = "";
602 			for (i = 0; i < n1; i++)
603 				printf("%s%u", sep, a1[i]), sep = ",";
604 			printf("> and <%u: ", n2);
605 			sep = "";
606 			for (i = 0; i < n2; i++)
607 				printf("%s%u", sep, a2[i]), sep = ",";
608 			printf(">\n");
609 		} else
610 			printf("%s: %u items in %s, %u items in %s", name,
611 			    n1, TIFFFileName(tif1),
612 			    n2, TIFFFileName(tif2)
613 			);
614 	} else if (TIFFGetField(tif2, tag, &n2, &a2))
615 		printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
616 	else
617 		return (1);
618 	return (0);
619 }
620 
621 static int
CheckLongTag(TIFF * tif1,TIFF * tif2,int tag,char * name)622 CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
623 {
624 	uint32 v1, v2;
625 	CHECK(v1 == v2, "%s: %u %u\n");
626 }
627 
628 static int
CheckFloatTag(TIFF * tif1,TIFF * tif2,int tag,char * name)629 CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
630 {
631 	float v1, v2;
632 	CHECK(v1 == v2, "%s: %g %g\n");
633 }
634 
635 static int
CheckStringTag(TIFF * tif1,TIFF * tif2,int tag,char * name)636 CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
637 {
638 	char *v1, *v2;
639 	CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n");
640 }
641 
642 static void
leof(const char * name,uint32 row,int s)643 leof(const char* name, uint32 row, int s)
644 {
645 
646 	printf("%s: EOF at scanline %lu", name, (unsigned long)row);
647 	if (s >= 0)
648 		printf(", sample %d", s);
649 	printf("\n");
650 }
651 
652 /* vim: set ts=8 sts=8 sw=8 noet: */
653 /*
654  * Local Variables:
655  * mode: c
656  * c-basic-offset: 8
657  * fill-column: 78
658  * End:
659  */
660