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