1 
2 /*
3  * International Color Consortium Format Library (icclib)
4  * Library Read/Write test and example code.
5  *
6  * Author:  Graeme W. Gill
7  * Date:    1999/11/29
8  * Version: 2.15
9  *
10  * Copyright 1997 - 2012 Graeme W. Gill
11  *
12  * This material is licensed with an "MIT" free use license:-
13  * see the License4.txt file in this directory for licensing details.
14  */
15 
16 /* TTBD:
17  *
18  *	Fix enums to be selected randomly (ie. header)
19  *
20  *	Should add test of ->delete_tag()
21  *	Should add test of ->rename_tag()
22  *
23  *  Add many extra comments and explanations.
24  *
25  */
26 
27 /*
28 
29 	This file is intended to serve two purposes. One
30 	is to minimally test the ability of the icc library
31 	to read and write all tag types. The other is as
32 	a source code example of how to read and write
33 	each tag type, since icc.h might otherwise take
34 	some effort to understand.
35 
36     Note XYZ scaling to 1.0, not 100.0
37 
38  */
39 
40 #define NTRIALS 100
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <fcntl.h>
46 #include <string.h>
47 #ifdef __sun
48 #include <unistd.h>
49 #endif
50 #include "icc.h"
51 
52 void error(char *fmt, ...), warning(char *fmt, ...);
53 
54 /* Rounded floating test numbers */
55 int rand_int(int low, int high);
56 unsigned int rand_o8(void), rand_o16(void), rand_o32(void);
57 double rand_8f(void), rand_L8(void), rand_ab8(void);
58 double rand_16f(void), rand_XYZ16(void), rand_u8f8(void), rand_L16(void), rand_ab16(void);
59 double rand_u16f16(void), rand_s15f16(void);
60 int dcomp(double a, double b);
61 
62 /* random ICC specific values */
63 unsigned int rand_ScreenEncodings(void);
64 unsigned int rand_DeviceAttributes(void);
65 unsigned int rand_ProfileHeaderFlags(void);
66 unsigned int rand_AsciiOrBinaryData(void);
67 icColorSpaceSignature rand_ColorSpaceSignature(void);
68 icColorSpaceSignature rand_PCS(void);
69 icTechnologySignature rand_TechnologySignature(void);
70 icProfileClassSignature rand_ProfileClassSignature(void);
71 icPlatformSignature rand_PlatformSignature(void);
72 icMeasurementFlare rand_MeasurementFlare(void);
73 icMeasurementGeometry rand_MeasurementGeometry(void);
74 icRenderingIntent rand_RenderingIntent(void);
75 icSpotShape rand_SpotShape(void);
76 icStandardObserver rand_StandardObserver(void);
77 icIlluminant rand_Illuminant(void);
78 
79 /* declare some test functions */
80 int md5_test(void);
81 
82 /*
83 	I've split the functionality up into two pieces.
84 	The main() code does the overall file write/read,
85 	while the tag type code is all in the doit() function.
86 	The write/read logic is all sandwiched together (distinguished
87 	by the state of the mode flag), so that the code for each
88 	tag type is kept adjacent.
89 
90 	In a real application, one wouldn't do it this way.
91 */
92 
93 int doit(int mode, icc *wr_icco, icc *rd_icco);
94 
95 int
main(int argc,char * argv[])96 main(
97 	int argc,
98 	char *argv[]
99 ) {
100 	char *file_name = "xxxx.icm";
101 	icmFile *wr_fp, *rd_fp;
102 	icc *wr_icco, *rd_icco;		/* Keep object separate */
103 	int rv = 0;
104 	int i;
105 	unsigned int offset = 0;	/* File write/read offset, 0 for standard icc */
106 
107 	printf("ICC library regression test, V%s\n",ICCLIB_VERSION_STR);
108 
109 	/* Do any internal code tests. */
110 
111 	if (md5_test() != 0)
112 		error ("MD5 checksum routine is faulty");
113 
114 
115 	/* Outer loop does a number of file write/reads, */
116 	/* in order to exercise random tests, and to test file offsets. */
117 
118 	for (i = 0; i < NTRIALS; i++) {
119 		unsigned int size;		/* Expected write size */
120 
121 		printf(".");
122 		fflush(stdout);
123 
124 		/* -------------------------- */
125 		/* Deal with writing the file */
126 
127 		/* Open up the file for writing */
128 		if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
129 			error ("Write: Can't open file '%s'",file_name);
130 
131 		if ((wr_icco = new_icc()) == NULL)
132 			error ("Write: Creation of ICC object failed");
133 
134 		/* Add all the tags with their tag types */
135 		if ((rv = doit(0, wr_icco, NULL)) != 0)
136 			error ("Write tags: %d, %s",rv,wr_icco->err);
137 
138 		/* Write the file (including all tags) out */
139 		/* The last parameter is the offset to write the */
140 		/* ICC profile into the file. For a standard ICC profile, */
141 		/* this needs to be 0, but it might be non-zero if you are writing */
142 		/* an embedded profile. */
143 
144 		/* Check that get_size() is working too. */
145 		if ((size = wr_icco->get_size(wr_icco)) == 0)
146 			error ("Write size: %d, %s",wr_icco->errc,wr_icco->err);
147 
148 		if ((rv = wr_icco->write(wr_icco,wr_fp,offset)) != 0)
149 			error ("Write file: %d, %s",rv,wr_icco->err);
150 
151 		/* To check that get_size() is correct: */
152 		{
153 			icmFileStd *pp = (icmFileStd *)wr_fp;	/* Cheat - Look inside icmFile */
154 
155 			if (fseek(pp->fp, 0, SEEK_END))
156 				error ("Write: seek to EOF failed");
157 			if ((unsigned int)ftell(pp->fp) != offset + size)
158 				error ("Write: get_size function didn't return correct value - got %d, expected %d",
159 				        ftell(pp->fp),offset+size);
160 		}
161 
162 		/*
163 			Would normally call wr_icco->del(wr_icco);
164 			but leave it, so that we can verify the read.
165 		*/
166 
167 		wr_fp->del(wr_fp);
168 
169 		/* -------------------------- */
170 		/* Deal with reading and verifying the file */
171 
172 		/* Open up the file for reading */
173 		if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
174 			error ("Read: Can't open file '%s'",file_name);
175 
176 		if ((rd_icco = new_icc()) == NULL)
177 			error ("Read: Creation of ICC object failed");
178 
179 		/* Read the header and tag list */
180 		/* The last parameter is the offset to read the */
181 		/* ICC profile from the file. For a standard ICC proifile, */
182 		/* this needs to be 0, but it might be non-zero if you are writing */
183 		/* an embedded profile this needs to be 0, but it might be non-zero */
184 		/* if you are writing an embedded profile. */
185 		if ((rv = rd_icco->read(rd_icco,rd_fp,offset)) != 0)
186 			error ("Read: %d, %s",rv,rd_icco->err);
187 
188 		/* Read and verify all the tags and their tag types */
189 		if ((rv = doit(1, wr_icco, rd_icco)) != 0)
190 			error ("Read: %d, %s",rv,rd_icco->err);
191 
192 		/* -------- */
193 		/* Clean up */
194 		wr_icco->del(wr_icco);
195 
196 		rd_icco->del(rd_icco);
197 		rd_fp->del(rd_fp);
198 
199 		/* choose another file offset to test */
200 		offset = rand_int(0,72789);
201 	}
202 
203 	return 0;
204 }
205 
206 /* -------------------------------------------------------------- */
207 /* Internal routine checks. */
208 
209 /* Test the MD5 function. Return nz if fail. */
md5_test()210 int md5_test() {
211 	int rv = 0;
212 	int i, j;
213 	icc *icco;
214 	icmMD5 *m;
215 
216 	unsigned char chs1[16];
217 	unsigned char chs2[16];
218 
219 	/* Standard RFC 1321 test cases */
220 	struct {
221 		char *s;
222 		ORD32 sum[4];
223 	} tc[] = {
224 		{ "",  { 0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e } },
225 		{ "a", { 0x0cc175b9, 0xc0f1b6a8, 0x31c399e2, 0x69772661 } },
226 		{ "abc", { 0x90015098, 0x3cd24fb0, 0xd6963f7d, 0x28e17f72 } },
227 		{ "message digest", { 0xf96b697d, 0x7cb7938d, 0x525a2f31, 0xaaf161d0 } },
228 		{ "abcdefghijklmnopqrstuvwxyz", { 0xc3fcd3d7, 0x6192e400, 0x7dfb496c, 0xca67e13b } },
229 		{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
230 			 { 0xd174ab98, 0xd277d9f5, 0xa5611c2c, 0x9f419d9f } },
231 		{ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
232 			 { 0x57edf4a2, 0x2be3c955, 0xac49da2e, 0x2107b67a } },
233 		{ NULL,  { 0,0,0,0 } }
234 	};
235 
236 	if ((icco = new_icc()) == NULL)
237 		error ("Creation of ICC object failed");
238 
239 	m = new_icmMD5_a(icco->al);
240 
241 	for (i = 0; ; i++) {
242 		if (tc[i].s == NULL)
243 			break;
244 
245 		m->reset(m);
246 
247 		m->add(m, (unsigned char *)tc[i].s, strlen(tc[i].s));
248 		m->get(m, chs2);
249 
250 		/* Convert reference to a byte stream */
251 		chs1[0] = (tc[i].sum[0] >> 24) & 0xff,
252 		chs1[1] = (tc[i].sum[0] >> 16) & 0xff,
253 		chs1[2] = (tc[i].sum[0] >> 8) & 0xff,
254 		chs1[3] = tc[i].sum[0] & 0xff,
255 		chs1[4] = (tc[i].sum[1] >> 24) & 0xff,
256 		chs1[5] = (tc[i].sum[1] >> 16) & 0xff,
257 		chs1[6] = (tc[i].sum[1] >> 8) & 0xff,
258 		chs1[7] = tc[i].sum[1] & 0xff,
259 		chs1[8] = (tc[i].sum[2] >> 24) & 0xff,
260 		chs1[9] = (tc[i].sum[2] >> 16) & 0xff,
261 		chs1[10] = (tc[i].sum[2] >> 8) & 0xff,
262 		chs1[11] = tc[i].sum[2] & 0xff,
263 		chs1[12] = (tc[i].sum[3] >> 24) & 0xff,
264 		chs1[13] = (tc[i].sum[3] >> 16) & 0xff,
265 		chs1[14] = (tc[i].sum[3] >> 8) & 0xff,
266 		chs1[15] = tc[i].sum[3] & 0xff;
267 
268 		for (j = 0; j < 16; j++) {
269 			if (chs1[j] != chs2[j]) {
270 				printf("MD5 check on '%s' fails at %d with:\n",tc[i].s,j);
271 				printf("Sum is    %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
272 					chs2[0], chs2[1], chs2[2], chs2[3], chs2[4], chs2[5], chs2[6], chs2[7],
273 					chs2[8], chs2[9], chs2[10], chs2[11], chs2[12], chs2[13], chs2[14], chs2[15]);
274 				printf("Should be %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
275 					chs1[0], chs1[1], chs1[2], chs1[3], chs1[4], chs1[5], chs1[6], chs1[7],
276 					chs1[8], chs1[9], chs1[10], chs1[11], chs1[12], chs1[13], chs1[14], chs1[15]);
277 				rv = 1;
278 				break;
279 			}
280 		}
281 
282 	}
283 	m->del(m);
284 	icco->del(icco);
285 
286 	return rv;
287 }
288 
289 /* -------------------------------------------------------------- */
290 /* This is the code that inits and checks the header and tag data. */
291 /* Note that to undestand this, you need a copy of the ICC profile */
292 /* spec., and a copy of the icc header file (icc34.h in this code) */
293 /* All items that begin "icXXX" are from the ICC generic icc34.h file, */
294 /* while the items that begin "icmXXX" are machine versions of structures */
295 /* that are specific to this library. */
296 
doit(int mode,icc * wr_icco,icc * rd_icco)297 int doit(
298 	int mode,		/* 0 - write, 1 = read/verify */
299 	icc *wr_icco,	/* The write icc object */
300 	icc *rd_icco	/* The read icc object */
301 ) {
302 	int rv = 0;
303 
304 	/* ----------- */
305 	/* The header: */
306 	if (mode == 0) {
307 		icmHeader *wh = wr_icco->header;
308 
309 		/* Values that must be set before writing */
310 		wh->deviceClass     = icSigAbstractClass;
311     	wh->colorSpace      = rand_ColorSpaceSignature();
312     	wh->pcs             = rand_PCS();
313     	wh->renderingIntent = rand_RenderingIntent();
314 
315 		/* Values that should be set before writing */
316 		wh->manufacturer = str2tag("tst1");
317     	wh->model        = str2tag("1234");
318     	wh->attributes.l = rand_DeviceAttributes();
319     	wh->flags = rand_ProfileHeaderFlags();
320 
321 		/* Values that may optionally be set before writing */
322     	wh->attributes.h = 0x12345678;
323     	wh->creator = str2tag("tst2");
324 
325 		/* Values that are not normally set. Set them to non-defaults for testing */
326 		wh->cmmId = str2tag("tst3");
327     	wh->majv = 2;					/* Default version 2.1.0 */
328 		wh->minv = 1;
329 		wh->bfv  = 0;
330     	wh->date.year    = rand_int(1900,3000);		/* Defaults to current date */
331     	wh->date.month   = rand_int(1,12);
332     	wh->date.day     = rand_int(1,31);
333     	wh->date.hours   = rand_int(0,23);
334     	wh->date.minutes = rand_int(0,59);
335     	wh->date.seconds = rand_int(0,59);
336     	wh->platform     = rand_PlatformSignature();
337     	wh->illuminant.X = rand_XYZ16();		/* Defaults to D50 */
338     	wh->illuminant.Y = rand_XYZ16();
339     	wh->illuminant.Z = rand_XYZ16();
340 	} else {
341 		icmHeader *rh = rd_icco->header;
342 		icmHeader *wh = wr_icco->header;
343 
344 		/* Check all the values */
345 		rv |= (rh->deviceClass != wh->deviceClass);
346     	rv |= (rh->colorSpace != wh->colorSpace);
347     	rv |= (rh->pcs != wh->pcs);
348     	rv |= (rh->renderingIntent != wh->renderingIntent);
349 		rv |= (rh->manufacturer != wh->manufacturer);
350     	rv |= (rh->model != wh->model);
351     	rv |= (rh->attributes.l != wh->attributes.l);
352     	rv |= (rh->attributes.h != wh->attributes.h);
353     	rv |= (rh->flags != wh->flags);
354     	rv |= (rh->creator != wh->creator);
355 		rv |= (rh->cmmId != wh->cmmId);
356     	rv |= (rh->majv != wh->majv);
357 		rv |= (rh->minv != wh->minv);
358 		rv |= (rh->bfv != wh->bfv);
359     	rv |= (rh->date.year != wh->date.year);
360     	rv |= (rh->date.month != wh->date.month);
361     	rv |= (rh->date.day != wh->date.day);
362     	rv |= (rh->date.hours != wh->date.hours);
363     	rv |= (rh->date.minutes != wh->date.minutes);
364     	rv |= (rh->date.seconds != wh->date.seconds);
365     	rv |= (rh->platform != wh->platform);
366     	rv |= dcomp(rh->illuminant.X, wh->illuminant.X);
367     	rv |= dcomp(rh->illuminant.Y, wh->illuminant.Y);
368     	rv |= dcomp(rh->illuminant.Z, wh->illuminant.Z);
369 		if (rv)
370 			error ("Header verify failed");
371 	}
372 	/* ------------- */
373 	/* CrdInfo info: */
374 	{
375 	char *str1 = "Product Name";
376 	char *str2[4] = { "Intent zero CRD Name",
377 	                  "Intent one CRD Name",
378 	                  "Intent two CRD Name",
379 	                  "Intent three CRD Name" };
380 	static icmCrdInfo *wo;
381 	if (mode == 0) {
382 		unsigned int i;
383 		if ((wo = (icmCrdInfo *)wr_icco->add_tag(
384 		           wr_icco, icSigCrdInfoTag, icSigCrdInfoType)) == NULL)
385 			return 1;
386 
387 		wo->ppsize = strlen(str1)+1; 			/* Allocated and used size of text, inc null */
388 		for (i = 0; i < 4; i++)
389 			wo->crdsize[i] = strlen(str2[i])+1;	/* Allocated and used size of text, inc null */
390 
391 		wo->allocate((icmBase *)wo);			/* Allocate space */
392 		/* Note we could allocate and copy as we go, rather than doing them all at once. */
393 
394 		strcpy(wo->ppname, str1);				/* Copy the text in */
395 		for (i = 0; i < 4; i++)
396 			strcpy(wo->crdname[i], str2[i]);	/* Copy the text in */
397 	} else {
398 		icmCrdInfo *ro;
399 		unsigned int i;
400 
401 		/* Try and read the tag from the file */
402 		ro = (icmCrdInfo *)rd_icco->read_tag(rd_icco, icSigCrdInfoTag);
403 		if (ro == NULL)
404 			return 1;
405 
406 		/* Need to check that the cast is appropriate. */
407 		if (ro->ttype != icSigCrdInfoType)
408 			return 1;
409 
410 		/* Now check it out */
411 		if (ro->ppsize != wo->ppsize)
412 		for (i = 0; i < 4; i++) {
413 			if (ro->crdsize[i] != wo->crdsize[i])
414 				error ("CrdInfo crdsize[%d] doesn't match",i);
415 		}
416 
417 		rv |= strcmp(ro->ppname, wo->ppname);
418 		for (i = 0; i < 4; i++) {
419 			rv |= strcmp(ro->crdname[i], wo->crdname[i]);
420 		}
421 
422 		if (rv)
423 			error ("CrdInfo verify failed");
424 	}
425 	}
426 	/* ---------------------- */
427 	/* Curve - Linear version */
428 	{
429 	static icmCurve *wo;
430 	if (mode == 0) {
431 		if ((wo = (icmCurve *)wr_icco->add_tag(
432 		           wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL)
433 			return 1;
434 
435 		wo->flag = icmCurveLin; 	/* Linear version */
436 		wo->allocate((icmBase *)wo);/* Allocate space */
437 	} else {
438 		icmCurve *ro;
439 
440 		/* Try and read the tag from the file */
441 		ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigRedTRCTag);
442 		if (ro == NULL)
443 			return 1;
444 
445 		/* Need to check that the cast is appropriate. */
446 		if (ro->ttype != icSigCurveType)
447 			return 1;
448 
449 		/* Now check it out */
450 		if (ro->flag != wo->flag)
451 			error ("Curve flag doesn't match for Linear");
452 
453 		if (ro->size != wo->size)
454 			error ("Curve size doesn't match");
455 
456 		if (rv)
457 			error ("Curve verify failed");
458 	}
459 	}
460 	/* --------------------- */
461 	/* Curve - Gamma version */
462 	{
463 	static icmCurve *wo;
464 	if (mode == 0) {
465 		if ((wo = (icmCurve *)wr_icco->add_tag(
466 		           wr_icco, icSigGreenTRCTag, icSigCurveType)) == NULL)
467 			return 1;
468 
469 		wo->flag = icmCurveGamma; 		/* Gamma version */
470 		wo->allocate((icmBase *)wo);	/* Allocate space */
471 		wo->data[0] = rand_u8f8();		/* Gamma value */
472 	} else {
473 		icmCurve *ro;
474 
475 		/* Try and read the tag from the file */
476 		ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigGreenTRCTag);
477 		if (ro == NULL)
478 			return 1;
479 
480 		/* Need to check that the cast is appropriate. */
481 		if (ro->ttype != icSigCurveType)
482 			return 1;
483 
484 		/* Now check it out */
485 		if (ro->flag != wo->flag)
486 			error ("Curve flag doesn't match for Gamma");
487 
488 		if (ro->size != wo->size)
489 			error ("Curve size doesn't match");
490 
491 		rv |= dcomp(ro->data[0], wo->data[0]);
492 
493 		if (rv)
494 			error ("Curve verify failed");
495 	}
496 	}
497 	/* ------------------------- */
498 	/* Curve - Specified version */
499 	{
500 	static icmCurve *wo;
501 	if (mode == 0) {
502 		unsigned int i;
503 		if ((wo = (icmCurve *)wr_icco->add_tag(
504 		           wr_icco, icSigBlueTRCTag, icSigCurveType)) == NULL)
505 			return 1;
506 
507 		wo->flag = icmCurveSpec; 	/* Specified version */
508 		wo->size = rand_int(2,23);	/* Number of entries (min must be 2!) */
509 		wo->allocate((icmBase *)wo);/* Allocate space */
510 		for (i = 0; i < wo->size; i++)
511 			wo->data[i] = rand_16f();	/* Curve values 0.0 - 1.0 */
512 	} else {
513 		icmCurve *ro;
514 		unsigned int i;
515 
516 		/* Try and read the tag from the file */
517 		ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigBlueTRCTag);
518 		if (ro == NULL)
519 			return 1;
520 
521 		/* Need to check that the cast is appropriate. */
522 		if (ro->ttype != icSigCurveType)
523 			return 1;
524 
525 		/* Now check it out */
526 		if (ro->flag != wo->flag)
527 			error ("Curve flag doesn't match for specified");
528 
529 		if (ro->size != wo->size)
530 			error ("Curve size doesn't match");
531 
532 		for (i = 0; i < wo->size; i++)
533 			rv |= dcomp(ro->data[i], wo->data[i]);
534 
535 		if (rv)
536 			error ("Curve verify failed");
537 	}
538 	}
539 	/* ------------------- */
540 	/* Data - text version */
541 	{
542 	static icmData *wo;
543 	char *ts1 = "This is a data string";
544 	if (mode == 0) {
545 		if ((wo = (icmData *)wr_icco->add_tag(
546 		           wr_icco, icSigPs2CRD0Tag,	icSigDataType)) == NULL)
547 			return 1;
548 
549 		wo->flag = icmDataASCII;	/* Holding ASCII data */
550 		wo->size = strlen(ts1)+1; 	/* Allocated and used size of text, inc null */
551 		wo->allocate((icmBase *)wo);/* Allocate space */
552 		strcpy((char *)wo->data, ts1);		/* Copy the text in */
553 	} else {
554 		icmData *ro;
555 
556 		/* Try and read the tag from the file */
557 		ro = (icmData *)rd_icco->read_tag(rd_icco, icSigPs2CRD0Tag);
558 		if (ro == NULL)
559 			return 1;
560 
561 		/* Need to check that the cast is appropriate. */
562 		if (ro->ttype != icSigDataType)
563 			return 1;
564 
565 		/* Now check it out */
566 		if (ro->flag != wo->flag)
567 			error ("Data size doesn't match");
568 
569 		if (ro->size != wo->size)
570 			error ("Data size doesn't match");
571 
572 		rv |= strcmp((char *)ro->data, (char *)wo->data);
573 
574 		if (rv)
575 			error ("Data verify failed");
576 	}
577 	}
578 	/* --------------------- */
579 	/* Data - Binary version */
580 	{
581 	static icmData *wo;
582 	if (mode == 0) {
583 		unsigned int i;
584 		if ((wo = (icmData *)wr_icco->add_tag(
585 		           wr_icco, icSigPs2CRD1Tag,	icSigDataType)) == NULL)
586 			return 1;
587 
588 		wo->flag = icmDataBin;		/* Holding binary data */
589 		wo->size = rand_int(0,43);	/* Space we need for data */
590 		wo->allocate((icmBase *)wo);/* Allocate space */
591 		for (i = 0; i < wo->size; i ++)
592 			wo->data[i] = rand_o8();
593 	} else {
594 		icmData *ro;
595 		unsigned int i;
596 
597 		/* Try and read the tag from the file */
598 		ro = (icmData *)rd_icco->read_tag(rd_icco, icSigPs2CRD1Tag);
599 		if (ro == NULL)
600 			return 1;
601 
602 		/* Need to check that the cast is appropriate. */
603 		if (ro->ttype != icSigDataType)
604 			return 1;
605 
606 		/* Now check it out */
607 		if (ro->flag != wo->flag)
608 			error ("Data size doesn't match");
609 
610 		if (ro->size != wo->size)
611 			error ("Data size doesn't match");
612 
613 		for (i = 0; i < wo->size; i++)
614 			rv |= (ro->data[i] != wo->data[i]);
615 
616 		if (rv)
617 			error ("Data verify failed");
618 	}
619 	}
620 	/* --------- */
621 	/* DateTime: */
622 	{
623 	static icmDateTimeNumber *wo;
624 	if (mode == 0) {
625 		if ((wo = (icmDateTimeNumber *)wr_icco->add_tag(
626 		           wr_icco, icSigCalibrationDateTimeTag, icSigDateTimeType)) == NULL)
627 			return 1;
628 
629     	wo->year = rand_int(1900, 3000);
630     	wo->month = rand_int(1, 12);
631     	wo->day = rand_int(1, 31);
632     	wo->hours = rand_int(0, 23);
633     	wo->minutes = rand_int(0, 59);
634     	wo->seconds = rand_int(0, 59);
635 	} else {
636 		icmDateTimeNumber *ro;
637 
638 		/* Try and read the tag from the file */
639 		ro = (icmDateTimeNumber *)rd_icco->read_tag(rd_icco, icSigCalibrationDateTimeTag);
640 		if (ro == NULL)
641 			return 1;
642 
643 		/* Need to check that the cast is appropriate. */
644 		if (ro->ttype != icSigDateTimeType)
645 			return 1;
646 
647 		/* Now check it out */
648     	rv |= (ro->year    != wo->year);
649     	rv |= (ro->month   != wo->month);
650     	rv |= (ro->day     != wo->day);
651     	rv |= (ro->hours   != wo->hours);
652     	rv |= (ro->minutes != wo->minutes);
653     	rv |= (ro->seconds != wo->seconds);
654 
655 		if (rv)
656 			error ("DateTime verify failed");
657 	}
658 	}
659 	/* ----------- */
660 	/* 16 bit lut: */
661 	{
662 	static icmLut *wo;
663 	if (mode == 0) {
664 		unsigned int i, j, k;
665 		if ((wo = (icmLut *)wr_icco->add_tag(
666 		           wr_icco, icSigAToB0Tag,	icSigLut16Type)) == NULL)
667 			return 1;
668 
669 		wo->inputChan = 2;
670 		wo->outputChan = 3;
671     	wo->clutPoints = 5;
672     	wo->inputEnt = 56;
673     	wo->outputEnt = 73;
674 		wo->allocate((icmBase *)wo);/* Allocate space */
675 
676 		/* The matrix is only applicable to XYZ input space */
677 		for (i = 0; i < 3; i++)							/* Matrix */
678 			for (j = 0; j < 3; j++)
679 				wo->e[i][j] = rand_s15f16();
680 
681 		/* See icc.getNormFuncs() for normalizing functions */
682 		/* The input table index range is over the normalized range 0.0 - 1.0. */
683 		/* The range in input color space can be determined by denormalizing */
684 		/* the values 0.0 - 1.0. */
685 		for (i = 0; i < wo->inputChan; i++)				/* Input tables */
686 			for (j = 0; j < wo->inputEnt; j++)
687 				wo->inputTable[i * wo->inputEnt + j] = rand_16f();
688 
689 														/* Lut */
690 		/* The multidimentional lut has a normalized index range */
691 		/* of 0.0 - 1.0 in each dimension. Its entry values are also */
692 		/* normalized values in the range 0.0 - 1.0. */
693 		for (i = 0; i < wo->clutPoints; i++)			/* Input chan 0 - slow changing */
694 			for (j = 0; j < wo->clutPoints; j++)		/* Input chan 1 - faster changing */
695 				for (k = 0; k < wo->outputChan; k++)	/* Output chans */
696 					wo->clutTable[(i * wo->clutPoints + j) * wo->outputChan + k] = rand_16f();
697 
698 		/* The output color space values should be normalized to the */
699 		/* range 0.0 - 1.0 for use as output table entry values. */
700 		for (i = 0; i < wo->outputChan; i++)			/* Output tables */
701 			for (j = 0; j < wo->outputEnt; j++)
702 				wo->outputTable[i * wo->outputEnt + j] = rand_16f();
703 
704 	} else {
705 		icmLut *ro;
706 		unsigned int size;
707 		unsigned int i, j;
708 
709 		/* Try and read the tag from the file */
710 		ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB0Tag);
711 		if (ro == NULL)
712 			return 1;
713 
714 		/* Need to check that the cast is appropriate. */
715 		if (ro->ttype != icSigLut16Type)
716 			return 1;
717 
718 		/* Now check it out */
719 		rv |= (ro->inputChan != wo->inputChan);
720 		rv |= (ro->outputChan != wo->outputChan);
721     	rv |= (ro->clutPoints != wo->clutPoints);
722     	rv |= (ro->inputEnt != wo->inputEnt);
723     	rv |= (ro->outputEnt != wo->outputEnt);
724 
725 		for (i = 0; i < 3; i++)
726 			for (j = 0; j < 3; j++)
727 				rv |= dcomp(ro->e[i][j], wo->e[i][j]);
728 
729 		size = (wo->inputChan * wo->inputEnt);
730 		for (i = 0; i < size; i++)
731 			rv |= dcomp(ro->inputTable[i], wo->inputTable[i]);
732 
733 		size = wo->outputChan;
734 		for (i = 0; i < wo->inputChan; i++)
735 			size *= wo->clutPoints;
736 		for (i = 0; i < size; i++)
737 			rv |= dcomp(ro->clutTable[i], wo->clutTable[i]);
738 
739 		size = (wo->outputChan * wo->outputEnt);
740 		for (i = 0; i < size; i++)
741 			rv |= dcomp(ro->outputTable[i], wo->outputTable[i]);
742 		if (rv)
743 			error ("Lut16 verify failed");
744 	}
745 	}
746 	/* ------------------ */
747 	/* 16 bit lut - link: */
748 	{
749 	static icmLut *wo;
750 	if (mode == 0) {
751 		/* Just link to the existing LUT. This is often used when there */
752 		/* is no distinction between intents, and saves file and memory space. */
753 		if ((wo = (icmLut *)wr_icco->link_tag(
754 		           wr_icco, icSigAToB1Tag,	icSigAToB0Tag)) == NULL)
755 			return 1;
756 	} else {
757 		icmLut *ro;
758 		unsigned int size;
759 		unsigned int i;
760 
761 		/* Try and read the tag from the file */
762 		ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB1Tag);
763 		if (ro == NULL)
764 			return 1;
765 
766 		/* Need to check that the cast is appropriate. */
767 		if (ro->ttype != icSigLut16Type)
768 			return 1;
769 
770 		/* Now check it out */
771 		rv |= (ro->inputChan != wo->inputChan);
772 		rv |= (ro->outputChan != wo->outputChan);
773     	rv |= (ro->clutPoints != wo->clutPoints);
774     	rv |= (ro->inputEnt != wo->inputEnt);
775     	rv |= (ro->outputEnt != wo->outputEnt);
776 
777 		size = (wo->inputChan * wo->inputEnt);
778 		for (i = 0; i < size; i++)
779 			rv |= (ro->inputTable[i] != wo->inputTable[i]);
780 
781 		size = wo->outputChan;
782 		for (i = 0; i < wo->inputChan; i++)
783 			size *= wo->clutPoints;
784 		for (i = 0; i < size; i++)
785 			rv |= (ro->clutTable[i] != wo->clutTable[i]);
786 
787 		size = (wo->outputChan * wo->outputEnt);
788 		for (i = 0; i < size; i++)
789 			rv |= (ro->outputTable[i] != wo->outputTable[i]);
790 		if (rv)
791 			error ("Lut16 link verify failed");
792 	}
793 	}
794 	/* ---------- */
795 	/* 8 bit lut: */
796 	{
797 	static icmLut *wo;
798 	if (mode == 0) {
799 		unsigned int i, j, m, k;
800 		if ((wo = (icmLut *)wr_icco->add_tag(
801 		           wr_icco, icSigAToB2Tag,	icSigLut8Type)) == NULL)
802 			return 1;
803 
804 		wo->inputChan = 3;
805 		wo->outputChan = 2;
806     	wo->clutPoints = 4;
807     	wo->inputEnt = 256;			/* Must be 256 for Lut8 */
808     	wo->outputEnt = 256;
809 		wo->allocate((icmBase *)wo);/* Allocate space */
810 
811 		for (i = 0; i < 3; i++)						/* Matrix */
812 			for (j = 0; j < 3; j++)
813 				wo->e[i][j] = rand_s15f16();
814 
815 		for (i = 0; i < wo->inputChan; i++)			/* Input tables */
816 			for (j = 0; j < wo->inputEnt; j++)
817 				wo->inputTable[i * wo->inputEnt + j] = rand_8f();
818 
819 													/* Lut */
820 		for (i = 0; i < wo->clutPoints; i++)				/* Input chan 0 */
821 			for (j = 0; j < wo->clutPoints; j++)			/* Input chan 1 */
822 				for (m = 0; m < wo->clutPoints; m++)		/* Input chan 2 */
823 					for (k = 0; k < wo->outputChan; k++) {	/* Output chans */
824 						int idx = ((i * wo->clutPoints + j)
825 						              * wo->clutPoints + m)
826 						              * wo->outputChan + k;
827 						wo->clutTable[idx] = rand_8f();
828 						}
829 
830 		for (i = 0; i < wo->outputChan; i++)		/* Output tables */
831 			for (j = 0; j < wo->outputEnt; j++)
832 				wo->outputTable[i * wo->outputEnt + j] = rand_8f();
833 
834 	} else {
835 		icmLut *ro;
836 		unsigned int size;
837 		unsigned int i, j;
838 
839 		/* Try and read the tag from the file */
840 		ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB2Tag);
841 		if (ro == NULL)
842 			return 1;
843 
844 		/* Need to check that the cast is appropriate. */
845 		if (ro->ttype != icSigLut8Type)
846 			return 1;
847 
848 		/* Now check it out */
849 		rv |= (ro->inputChan != wo->inputChan);
850 		rv |= (ro->outputChan != wo->outputChan);
851     	rv |= (ro->clutPoints != wo->clutPoints);
852     	rv |= (ro->inputEnt != wo->inputEnt);
853     	rv |= (ro->outputEnt != wo->outputEnt);
854 
855 		for (i = 0; i < 3; i++)
856 			for (j = 0; j < 3; j++)
857 				rv |= dcomp(ro->e[i][j], wo->e[i][j]);
858 
859 		size = (wo->inputChan * wo->inputEnt);
860 		for (i = 0; i < size; i++)
861 			rv |= dcomp(ro->inputTable[i], wo->inputTable[i]);
862 
863 		size = wo->outputChan;
864 		for (i = 0; i < wo->inputChan; i++)
865 			size *= wo->clutPoints;
866 		for (i = 0; i < size; i++)
867 			rv |= dcomp(ro->clutTable[i], wo->clutTable[i]);
868 
869 		size = (wo->outputChan * wo->outputEnt);
870 		for (i = 0; i < size; i++)
871 			rv |= dcomp(ro->outputTable[i], wo->outputTable[i]);
872 		if (rv)
873 			error ("Lut8 verify failed");
874 	}
875 	}
876 	/* ----------------- */
877 	/* Measurement: */
878 	{
879 	static icmMeasurement *wo;
880 	if (mode == 0) {
881 		if ((wo = (icmMeasurement *)wr_icco->add_tag(
882 		           wr_icco, icSigMeasurementTag, icSigMeasurementType)) == NULL)
883 			return 1;
884 
885 		/* Standard observer */
886 		switch(rand_int(0,2)) {
887 			case 0:
888 	    		wo->observer = icStdObsUnknown;
889 				break;
890 			case 1:
891 	    		wo->observer = icStdObs1931TwoDegrees;
892 				break;
893 			case 2:
894 	    		wo->observer = icStdObs1964TenDegrees;
895 				break;
896 		}
897 
898 		/* XYZ for backing color */
899     	wo->backing.X = rand_XYZ16();
900     	wo->backing.Y = rand_XYZ16();
901     	wo->backing.Z = rand_XYZ16();
902 
903 	    /* Measurement geometry */
904 		switch(rand_int(0,2)) {
905 			case 0:
906     			wo->geometry = icGeometryUnknown;
907 				break;
908 			case 1:
909     			wo->geometry = icGeometry045or450;
910 				break;
911 			case 2:
912     			wo->geometry = icGeometry0dord0;
913 				break;
914 		}
915 
916 	    /* Measurement flare */
917 		wo->flare = rand_u16f16();
918 
919 	    /* Illuminant */
920 		switch(rand_int(0,8)) {
921 			case 0:
922     			wo->illuminant = icIlluminantUnknown;
923 				break;
924 			case 1:
925     			wo->illuminant = icIlluminantD50;
926 				break;
927 			case 2:
928     			wo->illuminant = icIlluminantD65;
929 				break;
930 			case 3:
931     			wo->illuminant = icIlluminantD93;
932 				break;
933 			case 4:
934     			wo->illuminant = icIlluminantF2;
935 				break;
936 			case 5:
937     			wo->illuminant = icIlluminantD55;
938 				break;
939 			case 6:
940     			wo->illuminant = icIlluminantA;
941 				break;
942 			case 7:
943     			wo->illuminant = icIlluminantEquiPowerE;
944 				break;
945 			case 8:
946     			wo->illuminant = icIlluminantF8;
947 				break;
948 			}
949 	} else {
950 		icmMeasurement *ro;
951 
952 		/* Try and read the tag from the file */
953 		ro = (icmMeasurement *)rd_icco->read_tag(rd_icco, icSigMeasurementTag);
954 		if (ro == NULL)
955 			return 1;
956 
957 		/* Need to check that the cast is appropriate. */
958 		if (ro->ttype != icSigMeasurementType)
959 			return 1;
960 
961 		/* Now check it out */
962 	    rv |= (ro->observer   != wo->observer);
963     	rv |= dcomp(ro->backing.X, wo->backing.X);
964     	rv |= dcomp(ro->backing.Y, wo->backing.Y);
965     	rv |= dcomp(ro->backing.Z, wo->backing.Z);
966 		rv |= (ro->geometry   != wo->geometry);
967     	rv |= dcomp(ro->flare, wo->flare);
968     	rv |= (ro->illuminant != wo->illuminant);
969 
970 		if (rv)
971 			error ("Measurement verify failed");
972 	}
973 	}
974 	/* ----------------- */
975 	/* Old style NamedColor: */
976 	{
977 	static icmNamedColor *wo;
978 	if (mode == 0) {
979 		unsigned int i;
980 		if ((wo = (icmNamedColor *)wr_icco->add_tag(
981 		           wr_icco, icSigNamedColorTag, icSigNamedColorType)) == NULL)
982 			return 1;
983 
984    		wo->vendorFlag = rand_int(0,65535) << 16;	/* Bottom 16 bits for IC use */
985    		wo->count = 3;			/* Count of named colors */
986 		strcpy(wo->prefix,"Prefix"); /* Prefix for each color name, max 32, null terminated */
987 		strcpy(wo->suffix,"Suffix"); /* Suffix for each color name, max 32, null terminated */
988 
989 		wo->allocate((icmBase *)wo);	/* Allocate named color structures */
990 
991 		for (i = 0; i < wo->count; i++) {
992 			unsigned int j;
993 			sprintf(wo->data[i].root,"Color %d",i); /* Root name, max 32, null terminated */
994 			for (j = 0; j < wo->nDeviceCoords; j++)	/* nDeviceCoords defaults appropriately */
995 				wo->data[i].deviceCoords[j] = rand_8f(); /* Device coords of color */
996 		}
997 	} else {
998 		icmNamedColor *ro;
999 		unsigned int i;
1000 
1001 		/* Try and read the tag from the file */
1002 		ro = (icmNamedColor *)rd_icco->read_tag(rd_icco, icSigNamedColorTag);
1003 		if (ro == NULL)
1004 			return 1;
1005 
1006 		/* Need to check that the cast is appropriate. */
1007 		if (ro->ttype != icSigNamedColorType)
1008 			return 1;
1009 
1010 		/* Now check it out */
1011    		rv |= (ro->vendorFlag != wo->vendorFlag);
1012     	rv |= (ro->count != wo->count);
1013     	rv |= (ro->nDeviceCoords != wo->nDeviceCoords);
1014 		rv |= strcmp(ro->prefix, wo->prefix);
1015 		rv |= strcmp(ro->suffix, wo->suffix);
1016 
1017 		if (rv)
1018 			error ("NamedColor verify failed");
1019 
1020 		for (i = 0; i < wo->count; i++) {
1021 			unsigned int j;
1022 			rv |= strcmp(ro->data[i].root, wo->data[i].root);
1023 			for (j = 0; j < wo->nDeviceCoords; j++)
1024 				rv |= dcomp(ro->data[i].deviceCoords[j], wo->data[i].deviceCoords[j]);
1025 		}
1026 
1027 		if (rv)
1028 			error ("NamedColor verify failed");
1029 	}
1030 	}
1031 	/* ----------------- */
1032 	/* NamedColor2: */
1033 	{
1034 	static icmNamedColor *wo;	/* Shares same machine specific structure */
1035 	if (mode == 0) {
1036 		unsigned int i;
1037 		if ((wo = (icmNamedColor *)wr_icco->add_tag(
1038 		           wr_icco, icSigNamedColor2Tag, icSigNamedColor2Type)) == NULL)
1039 			return 1;
1040 
1041    		wo->vendorFlag = rand_int(0,65535) << 16;	/* Bottom 16 bits for ICC use */
1042    		wo->count = 4;			/* Count of named colors */
1043    		wo->nDeviceCoords =	3;	/* Num of device coordinates */
1044 		         /* Could set this different to that implied by wr_icco->header->colorSpace */
1045 		strcpy(wo->prefix,"Prefix-ix"); /* Prefix for each color name, max 32, null terminated */
1046 		strcpy(wo->suffix,"Suffix-ixix"); /* Suffix for each color name, max 32, null terminated */
1047 
1048 		wo->allocate((icmBase *)wo);	/* Allocate named color structures */
1049 
1050 		for (i = 0; i < wo->count; i++) {
1051 			unsigned int j;
1052 			sprintf(wo->data[i].root,"Pigment %d",i); /* Root name, max 32, null terminated */
1053 			for (j = 0; j < wo->nDeviceCoords; j++)
1054 				wo->data[i].deviceCoords[j] = rand_8f(); /* Device coords of color */
1055 			switch(wo->icp->header->pcs) {
1056 				case icSigXYZData:
1057 						wo->data[i].pcsCoords[0] = rand_XYZ16();
1058 						wo->data[i].pcsCoords[1] = rand_XYZ16();
1059 						wo->data[i].pcsCoords[2] = rand_XYZ16();
1060 					break;
1061 			   	case icSigLabData:
1062 						wo->data[i].pcsCoords[0] = rand_L16();
1063 						wo->data[i].pcsCoords[1] = rand_ab16();
1064 						wo->data[i].pcsCoords[2] = rand_ab16();
1065 					break;
1066 				default:
1067 					break;
1068 			}
1069 		}
1070 	} else {
1071 		icmNamedColor *ro;
1072 		unsigned int i;
1073 
1074 		/* Try and read the tag from the file */
1075 		ro = (icmNamedColor *)rd_icco->read_tag(rd_icco, icSigNamedColor2Tag);
1076 		if (ro == NULL)
1077 			return 1;
1078 
1079 		/* Need to check that the cast is appropriate. */
1080 		if (ro->ttype != icSigNamedColor2Type)
1081 			return 1;
1082 
1083 		/* Now check it out */
1084    		rv |= (ro->vendorFlag != wo->vendorFlag);
1085     	rv |= (ro->count != wo->count);
1086     	rv |= (ro->nDeviceCoords != wo->nDeviceCoords);
1087 		rv |= strcmp(ro->prefix, wo->prefix);
1088 		rv |= strcmp(ro->suffix, wo->suffix);
1089 
1090 		if (rv)
1091 			error ("NamedColor2 verify failed");
1092 
1093 		for (i = 0; i < wo->count; i++) {
1094 			unsigned int j;
1095 			rv |= strcmp(ro->data[i].root, wo->data[i].root);
1096 			for (j = 0; j < wo->nDeviceCoords; j++)
1097 				rv |= dcomp(ro->data[i].deviceCoords[j], wo->data[i].deviceCoords[j]);
1098 			for (j = 0; j < 3; j++) {
1099 				rv |= dcomp(ro->data[i].pcsCoords[j], wo->data[i].pcsCoords[j]);
1100 			}
1101 		}
1102 
1103 		if (rv)
1104 			error ("NamedColor2 verify failed");
1105 	}
1106 	}
1107 	/* ----------------- */
1108 	/* ColorantTable: */
1109 	{
1110 	static icmColorantTable *wo;
1111 	if (mode == 0) {
1112 		unsigned int i;
1113 		if ((wo = (icmColorantTable *)wr_icco->add_tag(
1114 		           wr_icco, icSigColorantTableTag, icSigColorantTableType)) == NULL)
1115 			return 1;
1116 
1117    		wo->count = 4;			/* Count of colorants - should be same as implied by device space */
1118 		wo->allocate((icmBase *)wo);	/* Allocate ColorantTable structures */
1119 
1120 		for (i = 0; i < wo->count; i++) {
1121 			sprintf(wo->data[i].name,"Color %d",i); /* Colorant name, max 32, null terminated */
1122 			switch(wo->icp->header->pcs) {
1123 				case icSigXYZData:
1124 						wo->data[i].pcsCoords[0] = rand_XYZ16();
1125 						wo->data[i].pcsCoords[1] = rand_XYZ16();
1126 						wo->data[i].pcsCoords[2] = rand_XYZ16();
1127 					break;
1128 			   	case icSigLabData:
1129 						wo->data[i].pcsCoords[0] = rand_L16();
1130 						wo->data[i].pcsCoords[1] = rand_ab16();
1131 						wo->data[i].pcsCoords[2] = rand_ab16();
1132 					break;
1133 				default:
1134 					break;
1135 			}
1136 		}
1137 	} else {
1138 		icmColorantTable *ro;
1139 		unsigned int i;
1140 
1141 		/* Try and read the tag from the file */
1142 		ro = (icmColorantTable *)rd_icco->read_tag(rd_icco, icSigColorantTableTag);
1143 		if (ro == NULL)
1144 			return 1;
1145 
1146 		/* Need to check that the cast is appropriate. */
1147 		if (ro->ttype != icSigColorantTableType)
1148 			return 1;
1149 
1150 		/* Now check it out */
1151     	rv |= (ro->count != wo->count);
1152 
1153 		if (rv)
1154 			error ("ColorantTable verify failed");
1155 
1156 		for (i = 0; i < wo->count; i++) {
1157 			int j;
1158 			rv |= strcmp(ro->data[i].name, wo->data[i].name);
1159 			for (j = 0; j < 3; j++) {
1160 				rv |= dcomp(ro->data[i].pcsCoords[j], wo->data[i].pcsCoords[j]);
1161 			}
1162 		}
1163 
1164 		if (rv)
1165 			error ("ColorantTable verify failed");
1166 	}
1167 	}
1168 	/* ----------------- */
1169 	/* ProfileSequenceDescTag: */
1170 	{
1171 	unsigned short ts2a[29] = {'T','h','i','s',' ','i','s',' ','a',' ','d','e','v','i','c','e',
1172 	                          ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000};
1173 	unsigned short ts2b[28] = {'T','h','i','s',' ','i','s',' ','a',' ','m','o','d','e','l',
1174 	                          ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000};
1175 	char *ts3a = "This is a device description";
1176 	char *ts3b = "This is a model description";
1177 	static icmProfileSequenceDesc*wo;
1178 	if (mode == 0) {
1179 		unsigned int i;
1180 		if ((wo = (icmProfileSequenceDesc *)wr_icco->add_tag(
1181 		           wr_icco, icSigProfileSequenceDescTag, icSigProfileSequenceDescType)) == NULL)
1182 			return 1;
1183 
1184 		wo->count = 3; 		/* Number of descriptions in sequence */
1185 		wo->allocate((icmBase *)wo);	/* Allocate space for all the DescStructures */
1186 
1187 		/* Fill in each description structure in sequence */
1188 		for (i = 0; i < wo->count; i++) {
1189 			char ts1[100];
1190 			wo->data[i].deviceMfg   = str2tag("mfg7");
1191 			wo->data[i].deviceModel = str2tag("2345");
1192 			wo->data[i].attributes.l = icTransparency | icMatte;
1193 			wo->data[i].attributes.h = 0x98765432;
1194 			wo->data[i].technology = rand_TechnologySignature();
1195 
1196 			/* device Text description */
1197 			sprintf(ts1,"This is device descrption %d",i);
1198 			wo->data[i].device.size = strlen(ts1)+1;
1199 			wo->data[i].allocate(&wo->data[i]); 		/* Allocate space */
1200 			strcpy(wo->data[i].device.desc, ts1);		/* Copy the string in */
1201 
1202 			/* We'll fudge up the Unicode string */
1203 			wo->data[i].device.ucLangCode = 8765;		/* UniCode language code */
1204 			wo->data[i].device.ucSize = 29;				/* Size in chars inc null */
1205 			wo->data[i].allocate(&wo->data[i]);			/* Allocate space */
1206 			memmove(wo->data[i].device.ucDesc, ts2a, 2 * 29);	/* Copy string in */
1207 
1208 			wo->data[i].device.scCode = 67;				/* Fudge scriptCode code */
1209 			wo->data[i].device.scSize = strlen(ts3a)+1;	/* Used size of scDesc in bytes, inc null */
1210 			if (wo->data[i].device.scSize > 67)
1211 				error("ScriptCode string longer than 67");
1212 			strcpy((char *)wo->data[i].device.scDesc, ts3a);	/* Copy the string in */
1213 
1214 			/* model Text description */
1215 			sprintf(ts1,"This is model descrption %d",i);
1216 			wo->data[i].model.size = strlen(ts1)+1;
1217 			wo->data[i].allocate(&wo->data[i]);			/* Allocate space */
1218 			strcpy(wo->data[i].model.desc, ts1);		/* Copy the string in */
1219 
1220 			/* We'll fudge up the Unicode string */
1221 			wo->data[i].model.ucLangCode = 7856;		/* UniCode language code */
1222 			wo->data[i].model.ucSize = 28;				/* Size in chars inc null */
1223 			wo->data[i].allocate(&wo->data[i]);			/* Allocate space */
1224 			memmove(wo->data[i].model.ucDesc, ts2b, 2 * 28);	/* Copy string in */
1225 
1226 			wo->data[i].model.scCode = 67;				/* Fudge scriptCode code */
1227 			wo->data[i].model.scSize = strlen(ts3b)+1;	/* Used size of scDesc in bytes, inc null */
1228 			if (wo->data[i].model.scSize > 67)
1229 				error("ScriptCode string longer than 67");
1230 			strcpy((char *)wo->data[i].model.scDesc, ts3b);	/* Copy the string in */
1231 		}
1232 	} else {
1233 		icmProfileSequenceDesc *ro;
1234 		unsigned int i;
1235 
1236 		/* Try and read the tag from the file */
1237 		ro = (icmProfileSequenceDesc *)rd_icco->read_tag(rd_icco, icSigProfileSequenceDescTag);
1238 		if (ro == NULL)
1239 			return 1;
1240 
1241 		/* Need to check that the cast is appropriate. */
1242 		if (ro->ttype != icSigProfileSequenceDescType)
1243 			return 1;
1244 
1245 		/* Now check it out */
1246 		if (ro->count != wo->count)
1247 			error ("ProfileSequenceDesc count doesn't match");
1248 
1249 		for (i = 0; i < wo->count; i++) {
1250 			rv |= (ro->data[i].deviceMfg    != wo->data[i].deviceMfg);
1251 			rv |= (ro->data[i].deviceModel  != wo->data[i].deviceModel);
1252 			rv |= (ro->data[i].attributes.l != wo->data[i].attributes.l);
1253 			rv |= (ro->data[i].attributes.h != wo->data[i].attributes.h);
1254 			rv |= (ro->data[i].technology   != wo->data[i].technology);
1255 
1256 			/* device Text description */
1257 			rv |= (ro->data[i].device.size  != wo->data[i].device.size);
1258 			rv |= strcmp(ro->data[i].device.desc, wo->data[i].device.desc);
1259 
1260 			rv |= (ro->data[i].device.ucLangCode != wo->data[i].device.ucLangCode);
1261 			rv |= (ro->data[i].device.ucSize != wo->data[i].device.ucSize);
1262 			rv |= memcmp(ro->data[i].device.ucDesc, wo->data[i].device.ucDesc, wo->data[i].device.ucSize * 2);
1263 
1264 			rv |= (ro->data[i].device.scCode != wo->data[i].device.scCode);
1265 			rv |= (ro->data[i].device.scSize != wo->data[i].device.scSize);
1266 			rv |= strcmp((char *)ro->data[i].device.scDesc, (char *)wo->data[i].device.scDesc);
1267 
1268 			/* model Text description */
1269 			rv |= (ro->data[i].model.size  != wo->data[i].model.size);
1270 			rv |= strcmp(ro->data[i].model.desc, wo->data[i].model.desc);
1271 
1272 			rv |= (ro->data[i].model.ucLangCode != wo->data[i].model.ucLangCode);
1273 			rv |= (ro->data[i].model.ucSize != wo->data[i].model.ucSize);
1274 			rv |= memcmp(ro->data[i].model.ucDesc, wo->data[i].model.ucDesc, wo->data[i].model.ucSize * 2);
1275 
1276 			rv |= (ro->data[i].model.scCode != wo->data[i].model.scCode);
1277 			rv |= (ro->data[i].model.scSize != wo->data[i].model.scSize);
1278 			rv |= strcmp((char *)ro->data[i].model.scDesc, (char *)wo->data[i].model.scDesc);
1279 		}
1280 
1281 		if (rv)
1282 			error ("ProfileSequenceDesc verify failed");
1283 	}
1284 	}
1285 	/* ----------------- */
1286 	/* S15Fixed16Array: */
1287 	{
1288 	static icmS15Fixed16Array *wo;
1289 	if (mode == 0) {
1290 		unsigned int i;
1291 		/* There is no standard Tag that uses icSigS15Fixed16ArrayType, so use a 'custom' tag */
1292 		if ((wo = (icmS15Fixed16Array *)wr_icco->add_tag(
1293 		           wr_icco, str2tag("sf32"), icSigS15Fixed16ArrayType)) == NULL)
1294 			return 1;
1295 
1296 		wo->size = rand_int(0,17);		/* Number in array */
1297 		wo->allocate((icmBase *)wo);	/* Allocate space */
1298 		for (i = 0; i < wo->size; i++) {
1299 			wo->data[i] = rand_s15f16(); /* Set numbers value */
1300 		}
1301 	} else {
1302 		icmS15Fixed16Array *ro;
1303 		unsigned int i;
1304 
1305 		/* Try and read the tag from the file */
1306 		ro = (icmS15Fixed16Array *)rd_icco->read_tag(rd_icco, str2tag("sf32"));
1307 		if (ro == NULL)
1308 			return 1;
1309 
1310 		/* Need to check that the cast is appropriate. */
1311 		if (ro->ttype != icSigS15Fixed16ArrayType)
1312 			return 1;
1313 
1314 		/* Now check it out */
1315 		if (ro->size != wo->size)
1316 			error ("S15Fixed16Array size doesn't match");
1317 
1318 		for (i = 0; i < wo->size; i++) {
1319 			rv |= dcomp(ro->data[i], wo->data[i]);
1320 		}
1321 
1322 		if (rv)
1323 			error ("S15Fixed16Array verify failed");
1324 	}
1325 	}
1326 	/* ----------------- */
1327 	/* Screening: */
1328 	{
1329 	static icmScreening *wo;
1330 	if (mode == 0) {
1331 		unsigned int i;
1332 		if ((wo = (icmScreening *)wr_icco->add_tag(
1333 		           wr_icco, icSigScreeningTag, icSigScreeningType)) == NULL)
1334 			return 1;
1335 
1336 		wo->screeningFlag = rand_ScreenEncodings();
1337 		wo->channels = rand_int(1,4);	/* Number of channels */
1338 		wo->allocate((icmBase *)wo);	/* Allocate space */
1339 		for (i = 0; i < wo->channels; i++) {
1340 			wo->data[i].frequency = rand_s15f16();		/* Set screening frequency */
1341 			wo->data[i].angle = rand_s15f16();			/* Set screening angle */
1342 			wo->data[i].spotShape = rand_SpotShape();	/* Set spot shape */
1343 		}
1344 	} else {
1345 		icmScreening *ro;
1346 		unsigned int i;
1347 
1348 		/* Try and read the tag from the file */
1349 		ro = (icmScreening *)rd_icco->read_tag(rd_icco, icSigScreeningTag);
1350 		if (ro == NULL)
1351 			return 1;
1352 
1353 		/* Need to check that the cast is appropriate. */
1354 		if (ro->ttype != icSigScreeningType)
1355 			return 1;
1356 
1357 		/* Now check it out */
1358 		if (ro->channels != wo->channels)
1359 			error ("Screening channels doesn't match");
1360 
1361 		rv |= (ro->screeningFlag != wo->screeningFlag);
1362 
1363 		for (i = 0; i < wo->channels; i++) {
1364 			rv |= dcomp(ro->data[i].frequency, wo->data[i].frequency);
1365 			rv |= dcomp(ro->data[i].angle, wo->data[i].angle);
1366 			rv |= (ro->data[i].spotShape != wo->data[i].spotShape);
1367 		}
1368 
1369 		if (rv)
1370 			error ("Screening verify failed");
1371 	}
1372 	}
1373 	/* ----------------- */
1374 	/* Signature: */
1375 	{
1376 	static icmSignature *wo;
1377 	if (mode == 0) {
1378 		if ((wo = (icmSignature *)wr_icco->add_tag(
1379 		           wr_icco, icSigTechnologyTag, icSigSignatureType)) == NULL)
1380 			return 1;
1381 
1382 		wo->sig = rand_TechnologySignature();
1383 	} else {
1384 		icmSignature *ro;
1385 
1386 		/* Try and read the tag from the file */
1387 		ro = (icmSignature *)rd_icco->read_tag(rd_icco, icSigTechnologyTag);
1388 		if (ro == NULL)
1389 			return 1;
1390 
1391 		/* Need to check that the cast is appropriate. */
1392 		if (ro->ttype != icSigSignatureType)
1393 			return 1;
1394 
1395 		/* Now check it out */
1396 		rv |= (ro->sig != wo->sig);
1397 
1398 		if (rv)
1399 			error ("Signature verify failed");
1400 	}
1401 	}
1402 	/* ----------------- */
1403 	/* Text Description: */
1404 	{
1405 	static icmTextDescription *wo;
1406 	char *ts1 = "This is a test description";
1407 	unsigned short ts2[27] = {'T','h','i','s',' ','i','s',' ','a',' ','t','e','s','t',
1408 	                          ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000};
1409 	char *ts3 = "This is a test3 description";
1410 	if (mode == 0) {
1411 		if ((wo = (icmTextDescription *)wr_icco->add_tag(
1412 		           wr_icco, icSigProfileDescriptionTag,	icSigTextDescriptionType)) == NULL)
1413 			return 1;
1414 
1415 		/* Data in tag type wojects is always allocated and freed by the woject */
1416 		wo->size = strlen(ts1)+1; 	/* Allocated and used size of desc, inc null */
1417 		wo->allocate((icmBase *)wo);/* Allocate space */
1418 		strcpy(wo->desc, ts1);		/* Copy the string in */
1419 
1420 		/* We'll fudge up the Unicode string */
1421 		wo->ucLangCode = 1234;		/* UniCode language code */
1422 		wo->ucSize = 27;			/* Allocated and used size of ucDesc in characters, inc null */
1423 		wo->allocate((icmBase *)wo);/* Allocate space */
1424 		memmove(wo->ucDesc, ts2, 2 * 27);	/* Copy string in */
1425 
1426 		/* Don't really know anything about scriptCode, but fudge some values */
1427 		wo->scCode = 23;			/* ScriptCode code */
1428 		wo->scSize = strlen(ts3)+1;	/* Used size of scDesc in bytes, inc null */
1429 					/* No allocations, since this has a fixed max of 67 bytes */
1430 		if (wo->scSize > 67)
1431 			error("ScriptCode string longer than 67");
1432 		strcpy((char *)wo->scDesc, ts3);	/* Copy the string in */
1433 	} else {
1434 		icmTextDescription *ro;
1435 
1436 		/* Try and read the tag from the file */
1437 		ro = (icmTextDescription *)rd_icco->read_tag(rd_icco, icSigProfileDescriptionTag);
1438 		if (ro == NULL)
1439 			return 1;
1440 
1441 		/* Need to check that the cast is appropriate. */
1442 		/* We could have left it icmBase, switched on ro->ttype, & then cast appropriately. */
1443 		if (ro->ttype != icSigTextDescriptionType)
1444 			return 1;
1445 
1446 		/* Now check it out */
1447 		rv |= (ro->size != wo->size);
1448 		rv |= strcmp(ro->desc, wo->desc);
1449 
1450 		rv |= (ro->ucLangCode != wo->ucLangCode);
1451 		rv |= (ro->ucSize != wo->ucSize);
1452 		rv |= memcmp(ro->ucDesc, wo->ucDesc, wo->ucSize * 2);
1453 
1454 		rv |= (ro->scCode != wo->scCode);
1455 		rv |= (ro->scSize != wo->scSize);
1456 		rv |= strcmp((char *)ro->scDesc, (char *)wo->scDesc);
1457 		if (rv)
1458 			error ("Text Description verify failed4");
1459 	}
1460 	}
1461 	/* ----- */
1462 	/* Text: */
1463 	{
1464 	static icmText *wo;
1465 	char *ts1 = "This is Copyright by me!";
1466 	if (mode == 0) {
1467 		if ((wo = (icmText *)wr_icco->add_tag(
1468 		           wr_icco, icSigCopyrightTag,	icSigTextType)) == NULL)
1469 			return 1;
1470 
1471 		wo->size = strlen(ts1)+1; 	/* Allocated and used size of text, inc null */
1472 		wo->allocate((icmBase *)wo);/* Allocate space */
1473 		strcpy(wo->data, ts1);		/* Copy the text in */
1474 	} else {
1475 		icmText *ro;
1476 
1477 		/* Try and read the tag from the file */
1478 		ro = (icmText *)rd_icco->read_tag(rd_icco, icSigCopyrightTag);
1479 		if (ro == NULL)
1480 			return 1;
1481 
1482 		/* Need to check that the cast is appropriate. */
1483 		if (ro->ttype != icSigTextType)
1484 			return 1;
1485 
1486 		/* Now check it out */
1487 		if (ro->size != wo->size)
1488 			error ("Text size doesn't match");
1489 
1490 		rv |= strcmp(ro->data, wo->data);
1491 
1492 		if (rv)
1493 			error ("Text verify failed");
1494 	}
1495 	}
1496 	/* ---------------- */
1497 	/* U16Fixed16Array: */
1498 	{
1499 	static icmU16Fixed16Array *wo;
1500 	if (mode == 0) {
1501 		unsigned int i;
1502 		/* There is no standard Tag that uses icSigU16Fixed16ArrayType, so use a 'custom' tag */
1503 		if ((wo = (icmU16Fixed16Array *)wr_icco->add_tag(
1504 		           wr_icco, str2tag("uf32"), icSigU16Fixed16ArrayType)) == NULL)
1505 			return 1;
1506 
1507 		wo->size = rand_int(0,17);		/* Number in array */
1508 		wo->allocate((icmBase *)wo);	/* Allocate space */
1509 		for (i = 0; i < wo->size; i++) {
1510 			wo->data[i] = rand_u16f16(); /* Set numbers value */
1511 		}
1512 	} else {
1513 		icmU16Fixed16Array *ro;
1514 		unsigned int i;
1515 
1516 		/* Try and read the tag from the file */
1517 		ro = (icmU16Fixed16Array *)rd_icco->read_tag(rd_icco, str2tag("uf32"));
1518 		if (ro == NULL)
1519 			return 1;
1520 
1521 		/* Need to check that the cast is appropriate. */
1522 		if (ro->ttype != icSigU16Fixed16ArrayType)
1523 			return 1;
1524 
1525 		/* Now check it out */
1526 		if (ro->size != wo->size)
1527 			error ("U16Fixed16Array size doesn't match");
1528 
1529 		for (i = 0; i < wo->size; i++) {
1530 			rv |= dcomp(ro->data[i], wo->data[i]);
1531 		}
1532 
1533 		if (rv)
1534 			error ("U16Fixed16Array verify failed");
1535 	}
1536 	}
1537 	/* ------------------- */
1538 	/* UcrBg - full curve: */
1539 	{
1540 	static icmUcrBg *wo;
1541 	char *ts1 = "UcrBg - full curve info";
1542 	if (mode == 0) {
1543 		unsigned int i;
1544 		if ((wo = (icmUcrBg *)wr_icco->add_tag(
1545 		           wr_icco, icSigUcrBgTag, icSigUcrBgType)) == NULL)
1546 			return 1;
1547 
1548 		wo->UCRcount = rand_int(2,55);		/* Number in UCR curve */
1549 		wo->BGcount  = rand_int(2,32);		/* Number in BG array */
1550 		wo->allocate((icmBase *)wo);		/* Allocate space for both curves */
1551 		for (i = 0; i < wo->UCRcount; i++)
1552 			wo->UCRcurve[i] = rand_16f();	/* Set numbers value */
1553 		for (i = 0; i < wo->BGcount; i++)
1554 			wo->BGcurve[i] = rand_16f();	/* Set numbers value */
1555 		wo->size = strlen(ts1)+1; 			/* Allocated and used size of text, inc null */
1556 		wo->allocate((icmBase *)wo);		/* Allocate space */
1557 		strcpy(wo->string, ts1);			/* Copy the text in */
1558 	} else {
1559 		icmUcrBg *ro;
1560 		unsigned int i;
1561 
1562 		/* Try and read the tag from the file */
1563 		ro = (icmUcrBg *)rd_icco->read_tag(rd_icco, icSigUcrBgTag);
1564 		if (ro == NULL)
1565 			return 1;
1566 
1567 		/* Need to check that the cast is appropriate. */
1568 		if (ro->ttype != icSigUcrBgType)
1569 			return 1;
1570 
1571 		/* Now check it out */
1572 		if (ro->UCRcount != wo->UCRcount)
1573 			error ("UcrBg UCRcount doesn't match");
1574 
1575 		if (ro->BGcount != wo->BGcount)
1576 			error ("UcrBg BGcount doesn't match");
1577 
1578 		for (i = 0; i < wo->UCRcount; i++)
1579 			rv |= dcomp(ro->UCRcurve[i], wo->UCRcurve[i]);
1580 
1581 		for (i = 0; i < wo->BGcount; i++)
1582 			rv |= dcomp(ro->BGcurve[i], wo->BGcurve[i]);
1583 
1584 		if (ro->size != wo->size)
1585 			error ("Text size doesn't match");
1586 
1587 		rv |= strcmp(ro->string, wo->string);
1588 
1589 		if (rv)
1590 			error ("UcrBg verify failed");
1591 	}
1592 	}
1593 	/* ------------------- */
1594 	/* UcrBg - percentage: */
1595 	{
1596 	static icmUcrBg *wo;
1597 	char *ts1 = "UcrBg - percentage info";
1598 	if (mode == 0) {
1599 		if ((wo = (icmUcrBg *)wr_icco->add_tag(
1600 		           wr_icco, str2tag("bfd%"), icSigUcrBgType)) == NULL)
1601 			return 1;
1602 
1603 		wo->UCRcount = 1;			/* 1 == UCR percentage */
1604 		wo->BGcount  = 1;			/* 1 == BG percentage */
1605 		wo->allocate((icmBase *)wo);/* Allocate space */
1606 		wo->UCRcurve[0] = (double) rand_int(0,65535);
1607 		wo->BGcurve[0] = (double) rand_int(0,65535);
1608 		wo->size = strlen(ts1)+1; 	/* Allocated and used size of text, inc null */
1609 		wo->allocate((icmBase *)wo);/* Allocate space */
1610 		strcpy(wo->string, ts1);	/* Copy the text in */
1611 	} else {
1612 		icmUcrBg *ro;
1613 
1614 		/* Try and read the tag from the file */
1615 		ro = (icmUcrBg *)rd_icco->read_tag(rd_icco, str2tag("bfd%"));
1616 		if (ro == NULL)
1617 			return 1;
1618 
1619 		/* Need to check that the cast is appropriate. */
1620 		if (ro->ttype != icSigUcrBgType)
1621 			return 1;
1622 
1623 		/* Now check it out */
1624 		if (ro->UCRcount != wo->UCRcount)
1625 			error ("UcrBg UCRcount doesn't match");
1626 
1627 		if (ro->BGcount != wo->BGcount)
1628 			error ("UcrBg BGcount doesn't match");
1629 
1630 		rv |= (ro->UCRcurve[0] != wo->UCRcurve[0]);
1631 		rv |= (ro->BGcurve[0] != wo->BGcurve[0]);
1632 
1633 		if (ro->size != wo->size)
1634 			error ("Text size doesn't match");
1635 
1636 		rv |= strcmp(ro->string, wo->string);
1637 
1638 		if (rv)
1639 			error ("UcrBg verify failed");
1640 	}
1641 	}
1642 	/* ------------ */
1643 	/* UInt16Array: */
1644 	{
1645 	static icmUInt16Array *wo;
1646 	if (mode == 0) {
1647 		unsigned int i;
1648 		/* There is no standard Tag that uses icSigUInt16ArrayType, so use a 'custom' tag */
1649 		if ((wo = (icmUInt16Array *)wr_icco->add_tag(
1650 		           wr_icco, str2tag("ui16"), icSigUInt16ArrayType)) == NULL)
1651 			return 1;
1652 
1653 		wo->size = rand_int(0,17);		/* Number in array */
1654 		wo->allocate((icmBase *)wo);	/* Allocate space */
1655 		for (i = 0; i < wo->size; i++) {
1656 			wo->data[i] = rand_o16(); /* Set numbers value */
1657 		}
1658 	} else {
1659 		icmUInt16Array *ro;
1660 		unsigned int i;
1661 
1662 		/* Try and read the tag from the file */
1663 		ro = (icmUInt16Array *)rd_icco->read_tag(rd_icco, str2tag("ui16"));
1664 		if (ro == NULL)
1665 			return 1;
1666 
1667 		/* Need to check that the cast is appropriate. */
1668 		if (ro->ttype != icSigUInt16ArrayType)
1669 			return 1;
1670 
1671 		/* Now check it out */
1672 		if (ro->size != wo->size)
1673 			error ("UInt16Array size doesn't match");
1674 
1675 		for (i = 0; i < wo->size; i++) {
1676 			rv |= (ro->data[i] != wo->data[i]);
1677 		}
1678 
1679 		if (rv)
1680 			error ("UInt16Array verify failed");
1681 	}
1682 	}
1683 	/* ------------ */
1684 	/* UInt32Array: */
1685 	{
1686 	static icmUInt32Array *wo;
1687 	if (mode == 0) {
1688 		unsigned int i;
1689 		/* There is no standard Tag that uses icSigUInt32ArrayType, so use a 'custom' tag */
1690 		if ((wo = (icmUInt32Array *)wr_icco->add_tag(
1691 		           wr_icco, str2tag("ui32"), icSigUInt32ArrayType)) == NULL)
1692 			return 1;
1693 
1694 		wo->size = rand_int(0,18);		/* Number in array */
1695 		wo->allocate((icmBase *)wo);	/* Allocate space */
1696 		for (i = 0; i < wo->size; i++) {
1697 			wo->data[i] = rand_o32(); /* Set numbers value */
1698 		}
1699 	} else {
1700 		icmUInt32Array *ro;
1701 		unsigned int i;
1702 
1703 		/* Try and read the tag from the file */
1704 		ro = (icmUInt32Array *)rd_icco->read_tag(rd_icco, str2tag("ui32"));
1705 		if (ro == NULL)
1706 			return 1;
1707 
1708 		/* Need to check that the cast is appropriate. */
1709 		if (ro->ttype != icSigUInt32ArrayType)
1710 			return 1;
1711 
1712 		/* Now check it out */
1713 		if (ro->size != wo->size)
1714 			error ("UInt32Array size doesn't match");
1715 
1716 		for (i = 0; i < wo->size; i++) {
1717 			rv |= (ro->data[i] != wo->data[i]);
1718 		}
1719 
1720 		if (rv)
1721 			error ("UInt32Array verify failed");
1722 	}
1723 	}
1724 	/* ------------ */
1725 	/* UInt64Array: */
1726 	{
1727 	static icmUInt64Array *wo;
1728 	if (mode == 0) {
1729 		unsigned int i;
1730 		/* There is no standard Tag that uses icSigUInt64ArrayType, so use a 'custom' tag */
1731 		if ((wo = (icmUInt64Array *)wr_icco->add_tag(
1732 		           wr_icco, str2tag("ui64"), icSigUInt64ArrayType)) == NULL)
1733 			return 1;
1734 
1735 		wo->size = rand_int(0,19);		/* Number in array */
1736 		wo->allocate((icmBase *)wo);	/* Allocate space */
1737 		for (i = 0; i < wo->size; i++) {
1738 			wo->data[i].l = rand_o32(); /* Set numbers value - low 32 bits */
1739 			wo->data[i].h = rand_o32(); /* Set numbers value - low 32 bits */
1740 		}
1741 	} else {
1742 		icmUInt64Array *ro;
1743 		unsigned int i;
1744 
1745 		/* Try and read the tag from the file */
1746 		ro = (icmUInt64Array *)rd_icco->read_tag(rd_icco, str2tag("ui64"));
1747 		if (ro == NULL)
1748 			return 1;
1749 
1750 		/* Need to check that the cast is appropriate. */
1751 		if (ro->ttype != icSigUInt64ArrayType)
1752 			return 1;
1753 
1754 		/* Now check it out */
1755 		if (ro->size != wo->size)
1756 			error ("UInt64Array size doesn't match");
1757 
1758 		for (i = 0; i < wo->size; i++) {
1759 			rv |= (ro->data[i].l != wo->data[i].l);
1760 			rv |= (ro->data[i].h != wo->data[i].h);
1761 		}
1762 
1763 		if (rv)
1764 			error ("UInt64Array verify failed");
1765 	}
1766 	}
1767 	/* ----------- */
1768 	/* UInt8Array: */
1769 	{
1770 	static icmUInt8Array *wo;
1771 	if (mode == 0) {
1772 		unsigned int i;
1773 		/* There is no standard Tag that uses icSigUInt8ArrayType, so use a 'custom' tag */
1774 		if ((wo = (icmUInt8Array *)wr_icco->add_tag(
1775 		           wr_icco, str2tag("ui08"), icSigUInt8ArrayType)) == NULL)
1776 			return 1;
1777 
1778 		wo->size = rand_int(0,18);		/* Number in array */
1779 		wo->allocate((icmBase *)wo);	/* Allocate space */
1780 		for (i = 0; i < wo->size; i++) {
1781 			wo->data[i] = rand_o8(); /* Set numbers value */
1782 		}
1783 	} else {
1784 		icmUInt8Array *ro;
1785 		unsigned int i;
1786 
1787 		/* Try and read the tag from the file */
1788 		ro = (icmUInt8Array *)rd_icco->read_tag(rd_icco, str2tag("ui08"));
1789 		if (ro == NULL)
1790 			return 1;
1791 
1792 		/* Need to check that the cast is appropriate. */
1793 		if (ro->ttype != icSigUInt8ArrayType)
1794 			return 1;
1795 
1796 		/* Now check it out */
1797 		if (ro->size != wo->size)
1798 			error ("UInt8Array size doesn't match");
1799 
1800 		for (i = 0; i < wo->size; i++) {
1801 			rv |= (ro->data[i] != wo->data[i]);
1802 		}
1803 
1804 		if (rv)
1805 			error ("UInt8Array verify failed");
1806 	}
1807 	}
1808 	/* --------------- */
1809 	/* VideoCardGamma: (ColorSync specific) */
1810 	{
1811 		static icmVideoCardGamma *wo;
1812 		if (mode == 0) {
1813 			int i;
1814 			if ((wo = (icmVideoCardGamma *)wr_icco->add_tag(
1815 				 wr_icco, icSigVideoCardGammaTag, icSigVideoCardGammaType)) == NULL)
1816 				return 1;
1817 
1818 			wo->tagType = icmVideoCardGammaTableType;
1819 			wo->u.table.channels = rand_int(1,3);
1820 			wo->u.table.entryCount = rand_int(2,1024);
1821 			wo->u.table.entrySize = rand_int(1,2);
1822 			wo->allocate((icmBase *)wo);
1823 			if (wo->u.table.entrySize == 1) {
1824 				unsigned char *cp = wo->u.table.data;
1825 				for (i=0; i<wo->u.table.channels*wo->u.table.entryCount;i++,cp++)
1826 					*cp = (unsigned char)rand_int(0,255);
1827 			} else {
1828 				unsigned short *sp = wo->u.table.data;
1829 				for (i=0; i<wo->u.table.channels*wo->u.table.entryCount;i++,sp++)
1830 					*sp = (unsigned short)rand_int(0,65535);
1831 			}
1832 		} else {
1833 			icmVideoCardGamma *ro;
1834 			int i;
1835 
1836 			/* Try and read tag from the file */
1837 			ro = (icmVideoCardGamma *)rd_icco->read_tag(rd_icco, icSigVideoCardGammaTag);
1838 			if (ro == NULL)
1839 				return 1;
1840 
1841 			/* Need to check that the cast is appropriate */
1842 			if (ro->ttype != icSigVideoCardGammaType)
1843 				return 1;
1844 
1845 			/* Now check it out */
1846 			rv |= (ro->tagType != wo->tagType);
1847 			rv |= (ro->u.table.channels != wo->u.table.channels);
1848 			rv |= (ro->u.table.entryCount != wo->u.table.entryCount);
1849 			rv |= (ro->u.table.entrySize != wo->u.table.entrySize);
1850 			for (i=0; i<ro->u.table.channels*ro->u.table.entryCount*ro->u.table.entrySize; i++) {
1851 				rv |= (((char*)ro->u.table.data)[i] != ((char*)wo->u.table.data)[i]);
1852 				if (rv) break;
1853 			}
1854 			if (rv)
1855 				error ("VideoCardGamma verify failed");
1856 		}
1857 	}
1858 	/* ------------------ */
1859 	/* ViewingConditions: */
1860 	{
1861 	static icmViewingConditions *wo;
1862 	if (mode == 0) {
1863 		if ((wo = (icmViewingConditions *)wr_icco->add_tag(
1864 		           wr_icco, icSigViewingConditionsTag, icSigViewingConditionsType)) == NULL)
1865 			return 1;
1866 
1867     	wo->illuminant.X = rand_XYZ16();	/* XYZ of illuminant in cd/m^2 */
1868     	wo->illuminant.Y = rand_XYZ16();
1869     	wo->illuminant.Z = rand_XYZ16();
1870     	wo->surround.X = rand_XYZ16();		/* XYZ of surround in cd/m^2 */
1871     	wo->surround.Y = rand_XYZ16();
1872     	wo->surround.Z = rand_XYZ16();
1873     	wo->stdIlluminant = rand_Illuminant();	/* Standard illuminent type */
1874 	} else {
1875 		icmViewingConditions *ro;
1876 
1877 		/* Try and read the tag from the file */
1878 		ro = (icmViewingConditions *)rd_icco->read_tag(rd_icco, icSigViewingConditionsTag);
1879 		if (ro == NULL)
1880 			return 1;
1881 
1882 		/* Need to check that the cast is appropriate. */
1883 		if (ro->ttype != icSigViewingConditionsType)
1884 			return 1;
1885 
1886 		/* Now check it out */
1887     	rv |= dcomp(ro->illuminant.X, wo->illuminant.X);
1888     	rv |= dcomp(ro->illuminant.Y, wo->illuminant.Y);
1889     	rv |= dcomp(ro->illuminant.Z, wo->illuminant.Z);
1890     	rv |= dcomp(ro->surround.X  , wo->surround.X);
1891     	rv |= dcomp(ro->surround.Y  , wo->surround.Y);
1892     	rv |= dcomp(ro->surround.Z  , wo->surround.Z);
1893     	rv |= (ro->stdIlluminant != wo->stdIlluminant);
1894 
1895 		if (rv)
1896 			error ("ViewingConditions verify failed");
1897 	}
1898 	}
1899 	/* ---------- */
1900 	/* XYZ array: */
1901 	{
1902 	static icmXYZArray *wo;
1903 	if (mode == 0) {
1904 		unsigned int i;
1905 		/* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
1906 		if ((wo = (icmXYZArray *)wr_icco->add_tag(
1907 		           wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
1908 			return 1;
1909 
1910 		wo->size = rand_int(1,7);	/* Should be one XYZ number, but test more */
1911 		wo->allocate((icmBase *)wo);	/* Allocate space */
1912 		for (i = 0; i < wo->size; i++) {
1913 			wo->data[i].X = rand_XYZ16();	/* Set numbers value */
1914 			wo->data[i].Y = rand_XYZ16();
1915 			wo->data[i].Z = rand_XYZ16();
1916 		}
1917 	} else {
1918 		icmXYZArray *ro;
1919 		unsigned int i;
1920 
1921 		/* Try and read the tag from the file */
1922 		ro = (icmXYZArray *)rd_icco->read_tag(rd_icco, icSigMediaWhitePointTag);
1923 		if (ro == NULL)
1924 			return 1;
1925 
1926 		/* Need to check that the cast is appropriate. */
1927 		if (ro->ttype != icSigXYZArrayType)
1928 			return 1;
1929 
1930 		/* Now check it out */
1931 		if (ro->size != wo->size)
1932 			error ("XYZArray size doesn't match");
1933 
1934 		for (i = 0; i < wo->size; i++) {
1935 			rv |= dcomp(ro->data[i].X, wo->data[i].X);
1936 			rv |= dcomp(ro->data[i].Y, wo->data[i].Y);
1937 	    	rv |= dcomp(ro->data[i].Z, wo->data[i].Z);
1938 		}
1939 
1940 		if (rv)
1941 			error ("XYZArray verify failed");
1942 	}
1943 	}
1944 
1945 	return 0;
1946 }
1947 
1948 /* ------------------------------------------------ */
1949 /* Floating point random number generators */
1950 /* These are appropriate for the underlying integer */
1951 /* representations in the icc format. */
1952 /* This is simply as a convenience so that we can */
1953 /* test the full range of representation, and */
1954 /* get away with exact verification. */
1955 
1956 /* 32 bit pseudo random sequencer */
1957 static unsigned int seed = 0x12345678;
1958 
1959 /* #define PSRAND(S) ((S) * 1103515245 + 12345) */
1960 #define PSRAND(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1))
1961 
rand_o8()1962 unsigned int rand_o8() {
1963 	ORD32 o32;
1964 	seed = PSRAND(seed);
1965 	o32 = seed & 0xff;
1966 	return o32;
1967 }
1968 
rand_o16()1969 unsigned int rand_o16() {
1970 	ORD32 o32;
1971 	seed = PSRAND(seed);
1972 	o32 = seed & 0xffff;
1973 	return o32;
1974 }
1975 
rand_o32()1976 unsigned int rand_o32() {
1977 	ORD32 o32;
1978 	o32 = seed = PSRAND(seed);
1979 	return o32;
1980 }
1981 
rand_int(int low,int high)1982 int rand_int(int low, int high) {
1983 	int i;
1984 	seed = PSRAND(seed);
1985 	i = seed % (high - low + 1);
1986 	return i + low;
1987 }
1988 
rand_u8f8()1989 double rand_u8f8() {
1990 	ORD32 o32;
1991 	seed = PSRAND(seed);
1992 	o32 = seed & 0xffff;
1993 	return (double)o32/256.0;
1994 }
1995 
rand_u16f16()1996 double rand_u16f16() {
1997 	ORD32 o32;
1998 	seed = PSRAND(seed);
1999 	o32 = seed;
2000 	return (double)o32/65536.0;
2001 }
2002 
rand_s15f16()2003 double rand_s15f16() {
2004 	INR32 i32;
2005 	seed = PSRAND(seed);
2006 	i32 = seed;
2007 	return (double)i32/65536.0;
2008 }
2009 
rand_XYZ16()2010 double rand_XYZ16() {
2011 	ORD32 o32;
2012 	seed = PSRAND(seed);
2013 	o32 = seed & 0xffff;
2014 	return (double)o32/32768.0;
2015 }
2016 
rand_L8()2017 double rand_L8() {
2018 	ORD32 o32;
2019 	seed = PSRAND(seed);
2020 	o32 = seed & 0xff;
2021 	return (double)o32/2.550;
2022 }
2023 
rand_ab8()2024 double rand_ab8() {
2025 	ORD32 o32;
2026 	seed = PSRAND(seed);
2027 	o32 = seed & 0xff;
2028 	return (double)o32-128.0;
2029 }
2030 
rand_L16()2031 double rand_L16() {
2032 	ORD32 o32;
2033 	seed = PSRAND(seed);
2034 	o32 = seed & 0xffff;
2035 	return (double)o32/652.800;				/* 0xff00/100.0 */
2036 }
2037 
rand_ab16()2038 double rand_ab16() {
2039 	ORD32 o32;
2040 	seed = PSRAND(seed);
2041 	o32 = seed & 0xffff;
2042 	return ((double)o32/256.0)-128.0;
2043 }
2044 
rand_8f()2045 double rand_8f() {
2046 	unsigned int rv;
2047 	seed = PSRAND(seed);
2048 	rv = seed & 0xff;
2049 	return (double)rv/255.0;
2050 }
2051 
rand_16f()2052 double rand_16f() {
2053 	unsigned int rv;
2054 	seed = PSRAND(seed);
2055 	rv = seed & 0xffff;
2056 	return (double)rv/65535.0;
2057 }
2058 
2059 /* Random selectors for ICC flags and enumerayions */
2060 
rand_ScreenEncodings()2061 unsigned int rand_ScreenEncodings() {
2062 	unsigned int flags = 0;
2063 
2064 	if (rand_int(0,1) == 0)
2065 		flags |= icPrtrDefaultScreensTrue;
2066 
2067 	if (rand_int(0,1) == 0)
2068 		flags |= icLinesPerInch;
2069 
2070 	return flags;
2071 }
2072 
2073 /* Device attributes */
rand_DeviceAttributes()2074 unsigned int rand_DeviceAttributes() {
2075 	unsigned int flags = 0;
2076 
2077 	if (rand_int(0,1) == 0)
2078 		flags |= icTransparency;
2079 
2080 	if (rand_int(0,1) == 0)
2081 		flags |= icMatte;
2082 
2083 	return flags;
2084 }
2085 
2086 /* Profile header flags */
rand_ProfileHeaderFlags()2087 unsigned int rand_ProfileHeaderFlags() {
2088 	unsigned int flags = 0;
2089 
2090 	if (rand_int(0,1) == 0)
2091 		flags |= icEmbeddedProfileTrue;
2092 
2093 	if (rand_int(0,1) == 0)
2094 		flags |= icUseWithEmbeddedDataOnly;
2095 
2096 	return flags;
2097 }
2098 
2099 
rand_AsciiOrBinaryData()2100 unsigned int rand_AsciiOrBinaryData() {
2101 	unsigned int flags = 0;
2102 
2103 	if (rand_int(0,1) == 0)
2104 		flags |= icBinaryData;
2105 
2106 	return flags;
2107 }
2108 
rand_ColorSpaceSignature()2109 icColorSpaceSignature rand_ColorSpaceSignature() {
2110 	switch(rand_int(0,25)) {
2111     	case 0:
2112 			return icSigXYZData;
2113     	case 1:
2114 			return icSigLabData;
2115     	case 2:
2116 			return icSigLuvData;
2117     	case 3:
2118 			return icSigYCbCrData;
2119     	case 4:
2120 			return icSigYxyData;
2121     	case 5:
2122 			return icSigRgbData;
2123     	case 6:
2124 			return icSigGrayData;
2125     	case 7:
2126 			return icSigHsvData;
2127     	case 8:
2128 			return icSigHlsData;
2129     	case 9:
2130 			return icSigCmykData;
2131     	case 10:
2132 			return icSigCmyData;
2133     	case 11:
2134 			return icSigMch6Data;
2135     	case 12:
2136 			return icSig2colorData;
2137     	case 13:
2138 			return icSig3colorData;
2139     	case 14:
2140 			return icSig4colorData;
2141     	case 15:
2142 			return icSig5colorData;
2143     	case 16:
2144 			return icSig6colorData;
2145     	case 17:
2146 			return icSig7colorData;
2147     	case 18:
2148 			return icSig8colorData;
2149     	case 19:
2150 			return icSig9colorData;
2151     	case 20:
2152 			return icSig10colorData;
2153     	case 21:
2154 			return icSig11colorData;
2155     	case 22:
2156 			return icSig12colorData;
2157     	case 23:
2158 			return icSig13colorData;
2159     	case 24:
2160 			return icSig14colorData;
2161     	case 25:
2162 			return icSig15colorData;
2163 	}
2164     return icMaxEnumData;
2165 }
2166 
rand_PCS()2167 icColorSpaceSignature rand_PCS() {
2168 	switch(rand_int(0,1)) {
2169     	case 0:
2170 			return icSigXYZData;
2171     	case 1:
2172 			return icSigLabData;
2173 	}
2174     return icMaxEnumData;
2175 }
2176 
rand_TechnologySignature()2177 icTechnologySignature rand_TechnologySignature() {
2178 	switch(rand_int(0,21)) {
2179     	case 0:
2180 			return icSigDigitalCamera;
2181     	case 1:
2182 			return icSigFilmScanner;
2183     	case 2:
2184 			return icSigReflectiveScanner;
2185     	case 3:
2186 			return icSigInkJetPrinter;
2187     	case 4:
2188 			return icSigThermalWaxPrinter;
2189     	case 5:
2190 			return icSigElectrophotographicPrinter;
2191     	case 6:
2192 			return icSigElectrostaticPrinter;
2193     	case 7:
2194 			return icSigDyeSublimationPrinter;
2195     	case 8:
2196 			return icSigPhotographicPaperPrinter;
2197     	case 9:
2198 			return icSigFilmWriter;
2199     	case 10:
2200 			return icSigVideoMonitor;
2201     	case 11:
2202 			return icSigVideoCamera;
2203     	case 12:
2204 			return icSigProjectionTelevision;
2205     	case 13:
2206 			return icSigCRTDisplay;
2207     	case 14:
2208 			return icSigPMDisplay;
2209     	case 15:
2210 			return icSigAMDisplay;
2211     	case 16:
2212 			return icSigPhotoCD;
2213     	case 17:
2214 			return icSigPhotoImageSetter;
2215     	case 18:
2216 			return icSigGravure;
2217     	case 19:
2218 			return icSigOffsetLithography;
2219     	case 20:
2220 			return icSigSilkscreen;
2221     	case 21:
2222 			return icSigFlexography;
2223 	}
2224 	return icMaxEnumTechnology;
2225 }
2226 
rand_ProfileClassSignature()2227 icProfileClassSignature rand_ProfileClassSignature() {
2228 	switch(rand_int(0,6)) {
2229 		case 0:
2230 			return icSigInputClass;
2231 		case 1:
2232 			return icSigDisplayClass;
2233 		case 2:
2234 			return icSigOutputClass;
2235 		case 3:
2236 			return icSigLinkClass;
2237 		case 4:
2238 			return icSigAbstractClass;
2239 		case 5:
2240 			return icSigColorSpaceClass;
2241 		case 6:
2242 			return icSigNamedColorClass;
2243 	}
2244 	return icMaxEnumClass;
2245 }
2246 
rand_PlatformSignature()2247 icPlatformSignature rand_PlatformSignature() {
2248 	switch(rand_int(0,4)) {
2249 		case 0:
2250 			return icSigMacintosh;
2251 		case 1:
2252 			return icSigMicrosoft;
2253 		case 2:
2254 			return icSigSolaris;
2255 		case 3:
2256 			return icSigSGI;
2257 		case 4:
2258 			return icSigTaligent;
2259 	}
2260 	return icMaxEnumPlatform;
2261 }
2262 
rand_MeasurementFlare()2263 icMeasurementFlare rand_MeasurementFlare() {
2264 	switch(rand_int(0,1)) {
2265 		case 0:
2266 			return icFlare0;
2267 		case 1:
2268 			return icFlare100;
2269 	}
2270 	return icMaxFlare;
2271 }
2272 
rand_MeasurementGeometry()2273 icMeasurementGeometry rand_MeasurementGeometry() {
2274 	switch(rand_int(0,2)) {
2275 		case 0:
2276 			return icGeometryUnknown;
2277 		case 1:
2278 			return icGeometry045or450;
2279 		case 2:
2280 			return icGeometry0dord0;
2281 	}
2282 	return icMaxGeometry;
2283 }
2284 
rand_RenderingIntent()2285 icRenderingIntent rand_RenderingIntent() {
2286 	switch(rand_int(0,3)) {
2287 		case 0:
2288 			return icPerceptual;
2289 	    case 1:
2290 			return icRelativeColorimetric;
2291 	    case 2:
2292 			return icSaturation;
2293 	    case 3:
2294 			return icAbsoluteColorimetric;
2295 	}
2296 	return icMaxEnumIntent;
2297 }
2298 
rand_SpotShape()2299 icSpotShape rand_SpotShape() {
2300 	switch(rand_int(0,7)) {
2301 		case 0:
2302 			return icSpotShapeUnknown;
2303 		case 1:
2304 			return icSpotShapePrinterDefault;
2305 		case 2:
2306 			return icSpotShapeRound;
2307 		case 3:
2308 			return icSpotShapeDiamond;
2309 		case 4:
2310 			return icSpotShapeEllipse;
2311 		case 5:
2312 			return icSpotShapeLine;
2313 		case 6:
2314 			return icSpotShapeSquare;
2315 		case 7:
2316 			return icSpotShapeCross;
2317 	}
2318 	return icMaxEnumSpot;
2319 }
2320 
rand_StandardObserver()2321 icStandardObserver rand_StandardObserver() {
2322 	switch(rand_int(0,2)) {
2323 		case 0:
2324 			return icStdObsUnknown;
2325 		case 1:
2326 			return icStdObs1931TwoDegrees;
2327 		case 2:
2328 			return icStdObs1964TenDegrees;
2329 	}
2330 	return icMaxStdObs;
2331 }
2332 
rand_Illuminant()2333 icIlluminant rand_Illuminant() {
2334 	switch(rand_int(0,8)) {
2335 		case 0:
2336 			return icIlluminantUnknown;
2337 		case 1:
2338 			return icIlluminantD50;
2339 		case 2:
2340 			return icIlluminantD65;
2341 		case 3:
2342 			return icIlluminantD93;
2343 		case 4:
2344 			return icIlluminantF2;
2345 		case 5:
2346 			return icIlluminantD55;
2347 		case 6:
2348 			return icIlluminantA;
2349 		case 7:
2350 			return icIlluminantEquiPowerE;
2351 		case 8:
2352 			return icIlluminantF8;
2353 	}
2354 	return icMaxEnumIlluminant;
2355 }
2356 
2357 /* Compare doubles with a margine to allow */
2358 /* for floating point handling funnies */
dcomp(double a,double b)2359 int dcomp(double a, double b) {
2360 	double dif = fabs(a - b);
2361 	double mag = fabs(a) + fabs(b);
2362 
2363 	return dif > (mag * 1e-10) ? 1 : 0;
2364 }
2365 
2366 /* ------------------------------------------------ */
2367 /* Basic printf type error() and warning() routines */
2368 
2369 void
error(char * fmt,...)2370 error(char *fmt, ...)
2371 {
2372 	va_list args;
2373 
2374 	fprintf(stderr,"icctest: Error - ");
2375 	va_start(args, fmt);
2376 	vfprintf(stderr, fmt, args);
2377 	va_end(args);
2378 	fprintf(stderr, "\n");
2379 	exit (-1);
2380 }
2381 
2382 void
warning(char * fmt,...)2383 warning(char *fmt, ...)
2384 {
2385 	va_list args;
2386 
2387 	fprintf(stderr,"icctest: Warning - ");
2388 	va_start(args, fmt);
2389 	vfprintf(stderr, fmt, args);
2390 	va_end(args);
2391 	fprintf(stderr, "\n");
2392 }
2393