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