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