Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/cmd/gs/icclib/icc.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
 
2
/* 
3
 * International Color Consortium Format Library (icclib)
4
 * For ICC profile version 3.4
5
 *
6
 * Author:  Graeme W. Gill
7
 * Date:    2002/04/22
8
 * Version: 2.02
9
 *
10
 * Copyright 1997 - 2002 Graeme W. Gill
11
 * See Licence.txt file for conditions of use.
12
 */
13
 
14
/*
15
 * TTBD:
16
 *
17
 *      Add a "warning mode" to file reading, in which file format
18
 *      errors are ignored where possible, rather than generating
19
 *      a fatal error (see ICM_STRICT #define).
20
 *
21
 *      NameColor Dump doesn't handle device space correctly - 
22
 *	    should use appropriate interpretation in case device is Lab etc.
23
 *
24
 *      Should recognise & honour unicode 0xFFFE endian marker.
25
 *      Should generate it on writing too ?
26
 *
27
 *		Should fix all write_number failure errors to indicate failed value.
28
 *		(Partially implemented - need to check all write_number functions)
29
 *
30
 *		Make write fail error messages be specific on which element failed.
31
 *
32
 *		Should add named color space lookup function support.
33
 *
34
 *		Should probably reject reading or writing profiles with majv != 2 ?
35
 *
36
 *      Would be nice to add generic ability to add new tag type handling,
37
 *      so that the base library doesn't need to be modified (ie. VideoCardGamma) ?
38
 *
39
 *		Need to add DeviceSettings and OutputResponse tags to bring up to
40
 *		ICC.1:1998-09 [started but not complete]
41
 *
42
 */
43
 
44
#undef ICM_STRICT	/* Not fully implimented - switch off strict checking of file format */
45
 
46
/* Trial: Make the default grid points of the Lab clut be symetrical about */
47
/*        a/b 0.0, and also make L = 100.0 fall on a grid point. */
48
/*        This seems a good idea. */
49
 
50
#define SYMETRICAL_DEFAULT_LAB_RANGE
51
 
52
/*
53
 * Change History:
54
 * 
55
 * 2.02
56
 *      Merged rename of [u]int64 to icm[Ui][I]nt64 (to work around
57
 *      AIX 5.1L portability bug) from Raph Levien.
58
 *
59
 *      Fixed stray , in icmLookupOrder structure definition (from Dan Coby)
60
 *
61
 * 2.01
62
 *		Change TextDescription code to not barf if #undef ICM_STRICT and
63
 *      Apple scriptcode not padded to 67 bytes.
64
 *
65
 *      Add get_ranges() method to all Lu types, not just LuLut.
66
 *      Fix bug in PCS overide logic that was causing
67
 *		reverse conversions to apply the wrong conversion.
68
 *
69
 *      Added Delta E convenience functions icmLabDE() and
70
 *      icmCIE94() etc.
71
 *
72
 *		Merged Raph Levien's cleanups, to quiet gcc warnings.
73
 *
74
 *      Merged another couple of warning cleanups from Jouk Jansen.
75
 *
76
 * 2.00
77
 *      Change absolute conversion to be white point only, and use
78
 *      Bradford transform by default. (ie. we are now ignoring the
79
 *      comment in section 6.4.22 of the 1998 spec. about the
80
 *      media black point being used for absolute colorimetry,
81
 *      ignoring the recommendation on page 118 in section E.5,
82
 *      and are taking up the recommendation on page 124 in section
83
 *      E.16 that a more sophisticated chromatic adaption model be used.)
84
 *
85
 *      This is for better compatibility with other CMM's, and to
86
 *      improve the results when using simple links between
87
 *      profiles with non-D50 white points. Standard profiles
88
 *      like sRGB will also be more accurate when interpreted
89
 *      with absolute colorimetric intent.
90
 *      This will cause some slight incompatibilty with previous
91
 *      versions of icclib.
92
 *
93
 *      Added ColorSync 2.5 specific VideoCardGamma tag support
94
 *      (from Neil Okamoto)
95
 *
96
 * 1.31
97
 *      Added file I/O class to allow substitution of alternative ICC profile
98
 *      file access. Provide standard file class instance, and memory image
99
 *      instance of file I/O class as default and example. 
100
 *      Added an optional new_icc_a() object creator, that takes a memory
101
 *      allocator class instance. This allows an alternate memory heap to
102
 *      be used with the icc class. 
103
 *      Renamed object free() methods to del() for more consistency with new().
104
 *
105
 * 1.30	
106
 *      Added workaround for reading some Adobe profiles with confused header DateTime.
107
 *      Enhanced tag allocate() methods so that they can resize allocations.
108
 *      Enhanced icmLut_set_tables() to access grid points in a cache friendly order.
109
 *      Fixed bug in check_icc_legal() that caused bogus errors, removed
110
 *      uneccessary static declarations in icc.h, and fixed a bug in
111
 *      icmTable_lookup_bwd() that effected both accuracy and speed. (Thanks to Andrei Frolov)
112
 *      Removed icmAbsoluteColorimetricXYZ intent, and replaced it with
113
 *      a PCS overide capability. This adds a new parameter to get_luobj() 
114
 *      Added Lab translations of some XYZ "dump" strings.
115
 *      Fix memory leak after failed tag read + rename_tag function
116
 *      + shared library support changes. (Thanks to Carles Llopis).
117
 *		Changed all the public 2str utility routines to a single function
118
 *      that can be used to interpret an enumeration or tag in a human
119
 *      readable form. 
120
 *
121
 * 1.23	
122
 *      Fixed important bug in Lut read/write. The matrix values had their
123
 *      rows and columns switched. Not many profiles exercise this code.
124
 *      Thanks to David Gillman for discovering this problem.
125
 *      Fixup compiler complains about illegal enum values for icmCurveStyle,
126
 *      and icmDataStyle. Malloc memory icmLut_lookup_clut_nl for gw[], so that
127
 *      it is more friendly to systems with a limited stack. (Thanks to Dave White)
128
 *
129
 * 1.22	99/11/11 Snapshot of current code.
130
 *      Added more hooks to support inherited implementation of
131
 *      color conversion, used in Argyll to support reversing
132
 *      multi-dimentional table lookups.
133
 *      Cleaned up color conversion code to make it easier to follow.
134
 *      Adding simplex interpolation for non-Lab style input space interpolation.
135
 *      Fix Sun misalignment and realloc problems (Thanks to Allan N. Hessenflow)
136
 *      Fixed endian problem with Unicode on read and write.
137
 *      Expanded icmTextDescription_dump() to do hex dump of Unicode and ScriptCode.
138
 *      Changed over to ICC.1:1998-09 .h file.
139
 *      Started implementing ICC.1:1998-09, but not complete yet!
140
 *
141
 * 1.21	99/2/14
142
 *     	After re-reading Michael Bourgoin's 1998 SIGGRAPH notes,
143
 *      I have consolidated the Lut input index, and table value encodings.
144
 *      The default set_tables() scaling has been adjusted appropriately
145
 *      for this correction of Lab encoding.
146
 *      Trying to create an 8 bit XYZ Lut will now fail if icclib helper
147
 *      functions are used to create it.
148
 * 
149
 * 1.20	99/2/7
150
 *      Added profile color lookup functon.
151
 *      Added set_tables() support.
152
 *      Various bug fixes and enhancements.
153
 */
154
 
155
#include <stdio.h>
156
#include <stdlib.h>
157
#include <stdarg.h>
158
#include <sys/types.h>
159
#include <string.h>
160
#include <ctype.h>
161
#include <math.h>
162
#include <time.h>
163
#ifdef __sun
164
#include <unistd.h>
165
#endif
166
#if defined(__IBMC__) && defined(_M_IX86)
167
#include <float.h>
168
#endif
169
#include "icc.h"
170
 
171
/* ========================================================== */
172
/* Default system interface object implementations */
173
 
174
/* Standard Stream file I/O icmFile compatible class */
175
/* Note that this uses malloc, so replace class if */
176
/* you need a different memory allocator. */
177
 
178
/* Set current position to offset. Return 0 on success, nz on failure. */
179
static int icmFileStd_seek(
180
icmFile *pp,
181
long int offset
182
) {
183
	icmFileStd *p = (icmFileStd *)pp;
184
 
185
	return fseek(p->fp, offset, SEEK_SET);
186
}
187
 
188
/* Read count items of size length. Return number of items successfully read. */
189
static size_t icmFileStd_read(
190
icmFile *pp,
191
void *buffer,
192
size_t size,
193
size_t count
194
) {
195
	icmFileStd *p = (icmFileStd *)pp;
196
 
197
	return fread(buffer, size, count, p->fp);
198
}
199
 
200
/* write count items of size length. Return number of items successfully written. */
201
static size_t icmFileStd_write(
202
icmFile *pp,
203
void *buffer,
204
size_t size,
205
size_t count
206
) {
207
	icmFileStd *p = (icmFileStd *)pp;
208
 
209
	return fwrite(buffer, size, count, p->fp);
210
}
211
 
212
 
213
/* flush all write data out to secondary storage. Return nz on failure. */
214
static int icmFileStd_flush(
215
icmFile *pp
216
) {
217
	icmFileStd *p = (icmFileStd *)pp;
218
 
219
	return fflush(p->fp);
220
}
221
 
222
/* we're done with the file object, return nz on failure */
223
static int icmFileStd_delete(
224
icmFile *pp
225
) {
226
	icmFileStd *p = (icmFileStd *)pp;
227
 
228
	if (p->doclose != 0) {
229
		if (fclose(p->fp) != 0)
230
			return 2;
231
	}
232
 
233
	free(p);
234
	return 0;
235
}
236
 
237
/* Create icmFile given a (binary) FILE* */
238
icmFile *new_icmFileStd_fp(
239
FILE *fp
240
) {
241
	icmFileStd *p;
242
	if ((p = (icmFileStd *) calloc(1,sizeof(icmFileStd))) == NULL)
243
		return NULL;
244
	p->seek  = icmFileStd_seek;
245
	p->read  = icmFileStd_read;
246
	p->write = icmFileStd_write;
247
	p->flush = icmFileStd_flush;
248
	p->del   = icmFileStd_delete;
249
 
250
	p->fp = fp;
251
	p->doclose = 0;
252
 
253
	return (icmFile *)p;
254
}
255
 
256
/* Create icmFile given a file name */
257
icmFile *new_icmFileStd_name(
258
char *name,
259
char *mode
260
) {
261
	FILE *fp;
262
	icmFile *p;
263
#if defined(O_BINARY)
264
	char nmode[50];
265
#endif
266
 
267
	if ((fp = fopen(name,mode)) == NULL)
268
		return NULL;
269
 
270
#if defined(O_BINARY)
271
	strcpy(nmode, mode);
272
	strcat(nmode, "b");
273
	if ((fp = freopen(name, nmode, fp)) == NULL)
274
		return NULL;
275
#endif
276
 
277
	p = new_icmFileStd_fp(fp);
278
 
279
	if (p != NULL) {
280
		icmFileStd *pp = (icmFileStd *)p;
281
		pp->doclose = 1;
282
	}
283
	return p;
284
}
285
 
286
/* ------------------------------------------------- */
287
/* Memory image icmFile compatible class */
288
/* Note that this uses malloc, so replace class if */
289
/* you need a different memory allocator. */
290
 
291
/* Set current position to offset. Return 0 on success, nz on failure. */
292
static int icmFileMem_seek(
293
icmFile *pp,
294
long int offset
295
) {
296
	icmFileMem *p = (icmFileMem *)pp;
297
	unsigned char *np;
298
 
299
	np = p->start + offset;
300
	if (np < p->start || np >= p->end)
301
		return 1;
302
	p->cur = np;
303
	return 0;
304
}
305
 
306
/* Read count items of size length. Return number of items successfully read. */
307
static size_t icmFileMem_read(
308
icmFile *pp,
309
void *buffer,
310
size_t size,
311
size_t count
312
) {
313
	icmFileMem *p = (icmFileMem *)pp;
314
	size_t len;
315
 
316
	len = size * count;
317
	if ((p->cur + len) >= p->end) {		/* Too much */
318
		if (size > 0)
319
			count = (p->end - p->cur)/size;
320
		else
321
			count = 0;
322
	}
323
	len = size * count;
324
	if (len > 0)
325
		memcpy (buffer, p->cur, len);
326
	p->cur += len;
327
	return count;
328
}
329
 
330
/* write count items of size length. Return number of items successfully written. */
331
static size_t icmFileMem_write(
332
icmFile *pp,
333
void *buffer,
334
size_t size,
335
size_t count
336
) {
337
	icmFileMem *p = (icmFileMem *)pp;
338
	size_t len;
339
 
340
	len = size * count;
341
	if ((p->cur + len) >= p->end) {		/* Too much */
342
		if (size > 0)
343
			count = (p->end - p->cur)/size;
344
		else
345
			count = 0;
346
	}
347
	len = size * count;
348
	if (len > 0)
349
		memcpy (p->cur, buffer, len);
350
	p->cur += len;
351
	return count;
352
}
353
 
354
 
355
/* flush all write data out to secondary storage. Return nz on failure. */
356
static int icmFileMem_flush(
357
icmFile *pp
358
) {
359
	return 0;
360
}
361
 
362
/* we're done with the file object, return nz on failure */
363
static int icmFileMem_delete(
364
icmFile *pp
365
) {
366
	icmFileMem *p = (icmFileMem *)pp;
367
 
368
	free(p);
369
	return 0;
370
}
371
 
372
/* Create a memory image file access class */
373
icmFile *new_icmFileMem(
374
void *base,				/* Pointer to base of memory buffer */
375
size_t length			/* Number of bytes in buffer */
376
) {
377
	icmFileMem *p;
378
	if ((p = (icmFileMem *) calloc(1,sizeof(icmFileMem))) == NULL)
379
		return NULL;
380
	p->seek  = icmFileMem_seek;
381
	p->read  = icmFileMem_read;
382
	p->write = icmFileMem_write;
383
	p->flush = icmFileMem_flush;
384
	p->del   = icmFileMem_delete;
385
 
386
	p->cur = p->start = base;
387
	p->end = p->start + length;
388
 
389
	return (icmFile *)p;
390
}
391
 
392
/* ------------------------------------------------- */
393
/* Standard Heap allocator icmAlloc compatible class */
394
/* Just call the standard system function */
395
 
396
static void *icmAllocStd_malloc(
397
struct _icmAlloc *pp,
398
size_t size
399
) {
400
	return malloc(size);
401
}
402
 
403
static void *icmAllocStd_calloc(
404
struct _icmAlloc *pp,
405
size_t num,
406
size_t size
407
) {
408
	return calloc(num, size);
409
}
410
 
411
static void *icmAllocStd_realloc(
412
struct _icmAlloc *pp,
413
void *ptr,
414
size_t size
415
) {
416
	return realloc(ptr, size);
417
}
418
 
419
 
420
static void icmAllocStd_free(
421
struct _icmAlloc *pp,
422
void *ptr
423
) {
424
	free(ptr);
425
}
426
 
427
/* we're done with the AllocStd object */
428
static void icmAllocStd_delete(
429
icmAlloc *pp
430
) {
431
	icmAllocStd *p = (icmAllocStd *)pp;
432
 
433
	free(p);
434
}
435
 
436
/* Create icmAllocStd */
437
icmAlloc *new_icmAllocStd() {
438
	icmAllocStd *p;
439
	if ((p = (icmAllocStd *) calloc(1,sizeof(icmAllocStd))) == NULL)
440
		return NULL;
441
	p->malloc  = icmAllocStd_malloc;
442
	p->calloc  = icmAllocStd_calloc;
443
	p->realloc = icmAllocStd_realloc;
444
	p->free    = icmAllocStd_free;
445
	p->del     = icmAllocStd_delete;
446
 
447
	return (icmAlloc *)p;
448
}
449
 
450
/* ========================================================== */
451
/* Conversion support functions */
452
/* Convert between ICC storage types and native C types */
453
/* Write routine return non-zero if numbers can't be represented */
454
 
455
/* Unsigned */
456
static unsigned int read_UInt8Number(char *p) {
457
	unsigned int rv;
458
	rv = (unsigned int)((ORD8 *)p)[0];
459
	return rv;
460
}
461
 
462
static int write_UInt8Number(unsigned int d, char *p) {
463
	if (d > 255)
464
		return 1;
465
	((ORD8 *)p)[0] = (ORD8)d;
466
	return 0;
467
}
468
 
469
static unsigned int read_UInt16Number(char *p) {
470
	unsigned int rv;
471
	rv = 256 * (unsigned int)((ORD8 *)p)[0]
472
	   +       (unsigned int)((ORD8 *)p)[1];
473
	return rv;
474
}
475
 
476
static int write_UInt16Number(unsigned int d, char *p) {
477
	if (d > 65535)
478
		return 1;
479
	((ORD8 *)p)[0] = (ORD8)(d >> 8);
480
	((ORD8 *)p)[1] = (ORD8)(d);
481
	return 0;
482
}
483
 
484
static unsigned int read_UInt32Number(char *p) {
485
	unsigned int rv;
486
	rv = 16777216 * (unsigned int)((ORD8 *)p)[0]
487
	   +    65536 * (unsigned int)((ORD8 *)p)[1]
488
	   +      256 * (unsigned int)((ORD8 *)p)[2]
489
	   +            (unsigned int)((ORD8 *)p)[3];
490
	return rv;
491
}
492
 
493
static int write_UInt32Number(unsigned int d, char *p) {
494
	((ORD8 *)p)[0] = (ORD8)(d >> 24);
495
	((ORD8 *)p)[1] = (ORD8)(d >> 16);
496
	((ORD8 *)p)[2] = (ORD8)(d >> 8);
497
	((ORD8 *)p)[3] = (ORD8)(d);
498
	return 0;
499
}
500
 
501
static void read_UInt64Number(icmUint64 *d, char *p) {
502
	d->h = 16777216 * (unsigned int)((ORD8 *)p)[0]
503
	     +    65536 * (unsigned int)((ORD8 *)p)[1]
504
	     +      256 * (unsigned int)((ORD8 *)p)[2]
505
	     +            (unsigned int)((ORD8 *)p)[3];
506
	d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
507
	     +    65536 * (unsigned int)((ORD8 *)p)[5]
508
	     +      256 * (unsigned int)((ORD8 *)p)[6]
509
	     +            (unsigned int)((ORD8 *)p)[7];
510
}
511
 
512
static int write_UInt64Number(icmUint64 *d, char *p) {
513
	((ORD8 *)p)[0] = (ORD8)(d->h >> 24);
514
	((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
515
	((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
516
	((ORD8 *)p)[3] = (ORD8)(d->h);
517
	((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
518
	((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
519
	((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
520
	((ORD8 *)p)[7] = (ORD8)(d->l);
521
	return 0;
522
}
523
 
524
static double read_U8Fixed8Number(char *p) {
525
	ORD32 o32;
526
	o32 = 256 * (ORD32)((ORD8 *)p)[0]		/* Read big endian 16 bit unsigned */
527
        +       (ORD32)((ORD8 *)p)[1];
528
	return (double)o32/256.0;
529
}
530
 
531
static int write_U8Fixed8Number(double d, char *p) {
532
	ORD32 o32;
533
	d = d * 256.0 + 0.5;
534
	if (d >= 65536.0)
535
		return 1;
536
	if (d < 0.0)
537
		return 1;
538
	o32 = (ORD32)d;
539
	((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
540
	((ORD8 *)p)[1] = (ORD8)((o32));
541
	return 0;
542
}
543
 
544
static double read_U16Fixed16Number(char *p) {
545
	ORD32 o32;
546
	o32 = 16777216 * (ORD32)((ORD8 *)p)[0]		/* Read big endian 32 bit unsigned */
547
        +    65536 * (ORD32)((ORD8 *)p)[1]
548
	    +      256 * (ORD32)((ORD8 *)p)[2]
549
	    +            (ORD32)((ORD8 *)p)[3];
550
	return (double)o32/65536.0;
551
}
552
 
553
static int write_U16Fixed16Number(double d, char *p) {
554
	ORD32 o32;
555
	d = d * 65536.0 + 0.5;
556
	if (d >= 4294967296.0)
557
		return 1;
558
	if (d < 0.0)
559
		return 1;
560
	o32 = (ORD32)d;
561
	((ORD8 *)p)[0] = (ORD8)((o32) >> 24);
562
	((ORD8 *)p)[1] = (ORD8)((o32) >> 16);
563
	((ORD8 *)p)[2] = (ORD8)((o32) >> 8);
564
	((ORD8 *)p)[3] = (ORD8)((o32));
565
	return 0;
566
}
567
 
568
 
569
#ifdef NEVER	/* Not currently used anywhere */
570
 
571
/* Signed numbers */
572
static int read_SInt8Number(char *p) {
573
	int rv;
574
	rv = (int)((INR8 *)p)[0];
575
	return rv;
576
}
577
 
578
static int write_SInt8Number(int d, char *p) {
579
	if (d > 127)
580
		return 1;
581
	else if (d < -128)
582
		return 1;
583
	((INR8 *)p)[0] = (INR8)d;
584
	return 0;
585
}
586
 
587
static int read_SInt16Number(char *p) {
588
	int rv;
589
	rv = 256 * (int)((INR8 *)p)[0]
590
	   +       (int)((ORD8 *)p)[1];
591
	return rv;
592
}
593
 
594
static int write_SInt16Number(int d, char *p) {
595
	if (d > 32767)
596
		return 1;
597
	else if (d < -32768)
598
		return 1;
599
	((INR8 *)p)[0] = (INR8)(d >> 8);
600
	((ORD8 *)p)[1] = (ORD8)(d);
601
	return 0;
602
}
603
 
604
#endif /* NEVER */
605
 
606
static int read_SInt32Number(char *p) {
607
	int rv;
608
	rv = 16777216 * (int)((INR8 *)p)[0]
609
	   +    65536 * (int)((ORD8 *)p)[1]
610
	   +      256 * (int)((ORD8 *)p)[2]
611
	   +            (int)((ORD8 *)p)[3];
612
	return rv;
613
}
614
 
615
static int write_SInt32Number(int d, char *p) {
616
	((INR8 *)p)[0] = (INR8)(d >> 24);
617
	((ORD8 *)p)[1] = (ORD8)(d >> 16);
618
	((ORD8 *)p)[2] = (ORD8)(d >> 8);
619
	((ORD8 *)p)[3] = (ORD8)(d);
620
	return 0;
621
}
622
 
623
#ifdef NEVER /* Not currently used anywhere */
624
 
625
static void read_SInt64Number(icmInt64 *d, char *p) {
626
	d->h = 16777216 * (int)((INR8 *)p)[0]
627
	     +    65536 * (int)((ORD8 *)p)[1]
628
	     +      256 * (int)((ORD8 *)p)[2]
629
	     +            (int)((ORD8 *)p)[3];
630
	d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
631
	     +    65536 * (unsigned int)((ORD8 *)p)[5]
632
	     +      256 * (unsigned int)((ORD8 *)p)[6]
633
	     +            (unsigned int)((ORD8 *)p)[7];
634
}
635
 
636
static int write_SInt64Number(icmInt64 *d, char *p) {
637
	((INR8 *)p)[0] = (INR8)(d->h >> 24);
638
	((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
639
	((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
640
	((ORD8 *)p)[3] = (ORD8)(d->h);
641
	((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
642
	((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
643
	((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
644
	((ORD8 *)p)[7] = (ORD8)(d->l);
645
	return 0;
646
}
647
 
648
#endif /* NEVER */
649
 
650
static double read_S15Fixed16Number(char *p) {
651
	INR32 i32;
652
	i32 = 16777216 * (INR32)((INR8 *)p)[0]		/* Read big endian 32 bit signed */
653
        +    65536 * (INR32)((ORD8 *)p)[1]
654
	    +      256 * (INR32)((ORD8 *)p)[2]
655
	    +            (INR32)((ORD8 *)p)[3];
656
	return (double)i32/65536.0;
657
}
658
 
659
static int write_S15Fixed16Number(double d, char *p) {
660
	INR32 i32;
661
	d = ceil(d * 65536.0);		/* Beware! (int)(d + 0.5) doesn't work! */
662
	if (d >= 2147483648.0)
663
		return 1;
664
	if (d < -2147483648.0)
665
		return 1;
666
	i32 = (INR32)d;
667
	((INR8 *)p)[0] = (INR8)((i32) >> 24);		/* Write big endian 32 bit signed */
668
	((ORD8 *)p)[1] = (ORD8)((i32) >> 16);
669
	((ORD8 *)p)[2] = (ORD8)((i32) >> 8);
670
	((ORD8 *)p)[3] = (ORD8)((i32));
671
	return 0;
672
}
673
 
674
/* PCS encoded numbers */
675
 
676
/* 16 bit XYZ  - value range 0.0 - 1.9997 */
677
static double read_PCSXYZ16Number(char *p) {
678
	ORD32 o32;
679
	o32 = 256 * (ORD32)((ORD8 *)p)[0]		/* Read big endian 16 bit unsigned */
680
        +       (ORD32)((ORD8 *)p)[1];
681
	return (double)o32/32768.0;
682
}
683
 
684
static int write_PCSXYZ16Number(double d, char *p) {
685
	ORD32 o32;
686
	d = d * 32768.0 + 0.5;
687
	if (d >= 65536.0)
688
		return 1;
689
	if (d < 0.0)
690
		return 1;
691
	o32 = (ORD32)d;
692
	((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
693
	((ORD8 *)p)[1] = (ORD8)((o32));
694
	return 0;
695
}
696
 
697
#ifdef NEVER /* Not currently used */
698
 
699
/* L part of 8 bit Lab - value range 0.0 - 100.0 */
700
static double read_PCSL8Number(char *p) {
701
	ORD32 o32;
702
	o32 = (ORD32)((ORD8 *)p)[0];		/* Read big endian 8 bit unsigned */
703
	return (double)o32/2.550;
704
}
705
 
706
static int write_PCSL8Number(double d, char *p) {
707
	ORD32 o32;
708
	d = d * 2.550 + 0.5;
709
	if (d >= 256.0)
710
		return 1;
711
	if (d < 0.0)
712
		return 1;
713
	o32 = (ORD32)d;
714
	((ORD8 *)p)[0] = (ORD8)((o32));
715
	return 0;
716
}
717
 
718
/* ab part of 8 bit Lab - value range -128.0 - 127.0 */
719
static double read_PCSab8Number(char *p) {
720
	ORD32 o32;
721
	o32 = (ORD32)((ORD8 *)p)[0];	/* Read big endian 8 bit unsigned */
722
	return (double)o32-128.0;
723
}
724
 
725
static int write_PCSab8Number(double d, char *p) {
726
	ORD32 o32;
727
	d = (d+128.0) + 0.5;
728
	if (d >= 256.0)
729
		return 1;
730
	if (d < 0.0)
731
		return 1;
732
	o32 = (ORD32)d;
733
	((ORD8 *)p)[0] = (ORD8)((o32));
734
	return 0;
735
}
736
 
737
#endif /* NEVER */
738
 
739
/* L part of 16 bit Lab - value range 0.0 - 100.0 */
740
static double read_PCSL16Number(char *p) {
741
	ORD32 o32;
742
	o32 = 256 * (ORD32)((ORD8 *)p)[0]		/* Read big endian 16 bit unsigned */
743
        +       (ORD32)((ORD8 *)p)[1];
744
	return (double)o32/652.800;				/* 0xff00/100.0 */
745
}
746
 
747
static int write_PCSL16Number(double d, char *p) {
748
	ORD32 o32;
749
	d = d * 652.800 + 0.5;
750
	if (d >= 65536.0)
751
		return 1;
752
	if (d < 0.0)
753
		return 1;
754
	o32 = (ORD32)d;
755
	((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
756
	((ORD8 *)p)[1] = (ORD8)((o32));
757
	return 0;
758
}
759
 
760
/* ab part of 16 bit Lab - value range -128.0 - 127.9961 */
761
static double read_PCSab16Number(char *p) {
762
	ORD32 o32;
763
	o32 = 256 * (ORD32)((ORD8 *)p)[0]		/* Read big endian 16 bit unsigned */
764
        +       (ORD32)((ORD8 *)p)[1];
765
	return ((double)o32/256.0)-128.0;
766
}
767
 
768
static int write_PCSab16Number(double d, char *p) {
769
	ORD32 o32;
770
	d = (d+128.0) * 256.0 + 0.5;
771
	if (d >= 65536.0)
772
		return 1;
773
	if (d < 0.0)
774
		return 1;
775
	o32 = (ORD32)d;
776
	((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
777
	((ORD8 *)p)[1] = (ORD8)((o32));
778
	return 0;
779
}
780
 
781
/* Device coordinate as 8 bit value range 0.0 - 1.0 */
782
static double read_DCS8Number(char *p) {
783
	unsigned int rv;
784
	rv =   (unsigned int)((ORD8 *)p)[0];
785
	return (double)rv/255.0;
786
}
787
 
788
static int write_DCS8Number(double d, char *p) {
789
	ORD32 o32;
790
	d = d * 255.0 + 0.5;
791
	if (d >= 256.0)
792
		return 1;
793
	if (d < 0.0)
794
		return 1;
795
	o32 = (ORD32)d;
796
	((ORD8 *)p)[0] = (ORD8)(o32);
797
	return 0;
798
}
799
 
800
/* Device coordinate as 16 bit value range 0.0 - 1.0 */
801
static double read_DCS16Number(char *p) {
802
	unsigned int rv;
803
	rv = 256 * (unsigned int)((ORD8 *)p)[0]
804
	   +       (unsigned int)((ORD8 *)p)[1];
805
	return (double)rv/65535.0;
806
}
807
 
808
static int write_DCS16Number(double d, char *p) {
809
	ORD32 o32;
810
	d = d * 65535.0 + 0.5;
811
	if (d >= 65536.0)
812
		return 1;
813
	if (d < 0.0)
814
		return 1;
815
	o32 = (ORD32)d;
816
	((ORD8 *)p)[0] = (ORD8)(o32 >> 8);
817
	((ORD8 *)p)[1] = (ORD8)(o32);
818
	return 0;
819
}
820
 
821
/* ---------------------------------------------------------- */
822
/* Auiliary function - return a string that represents a tag */
823
/* Note - returned buffers are static, can only be used 5 */
824
/* times before buffers get reused. */
825
char *tag2str(
826
	int tag
827
) {
828
	int i;
829
	static int si = 0;			/* String buffer index */
830
	static char buf[5][20];		/* String buffers */
831
	char *bp;
832
	unsigned char c[4];
833
 
834
	bp = buf[si++];
835
	si %= 5;				/* Rotate through buffers */
836
 
837
	c[0] = 0xff & (tag >> 24);
838
	c[1] = 0xff & (tag >> 16);
839
	c[2] = 0xff & (tag >> 8);
840
	c[3] = 0xff & (tag >> 0);
841
	for (i = 0; i < 4; i++) {	/* Can we represent it as a string ? */
842
		if (!isprint(c[i]))
843
			break;
844
	}
845
	if (i < 4) {	/* Not printable - use hex */
846
		sprintf(bp,"0x%x",tag);
847
	} else {		/* Printable */
848
		sprintf(bp,"'%c%c%c%c'",c[0],c[1],c[2],c[3]);
849
	}
850
	return bp;
851
}
852
 
853
/* Auiliary function - return a tag created from a string */
854
int str2tag(
855
	const char *str
856
) {
857
	unsigned long tag;
858
	tag = (((unsigned long)str[0]) << 24)
859
	    + (((unsigned long)str[1]) << 16)
860
	    + (((unsigned long)str[2]) << 8)
861
	    + (((unsigned long)str[3]));
862
	return (int)tag;
863
}
864
 
865
/* helper - return 1 if the string doesn't have a */
866
/*  null terminator, return 0 if it does. */
867
/* Note: will return 1 if len == 0 */
868
static int check_null_string(char *cp, int len) {
869
	for (; len > 0; len--) {
870
		if (*cp++ == '\000')
871
			break;
872
	}
873
	if (len == 0)
874
		return 1;
875
	return 0;
876
}
877
 
878
/* helper - return 1 if the string doesn't have a */
879
/*  null terminator, return 0 if it does. */
880
/* Note: will return 1 if len == 0 */
881
/* Unicode version */
882
static int check_null_string16(char *cp, int len) {
883
	for (; len > 0; len--) {	/* Length is in characters */
884
		if (cp[0] == 0 && cp[1] == 0)
885
			break;
886
		cp += 2;
887
	}
888
	if (len == 0) 
889
		return 1;
890
	return 0;
891
}
892
 
893
/* Color Space to number of component conversion */
894
/* Return 0 on error */
895
static unsigned int number_ColorSpaceSignature(icColorSpaceSignature sig) {
896
	switch(sig) {
897
		case icSigXYZData:
898
			return 3;
899
		case icSigLabData:
900
			return 3;
901
		case icSigLuvData:
902
			return 3;
903
		case icSigYCbCrData:
904
			return 3;
905
		case icSigYxyData:
906
			return 3;
907
		case icSigRgbData:
908
			return 3;
909
		case icSigGrayData:
910
			return 1;
911
		case icSigHsvData:
912
			return 3;
913
		case icSigHlsData:
914
			return 3;
915
		case icSigCmykData:
916
			return 4;
917
		case icSigCmyData:
918
			return 3;
919
		case icSig2colorData:
920
			return 2;
921
		case icSig3colorData:
922
			return 3;
923
		case icSig4colorData:
924
			return 4;
925
		case icSig5colorData:
926
		case icSigMch5Data:
927
			return 5;
928
		case icSig6colorData:
929
		case icSigMch6Data:
930
			return 6;
931
		case icSig7colorData:
932
		case icSigMch7Data:
933
			return 7;
934
		case icSig8colorData:
935
		case icSigMch8Data:
936
			return 8;
937
		case icSig9colorData:
938
			return 9;
939
		case icSig10colorData:
940
			return 10;
941
		case icSig11colorData:
942
			return 11;
943
		case icSig12colorData:
944
			return 12;
945
		case icSig13colorData:
946
			return 13;
947
		case icSig14colorData:
948
			return 14;
949
		case icSig15colorData:
950
			return 15;
951
		default:
952
			return 0;
953
	}
954
}
955
 
956
/* ------------------------------------------------------- */
957
/* Flag dump functions */
958
/* Note - returned buffers are static, can only be used 5 */
959
/* times before buffers get reused. */
960
 
961
/* Screening Encodings */
962
static char *string_ScreenEncodings(unsigned long flags) {
963
	static int si = 0;			/* String buffer index */
964
	static char buf[5][80];		/* String buffers */
965
	char *bp, *cp;
966
 
967
	cp = bp = buf[si++];
968
	si %= 5;				/* Rotate through buffers */
969
 
970
	if (flags & icPrtrDefaultScreensTrue) {
971
		sprintf(cp,"Default Screen");
972
	} else {
973
		sprintf(cp,"No Default Screen");
974
	}
975
	cp = cp + strlen(cp);
976
	if (flags & icLinesPerInch) {
977
		sprintf(cp,", Lines Per Inch");
978
	} else {
979
		sprintf(cp,", Lines Per cm");
980
	}
981
	cp = cp + strlen(cp);
982
 
983
	return bp;
984
}
985
 
986
/* Device attributes */
987
static char *string_DeviceAttributes(unsigned long flags) {
988
	static int si = 0;			/* String buffer index */
989
	static char buf[5][80];		/* String buffers */
990
	char *bp, *cp;
991
 
992
	cp = bp = buf[si++];
993
	si %= 5;				/* Rotate through buffers */
994
 
995
	if (flags & icTransparency) {
996
		sprintf(cp,"Transparency");
997
	} else {
998
		sprintf(cp,"Reflective");
999
	}
1000
	cp = cp + strlen(cp);
1001
	if (flags & icMatte) {
1002
		sprintf(cp,", Matte");
1003
	} else {
1004
		sprintf(cp,", Glossy");
1005
	}
1006
	cp = cp + strlen(cp);
1007
 
1008
	return bp;
1009
}
1010
 
1011
/* Profile header flags */
1012
static char *string_ProfileHeaderFlags(unsigned long flags) {
1013
	static int si = 0;			/* String buffer index */
1014
	static char buf[5][80];		/* String buffers */
1015
	char *bp, *cp;
1016
 
1017
	cp = bp = buf[si++];
1018
	si %= 5;				/* Rotate through buffers */
1019
 
1020
	if (flags & icEmbeddedProfileTrue) {
1021
		sprintf(cp,"Embedded Profile");
1022
	} else {
1023
		sprintf(cp,"Not Embedded Profile");
1024
	}
1025
	cp = cp + strlen(cp);
1026
	if (flags & icUseWithEmbeddedDataOnly) {
1027
		sprintf(cp,", Use with embedded data only");
1028
	} else {
1029
		sprintf(cp,", Use anywhere");
1030
	}
1031
	cp = cp + strlen(cp);
1032
 
1033
	return bp;
1034
}
1035
 
1036
 
1037
static char *string_AsciiOrBinaryData(unsigned long flags) {
1038
	static int si = 0;			/* String buffer index */
1039
	static char buf[5][80];		/* String buffers */
1040
	char *bp, *cp;
1041
 
1042
	cp = bp = buf[si++];
1043
	si %= 5;				/* Rotate through buffers */
1044
 
1045
	if (flags & icBinaryData) {
1046
		sprintf(cp,"Binary");
1047
	} else {
1048
		sprintf(cp,"Ascii");
1049
	}
1050
	cp = cp + strlen(cp);
1051
 
1052
	return bp;
1053
}
1054
 
1055
/* ------------------------------------------------------------ */
1056
/* Enumeration dump functions */
1057
/* Note - returned buffers are static, can only be used once */
1058
/* before buffers get reused if type is unknown. */
1059
 
1060
/* public tags and sizes */
1061
static const char *string_TagSignature(icTagSignature sig) {
1062
	static char buf[80];
1063
	switch(sig) {
1064
		case icSigAToB0Tag:
1065
			return "AToB0 Multidimentional Transform";
1066
		case icSigAToB1Tag:
1067
			return "AToB1 Multidimentional Transform";
1068
		case icSigAToB2Tag:
1069
			return "AToB2 Multidimentional Transform";
1070
		case icSigBlueColorantTag:
1071
			return "Blue Colorant";
1072
		case icSigBlueTRCTag:
1073
			return "Blue Tone Reproduction Curve";
1074
		case icSigBToA0Tag:
1075
			return "BToA0 Multidimentional Transform";
1076
		case icSigBToA1Tag:
1077
			return "BToA1 Multidimentional Transform";
1078
		case icSigBToA2Tag:
1079
			return "BToA2 Multidimentional Transform";
1080
		case icSigCalibrationDateTimeTag:
1081
			return "Calibration Date & Time";
1082
		case icSigCharTargetTag:
1083
			return "Characterization Target";
1084
		case icSigCopyrightTag:
1085
			return "Copyright";
1086
		case icSigCrdInfoTag:
1087
			return "CRD Info";
1088
		case icSigDeviceMfgDescTag:
1089
			return "Device Manufacturer Description";
1090
		case icSigDeviceModelDescTag:
1091
			return "Device Model Description";
1092
		case icSigGamutTag:
1093
			return "Gamut";
1094
		case icSigGrayTRCTag:
1095
			return "Gray Tone Reproduction Curve";
1096
		case icSigGreenColorantTag:
1097
			return "Green Colorant";
1098
		case icSigGreenTRCTag:
1099
			return "Green Tone Reproduction Curve";
1100
		case icSigLuminanceTag:
1101
			return "Luminance";
1102
		case icSigMeasurementTag:
1103
			return "Measurement";
1104
		case icSigMediaBlackPointTag:
1105
			return "Media Black Point";
1106
		case icSigMediaWhitePointTag:
1107
			return "Media White Point";
1108
		case icSigNamedColorTag:
1109
			return "Named Color";
1110
		case icSigNamedColor2Tag:
1111
			return "Named Color 2";
1112
		case icSigPreview0Tag:
1113
			return "Preview0";
1114
		case icSigPreview1Tag:
1115
			return "Preview1";
1116
		case icSigPreview2Tag:
1117
			return "Preview2";
1118
		case icSigProfileDescriptionTag:
1119
			return "Profile Description";
1120
		case icSigProfileSequenceDescTag:
1121
			return "Profile Sequence";
1122
		case icSigPs2CRD0Tag:
1123
			return "PS Level 2 CRD perceptual";
1124
		case icSigPs2CRD1Tag:
1125
			return "PS Level 2 CRD colorimetric";
1126
		case icSigPs2CRD2Tag:
1127
			return "PS Level 2 CRD saturation";
1128
		case icSigPs2CRD3Tag:
1129
			return "PS Level 2 CRD absolute";
1130
		case icSigPs2CSATag:
1131
			return "PS Level 2 color space array";
1132
		case icSigPs2RenderingIntentTag:
1133
			return "PS Level 2 Rendering Intent";
1134
		case icSigRedColorantTag:
1135
			return "Red Colorant";
1136
		case icSigRedTRCTag:
1137
			return "Red Tone Reproduction Curve";
1138
		case icSigScreeningDescTag:
1139
			return "Screening Description";
1140
		case icSigScreeningTag:
1141
			return "Screening Attributes";
1142
		case icSigTechnologyTag:
1143
			return "Device Technology";
1144
		case icSigUcrBgTag:
1145
			return "Under Color Removal & Black Generation";
1146
		case icSigVideoCardGammaTag:
1147
			return "Video Card Gamma Curve";
1148
		case icSigViewingCondDescTag:
1149
			return "Viewing Condition Description";
1150
		case icSigViewingConditionsTag:
1151
			return "Viewing Condition Paramaters";
1152
		default:
1153
			sprintf(buf,"Unrecognized - %s",tag2str(sig));
1154
			return buf;
1155
	}
1156
}
1157
 
1158
/* technology signature descriptions */
1159
static const char *string_TechnologySignature(icTechnologySignature sig) {
1160
	static char buf[80];
1161
	switch(sig) {
1162
		case icSigDigitalCamera:
1163
			return "Digital Camera";
1164
		case icSigFilmScanner:
1165
			return "Film Scanner";
1166
		case icSigReflectiveScanner:
1167
			return "Reflective Scanner";
1168
		case icSigInkJetPrinter:
1169
			return "InkJet Printer";
1170
		case icSigThermalWaxPrinter:
1171
			return "Thermal WaxPrinter";
1172
		case icSigElectrophotographicPrinter:
1173
			return "Electrophotographic Printer";
1174
		case icSigElectrostaticPrinter:
1175
			return "Electrostatic Printer";
1176
		case icSigDyeSublimationPrinter:
1177
			return "DyeSublimation Printer";
1178
		case icSigPhotographicPaperPrinter:
1179
			return "Photographic Paper Printer";
1180
		case icSigFilmWriter:
1181
			return "Film Writer";
1182
		case icSigVideoMonitor:
1183
			return "Video Monitor";
1184
		case icSigVideoCamera:
1185
			return "Video Camera";
1186
		case icSigProjectionTelevision:
1187
			return "Projection Television";
1188
		case icSigCRTDisplay:
1189
			return "Cathode Ray Tube Display";
1190
		case icSigPMDisplay:
1191
			return "Passive Matrix Display";
1192
		case icSigAMDisplay:
1193
			return "Active Matrix Display";
1194
		case icSigPhotoCD:
1195
			return "Photo CD";
1196
		case icSigPhotoImageSetter:
1197
			return "Photo ImageSetter";
1198
		case icSigGravure:
1199
			return "Gravure";
1200
		case icSigOffsetLithography:
1201
			return "Offset Lithography";
1202
		case icSigSilkscreen:
1203
			return "Silkscreen";
1204
		case icSigFlexography:
1205
			return "Flexography";
1206
		default:
1207
			sprintf(buf,"Unrecognized - %s",tag2str(sig));
1208
			return buf;
1209
	}
1210
}
1211
 
1212
/* type signatures */
1213
static const char *string_TypeSignature(icTagTypeSignature sig) {
1214
	static char buf[80];
1215
	switch(sig) {
1216
		case icSigCurveType:
1217
			return "Curve";
1218
		case icSigDataType:
1219
			return "Data";
1220
		case icSigDateTimeType:
1221
			return "DateTime";
1222
		case icSigLut16Type:
1223
			return "Lut16";
1224
		case icSigLut8Type:
1225
			return "Lut8";
1226
		case icSigMeasurementType:
1227
			return "Measurement";
1228
		case icSigNamedColorType:
1229
			return "Named Color";
1230
		case icSigProfileSequenceDescType:
1231
			return "Profile Sequence Desc";
1232
		case icSigS15Fixed16ArrayType:
1233
			return "S15Fixed16 Array";
1234
		case icSigScreeningType:
1235
			return "Screening";
1236
		case icSigSignatureType:
1237
			return "Signature";
1238
		case icSigTextType:
1239
			return "Text";
1240
		case icSigTextDescriptionType:
1241
			return "Text Description";
1242
		case icSigU16Fixed16ArrayType:
1243
			return "U16Fixed16 Array";
1244
		case icSigUcrBgType:
1245
			return "Under Color Removal & Black Generation";
1246
		case icSigUInt16ArrayType:
1247
			return "UInt16 Array";
1248
		case icSigUInt32ArrayType:
1249
			return "UInt32 Array";
1250
		case icSigUInt64ArrayType:
1251
			return "UInt64 Array";
1252
		case icSigUInt8ArrayType:
1253
			return "UInt8 Array";
1254
		case icSigVideoCardGammaType:
1255
			return "Video Card Gamma";
1256
		case icSigViewingConditionsType:
1257
			return "Viewing Conditions";
1258
		case icSigXYZType:
1259
			return "XYZ (Array?)";
1260
		case icSigNamedColor2Type:
1261
			return "Named Color 2";
1262
		case icSigCrdInfoType:
1263
			return "CRD Info";
1264
		default:
1265
			sprintf(buf,"Unrecognized - %s",tag2str(sig));
1266
			return buf;
1267
	}
1268
}
1269
 
1270
/* Color Space Signatures */
1271
static const char *string_ColorSpaceSignature(icColorSpaceSignature sig) {
1272
	static char buf[80];
1273
	switch(sig) {
1274
		case icSigXYZData:
1275
			return "XYZ";
1276
		case icSigLabData:
1277
			return "Lab";
1278
		case icSigLuvData:
1279
			return "Luv";
1280
		case icSigYCbCrData:
1281
			return "YCbCr";
1282
		case icSigYxyData:
1283
			return "Yxy";
1284
		case icSigRgbData:
1285
			return "RGB";
1286
		case icSigGrayData:
1287
			return "Gray";
1288
		case icSigHsvData:
1289
			return "HSV";
1290
		case icSigHlsData:
1291
			return "HLS";
1292
		case icSigCmykData:
1293
			return "CMYK";
1294
		case icSigCmyData:
1295
			return "CMY";
1296
		case icSig2colorData:
1297
			return "2 Color";
1298
		case icSig3colorData:
1299
			return "3 Color";
1300
		case icSig4colorData:
1301
			return "4 Color";
1302
		case icSig5colorData:
1303
		case icSigMch5Data:
1304
			return "5 Color";
1305
		case icSig6colorData:
1306
		case icSigMch6Data:
1307
			return "6 Color";
1308
		case icSig7colorData:
1309
		case icSigMch7Data:
1310
			return "7 Color";
1311
		case icSig8colorData:
1312
		case icSigMch8Data:
1313
			return "8 Color";
1314
		case icSig9colorData:
1315
			return "9 Color";
1316
		case icSig10colorData:
1317
			return "10 Color";
1318
		case icSig11colorData:
1319
			return "11 Color";
1320
		case icSig12colorData:
1321
			return "12 Color";
1322
		case icSig13colorData:
1323
			return "13 Color";
1324
		case icSig14colorData:
1325
			return "14 Color";
1326
		case icSig15colorData:
1327
			return "15 Color";
1328
		default:
1329
			sprintf(buf,"Unrecognized - %s",tag2str(sig));
1330
			return buf;
1331
	}
1332
}
1333
 
1334
#ifdef NEVER
1335
/* Public version of above */
1336
char *ColorSpaceSignature2str(icColorSpaceSignature sig) {
1337
	return string_ColorSpaceSignature(sig);
1338
}
1339
#endif
1340
 
1341
 
1342
/* profileClass enumerations */
1343
static const char *string_ProfileClassSignature(icProfileClassSignature sig) {
1344
	static char buf[80];
1345
	switch(sig) {
1346
		case icSigInputClass:
1347
			return "Input";
1348
		case icSigDisplayClass:
1349
			return "Display";
1350
		case icSigOutputClass:
1351
			return "Output";
1352
		case icSigLinkClass:
1353
			return "Link";
1354
		case icSigAbstractClass:
1355
			return "Abstract";
1356
		case icSigColorSpaceClass:
1357
			return "Color Space";
1358
		case icSigNamedColorClass:
1359
			return "Named Color";
1360
		default:
1361
			sprintf(buf,"Unrecognized - %s",tag2str(sig));
1362
			return buf;
1363
	}
1364
}
1365
 
1366
/* Platform Signatures */
1367
static const char *string_PlatformSignature(icPlatformSignature sig) {
1368
	static char buf[80];
1369
	switch(sig) {
1370
		case icSigMacintosh:
1371
			return "Macintosh";
1372
		case icSigMicrosoft:
1373
			return "Microsoft";
1374
		case icSigSolaris:
1375
			return "Solaris";
1376
		case icSigSGI:
1377
			return "SGI";
1378
		case icSigTaligent:
1379
			return "Taligent";
1380
		default:
1381
			sprintf(buf,"Unrecognized - %s",tag2str(sig));
1382
			return buf;
1383
	}
1384
}
1385
 
1386
/* Measurement Geometry, used in the measurmentType tag */
1387
static const char *string_MeasurementGeometry(icMeasurementGeometry sig) {
1388
	static char buf[30];
1389
	switch(sig) {
1390
		case icGeometryUnknown:
1391
			return "Unknown";
1392
		case icGeometry045or450:
1393
			return "0/45 or 45/0";
1394
		case icGeometry0dord0:
1395
			return "0/d or d/0";
1396
		default:
1397
			sprintf(buf,"Unrecognized - 0x%x",sig);
1398
			return buf;
1399
	}
1400
}
1401
 
1402
/* Rendering Intents, used in the profile header */
1403
static const char *string_RenderingIntent(icRenderingIntent sig) {
1404
	static char buf[30];
1405
	switch(sig) {
1406
		case icPerceptual:
1407
			return "Perceptual";
1408
		case icRelativeColorimetric:
1409
	    		return "Relative Colorimetric";
1410
		case icSaturation:
1411
	    		return "Saturation";
1412
		case icAbsoluteColorimetric:
1413
	    		return "Absolute Colorimetric";
1414
		default:
1415
			sprintf(buf,"Unrecognized - 0x%x",sig);
1416
			return buf;
1417
	}
1418
}
1419
 
1420
/* Different Spot Shapes currently defined, used for screeningType */
1421
static const char *string_SpotShape(icSpotShape sig) {
1422
	static char buf[30];
1423
	switch(sig) {
1424
		case icSpotShapeUnknown:
1425
			return "Unknown";
1426
		case icSpotShapePrinterDefault:
1427
			return "Printer Default";
1428
		case icSpotShapeRound:
1429
			return "Round";
1430
		case icSpotShapeDiamond:
1431
			return "Diamond";
1432
		case icSpotShapeEllipse:
1433
			return "Ellipse";
1434
		case icSpotShapeLine:
1435
			return "Line";
1436
		case icSpotShapeSquare:
1437
			return "Square";
1438
		case icSpotShapeCross:
1439
			return "Cross";
1440
		default:
1441
			sprintf(buf,"Unrecognized - 0x%x",sig);
1442
			return buf;
1443
	}
1444
}
1445
 
1446
/* Standard Observer, used in the measurmentType tag */
1447
static const char *string_StandardObserver(icStandardObserver sig) {
1448
	static char buf[30];
1449
	switch(sig) {
1450
		case icStdObsUnknown:
1451
			return "Unknown";
1452
		case icStdObs1931TwoDegrees:
1453
			return "1931 Two Degrees";
1454
		case icStdObs1964TenDegrees:
1455
			return "1964 Ten Degrees";
1456
		default:
1457
			sprintf(buf,"Unrecognized - 0x%x",sig);
1458
			return buf;
1459
	}
1460
}
1461
 
1462
/* Pre-defined illuminants, used in measurement and viewing conditions type */
1463
static const char *string_Illuminant(icIlluminant sig) {
1464
	static char buf[30];
1465
	switch(sig) {
1466
		case icIlluminantUnknown:
1467
			return "Unknown";
1468
		case icIlluminantD50:
1469
			return "D50";
1470
		case icIlluminantD65:
1471
			return "D65";
1472
		case icIlluminantD93:
1473
			return "D93";
1474
		case icIlluminantF2:
1475
			return "F2";
1476
		case icIlluminantD55:
1477
			return "D55";
1478
		case icIlluminantA:
1479
			return "A";
1480
		case icIlluminantEquiPowerE:
1481
			return "Equi-Power(E)";
1482
		case icIlluminantF8:
1483
			return "F8";
1484
		default:
1485
			sprintf(buf,"Unrecognized - 0x%x",sig);
1486
			return buf;
1487
	}
1488
}
1489
 
1490
/* Return a text abreviation of a color lookup algorithm */
1491
static const char *string_LuAlg(icmLuAlgType alg) {
1492
	static char buf[80];
1493
 
1494
	switch(alg) {
1495
    	case icmMonoFwdType:
1496
			return "MonoFwd";
1497
    	case icmMonoBwdType:
1498
			return "MonoBwd";
1499
    	case icmMatrixFwdType:
1500
			return "MatrixFwd";
1501
    	case icmMatrixBwdType:
1502
			return "MatrixBwd";
1503
    	case icmLutType:
1504
			return "Lut";
1505
	default:
1506
		sprintf(buf,"Unrecognized - %d",alg);
1507
		return buf;
1508
	}
1509
}
1510
 
1511
/* Return a string description of the given enumeration value */
1512
/* Public: */
1513
const char *icm2str(icmEnumType etype, int enumval) {
1514
 
1515
	switch(etype) {
1516
	    case icmScreenEncodings:
1517
			return string_ScreenEncodings((unsigned long) enumval);
1518
	    case icmDeviceAttributes:
1519
			return string_DeviceAttributes((unsigned long) enumval);
1520
		case icmProfileHeaderFlags:
1521
			return string_ProfileHeaderFlags((unsigned long) enumval);
1522
		case icmAsciiOrBinaryData:
1523
			return string_AsciiOrBinaryData((unsigned long) enumval);
1524
		case icmTagSignature:
1525
			return string_TagSignature((icTagSignature) enumval);
1526
		case icmTechnologySignature:
1527
			return string_TechnologySignature((icTechnologySignature) enumval);
1528
		case icmTypeSignature:
1529
			return string_TypeSignature((icTagTypeSignature) enumval);
1530
		case icmColorSpaceSignature:
1531
			return string_ColorSpaceSignature((icColorSpaceSignature) enumval);
1532
		case icmProfileClassSignaure:
1533
			return string_ProfileClassSignature((icProfileClassSignature) enumval);
1534
		case icmPlatformSignature:
1535
			return string_PlatformSignature((icPlatformSignature) enumval);
1536
		case icmMeasurementGeometry:
1537
			return string_MeasurementGeometry((icMeasurementGeometry) enumval);
1538
		case icmRenderingIntent:
1539
			return string_RenderingIntent((icRenderingIntent) enumval);
1540
		case icmSpotShape:
1541
			return string_SpotShape((icSpotShape) enumval);
1542
		case icmStandardObserver:
1543
			return string_StandardObserver((icStandardObserver) enumval);
1544
		case icmIlluminant:
1545
			return string_Illuminant((icIlluminant) enumval);
1546
		case icmLuAlg:
1547
			return string_LuAlg((icmLuAlgType) enumval);
1548
		default:
1549
			return "enum2str got unknown type";
1550
	}
1551
}
1552
 
1553
/* ========================================================== */
1554
/* Object I/O routines                                        */
1555
/* ========================================================== */
1556
/* icmUInt8Array object */
1557
 
1558
/* Return the number of bytes needed to write this tag */
1559
static unsigned int icmUInt8Array_get_size(
1560
	icmBase *pp
1561
) {
1562
	icmUInt8Array *p = (icmUInt8Array *)pp;
1563
	unsigned int len = 0;
1564
	len += 8;			/* 8 bytes for tag and padding */
1565
	len += p->size * 1;	/* 1 byte for each UInt8 */
1566
	return len;
1567
}
1568
 
1569
/* read the object, return 0 on success, error code on fail */
1570
static int icmUInt8Array_read(
1571
	icmBase *pp,
1572
	unsigned long len,		/* tag length */
1573
	unsigned long of		/* start offset within file */
1574
) {
1575
	icmUInt8Array *p = (icmUInt8Array *)pp;
1576
	icc *icp = p->icp;
1577
	int rv = 0;
1578
	unsigned long i, size;
1579
	char *bp, *buf;
1580
 
1581
	if (len < 8) {
1582
		sprintf(icp->err,"icmUInt8Array_read: Tag too small to be legal");
1583
		return icp->errc = 1;
1584
	}
1585
 
1586
	/* Allocate a file read buffer */
1587
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1588
		sprintf(icp->err,"icmUInt8Array_read: malloc() failed");
1589
		return icp->errc = 2;
1590
	}
1591
	bp = buf;
1592
 
1593
	/* Read portion of file into buffer */
1594
	if (   icp->fp->seek(icp->fp, of) != 0
1595
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
1596
		sprintf(icp->err,"icmUInt8Array_read: fseek() or fread() failed");
1597
		icp->al->free(icp->al, buf);
1598
		return icp->errc = 1;
1599
	}
1600
	p->size = size = (len - 8)/1;		/* Number of elements in the array */
1601
 
1602
	if ((rv = p->allocate((icmBase *)p)) != 0) {
1603
		icp->al->free(icp->al, buf);
1604
		return rv;
1605
	}
1606
 
1607
	/* Read type descriptor from the buffer */
1608
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
1609
		icp->al->free(icp->al, buf);
1610
		sprintf(icp->err,"icmUInt8Array_read: Wrong tag type for icmUInt8Array");
1611
		return icp->errc = 1;
1612
	}
1613
	bp += 8;	/* Skip padding */
1614
 
1615
	/* Read all the data from the buffer */
1616
	for (i = 0; i < size; i++, bp += 1) {
1617
		p->data[i] = read_UInt8Number(bp);
1618
	}
1619
	icp->al->free(p->icp->al, buf);
1620
	return 0;
1621
}
1622
 
1623
/* Write the contents of the object. Return 0 on sucess, error code on failure */
1624
static int icmUInt8Array_write(
1625
	icmBase *pp,
1626
	unsigned long of			/* File offset to write from */
1627
) {
1628
	icmUInt8Array *p = (icmUInt8Array *)pp;
1629
	icc *icp = p->icp;
1630
	unsigned long i;
1631
	unsigned int len;
1632
	char *bp, *buf;		/* Buffer to write from */
1633
	int rv = 0;
1634
 
1635
	/* Allocate a file write buffer */
1636
	len = p->get_size((icmBase *)p);
1637
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1638
		sprintf(icp->err,"icmUInt8Array_write malloc() failed");
1639
		return icp->errc = 2;
1640
	}
1641
	bp = buf;
1642
 
1643
	/* Write type descriptor to the buffer */
1644
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
1645
		sprintf(icp->err,"icmUInt8Array_write: write_SInt32Number() failed");
1646
		icp->al->free(icp->al, buf);
1647
		return icp->errc = rv;
1648
	}
1649
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
1650
	bp += 8;	/* Skip padding */
1651
 
1652
	/* Write all the data to the buffer */
1653
	for (i = 0; i < p->size; i++, bp += 1) {
1654
		if ((rv = write_UInt8Number(p->data[i],bp)) != 0) {
1655
			sprintf(icp->err,"icmUInt8Array_write: write_UInt8umber() failed");
1656
			icp->al->free(icp->al, buf);
1657
			return icp->errc = rv;
1658
		}
1659
	}
1660
 
1661
	/* Write to the file */
1662
	if (   icp->fp->seek(icp->fp, of) != 0
1663
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
1664
		sprintf(icp->err,"icmUInt8Array_write fseek() or fwrite() failed");
1665
		icp->al->free(icp->al, buf);
1666
		return icp->errc = 2;
1667
	}
1668
	icp->al->free(icp->al, buf);
1669
	return 0;
1670
}
1671
 
1672
/* Dump a text description of the object */
1673
static void icmUInt8Array_dump(
1674
	icmBase *pp,
1675
	FILE *op,		/* Output to dump to */
1676
	int   verb		/* Verbosity level */
1677
) {
1678
	icmUInt8Array *p = (icmUInt8Array *)pp;
1679
	if (verb <= 0)
1680
		return;
1681
 
1682
	fprintf(op,"UInt8Array:\n");
1683
	fprintf(op,"  No. elements = %lu\n",p->size);
1684
	if (verb >= 2) {
1685
		unsigned long i;
1686
		for (i = 0; i < p->size; i++)
1687
			fprintf(op,"    %lu:  %u\n",i,p->data[i]);
1688
	}
1689
}
1690
 
1691
/* Allocate variable sized data elements */
1692
static int icmUInt8Array_allocate(
1693
	icmBase *pp
1694
) {
1695
	icmUInt8Array *p = (icmUInt8Array *)pp;
1696
	icc *icp = p->icp;
1697
 
1698
	if (p->size != p->_size) {
1699
		if (p->data != NULL)
1700
			icp->al->free(icp->al, p->data);
1701
		if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) {
1702
			sprintf(icp->err,"icmUInt8Array_alloc: malloc() of icmUInt8Array data failed");
1703
			return icp->errc = 2;
1704
		}
1705
		p->_size = p->size;
1706
	}
1707
	return 0;
1708
}
1709
 
1710
/* Free all storage in the object */
1711
static void icmUInt8Array_delete(
1712
	icmBase *pp
1713
) {
1714
	icmUInt8Array *p = (icmUInt8Array *)pp;
1715
	icc *icp = p->icp;
1716
 
1717
	if (p->data != NULL)
1718
		icp->al->free(icp->al, p->data);
1719
	icp->al->free(icp->al, p);
1720
}
1721
 
1722
/* Create an empty object. Return null on error */
1723
static icmBase *new_icmUInt8Array(
1724
	icc *icp
1725
) {
1726
	icmUInt8Array *p;
1727
	if ((p = (icmUInt8Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt8Array))) == NULL)
1728
		return NULL;
1729
	p->ttype    = icSigUInt8ArrayType;
1730
	p->refcount = 1;
1731
	p->get_size = icmUInt8Array_get_size;
1732
	p->read     = icmUInt8Array_read;
1733
	p->write    = icmUInt8Array_write;
1734
	p->dump     = icmUInt8Array_dump;
1735
	p->allocate = icmUInt8Array_allocate;
1736
	p->del      = icmUInt8Array_delete;
1737
	p->icp      = icp;
1738
 
1739
	return (icmBase *)p;
1740
}
1741
 
1742
/* ---------------------------------------------------------- */
1743
/* icmUInt16Array object */
1744
 
1745
/* Return the number of bytes needed to write this tag */
1746
static unsigned int icmUInt16Array_get_size(
1747
	icmBase *pp
1748
) {
1749
	icmUInt16Array *p = (icmUInt16Array *)pp;
1750
	unsigned int len = 0;
1751
	len += 8;			/* 8 bytes for tag and padding */
1752
	len += p->size * 2;	/* 2 bytes for each UInt16 */
1753
	return len;
1754
}
1755
 
1756
/* read the object, return 0 on success, error code on fail */
1757
static int icmUInt16Array_read(
1758
	icmBase *pp,
1759
	unsigned long len,		/* tag length */
1760
	unsigned long of		/* start offset within file */
1761
) {
1762
	icmUInt16Array *p = (icmUInt16Array *)pp;
1763
	icc *icp = p->icp;
1764
	int rv = 0;
1765
	unsigned long i, size;
1766
	char *bp, *buf;
1767
 
1768
	if (len < 8) {
1769
		sprintf(icp->err,"icmUInt16Array_read: Tag too small to be legal");
1770
		return icp->errc = 1;
1771
	}
1772
 
1773
	/* Allocate a file read buffer */
1774
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1775
		sprintf(icp->err,"icmUInt16Array_read: malloc() failed");
1776
		return icp->errc = 2;
1777
	}
1778
	bp = buf;
1779
 
1780
	/* Read portion of file into buffer */
1781
	if (   icp->fp->seek(icp->fp, of) != 0
1782
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
1783
		sprintf(icp->err,"icmUInt16Array_read: fseek() or fread() failed");
1784
		icp->al->free(icp->al, buf);
1785
		return icp->errc = 1;
1786
	}
1787
	p->size = size = (len - 8)/2;		/* Number of elements in the array */
1788
 
1789
	if ((rv = p->allocate((icmBase *)p)) != 0) {
1790
		icp->al->free(icp->al, buf);
1791
		return rv;
1792
	}
1793
 
1794
	/* Read type descriptor from the buffer */
1795
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
1796
		sprintf(icp->err,"icmUInt16Array_read: Wrong tag type for icmUInt16Array");
1797
		icp->al->free(icp->al, buf);
1798
		return icp->errc = 1;
1799
	}
1800
	bp += 8;	/* Skip padding */
1801
 
1802
	/* Read all the data from the buffer */
1803
	for (i = 0; i < size; i++, bp += 2) {
1804
		p->data[i] = read_UInt16Number(bp);
1805
	}
1806
	icp->al->free(icp->al, buf);
1807
	return 0;
1808
}
1809
 
1810
/* Write the contents of the object. Return 0 on sucess, error code on failure */
1811
static int icmUInt16Array_write(
1812
	icmBase *pp,
1813
	unsigned long of			/* File offset to write from */
1814
) {
1815
	icmUInt16Array *p = (icmUInt16Array *)pp;
1816
	icc *icp = p->icp;
1817
	unsigned long i;
1818
	unsigned int len;
1819
	char *bp, *buf;		/* Buffer to write from */
1820
	int rv = 0;
1821
 
1822
	/* Allocate a file write buffer */
1823
	len = p->get_size((icmBase *)p);
1824
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1825
		sprintf(icp->err,"icmUInt16Array_write malloc() failed");
1826
		return icp->errc = 2;
1827
	}
1828
	bp = buf;
1829
 
1830
	/* Write type descriptor to the buffer */
1831
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
1832
		sprintf(icp->err,"icmUInt16Array_write: write_SInt32Number() failed");
1833
		icp->al->free(icp->al, buf);
1834
		return icp->errc = rv;
1835
	}
1836
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
1837
 
1838
	/* Write all the data to the buffer */
1839
	bp += 8;	/* Skip padding */
1840
	for (i = 0; i < p->size; i++, bp += 2) {
1841
		if ((rv = write_UInt16Number(p->data[i],bp)) != 0) {
1842
			sprintf(icp->err,"icmUInt16Array_write: write_UInt16umber() failed");
1843
			icp->al->free(icp->al, buf);
1844
			return icp->errc = rv;
1845
		}
1846
	}
1847
 
1848
	/* Write to the file */
1849
	if (   icp->fp->seek(icp->fp, of) != 0
1850
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
1851
		sprintf(icp->err,"icmUInt16Array_write fseek() or fwrite() failed");
1852
		icp->al->free(icp->al, buf);
1853
		return icp->errc = 2;
1854
	}
1855
	icp->al->free(icp->al, buf);
1856
	return 0;
1857
}
1858
 
1859
/* Dump a text description of the object */
1860
static void icmUInt16Array_dump(
1861
	icmBase *pp,
1862
	FILE *op,		/* Output to dump to */
1863
	int   verb		/* Verbosity level */
1864
) {
1865
	icmUInt16Array *p = (icmUInt16Array *)pp;
1866
	if (verb <= 0)
1867
		return;
1868
 
1869
	fprintf(op,"UInt16Array:\n");
1870
	fprintf(op,"  No. elements = %lu\n",p->size);
1871
	if (verb >= 2) {
1872
		unsigned long i;
1873
		for (i = 0; i < p->size; i++)
1874
			fprintf(op,"    %lu:  %u\n",i,p->data[i]);
1875
	}
1876
}
1877
 
1878
/* Allocate variable sized data elements */
1879
static int icmUInt16Array_allocate(
1880
	icmBase *pp
1881
) {
1882
	icmUInt16Array *p = (icmUInt16Array *)pp;
1883
	icc *icp = p->icp;
1884
 
1885
	if (p->size != p->_size) {
1886
		if (p->data != NULL)
1887
			icp->al->free(icp->al, p->data);
1888
		if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) {
1889
			sprintf(icp->err,"icmUInt16Array_alloc: malloc() of icmUInt16Array data failed");
1890
			return icp->errc = 2;
1891
		}
1892
		p->_size = p->size;
1893
	}
1894
	return 0;
1895
}
1896
 
1897
/* Free all storage in the object */
1898
static void icmUInt16Array_delete(
1899
	icmBase *pp
1900
) {
1901
	icmUInt16Array *p = (icmUInt16Array *)pp;
1902
	icc *icp = p->icp;
1903
 
1904
	if (p->data != NULL)
1905
		icp->al->free(icp->al, p->data);
1906
	icp->al->free(icp->al, p);
1907
}
1908
 
1909
/* Create an empty object. Return null on error */
1910
static icmBase *new_icmUInt16Array(
1911
	icc *icp
1912
) {
1913
	icmUInt16Array *p;
1914
	if ((p = (icmUInt16Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt16Array))) == NULL)
1915
		return NULL;
1916
	p->ttype    = icSigUInt16ArrayType;
1917
	p->refcount = 1;
1918
	p->get_size = icmUInt16Array_get_size;
1919
	p->read     = icmUInt16Array_read;
1920
	p->write    = icmUInt16Array_write;
1921
	p->dump     = icmUInt16Array_dump;
1922
	p->allocate = icmUInt16Array_allocate;
1923
	p->del      = icmUInt16Array_delete;
1924
	p->icp      = icp;
1925
 
1926
	return (icmBase *)p;
1927
}
1928
 
1929
/* ---------------------------------------------------------- */
1930
/* icmUInt32Array object */
1931
 
1932
/* Return the number of bytes needed to write this tag */
1933
static unsigned int icmUInt32Array_get_size(
1934
	icmBase *pp
1935
) {
1936
	icmUInt32Array *p = (icmUInt32Array *)pp;
1937
	unsigned int len = 0;
1938
	len += 8;			/* 8 bytes for tag and padding */
1939
	len += p->size * 4;	/* 4 bytes for each UInt32 */
1940
	return len;
1941
}
1942
 
1943
/* read the object, return 0 on success, error code on fail */
1944
static int icmUInt32Array_read(
1945
	icmBase *pp,
1946
	unsigned long len,		/* tag length */
1947
	unsigned long of		/* start offset within file */
1948
) {
1949
	icmUInt32Array *p = (icmUInt32Array *)pp;
1950
	icc *icp = p->icp;
1951
	int rv = 0;
1952
	unsigned long i, size;
1953
	char *bp, *buf;
1954
 
1955
	if (len < 8) {
1956
		sprintf(icp->err,"icmUInt32Array_read: Tag too small to be legal");
1957
		return icp->errc = 1;
1958
	}
1959
 
1960
	/* Allocate a file read buffer */
1961
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
1962
		sprintf(icp->err,"icmUInt32Array_read: malloc() failed");
1963
		return icp->errc = 2;
1964
	}
1965
	bp = buf;
1966
 
1967
	/* Read portion of file into buffer */
1968
	if (   icp->fp->seek(icp->fp, of) != 0
1969
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
1970
		sprintf(icp->err,"icmUInt32Array_read: fseek() or fread() failed");
1971
		icp->al->free(icp->al, buf);
1972
		return icp->errc = 1;
1973
	}
1974
	p->size = size = (len - 8)/4;		/* Number of elements in the array */
1975
 
1976
	if ((rv = p->allocate((icmBase *)p)) != 0) {
1977
		icp->al->free(icp->al, buf);
1978
		return rv;
1979
	}
1980
 
1981
	/* Read type descriptor from the buffer */
1982
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
1983
		sprintf(icp->err,"icmUInt32Array_read: Wrong tag type for icmUInt32Array");
1984
		icp->al->free(icp->al, buf);
1985
		return icp->errc = 1;
1986
	}
1987
	bp += 8;	/* Skip padding */
1988
 
1989
	/* Read all the data from the buffer */
1990
	for (i = 0; i < size; i++, bp += 4) {
1991
		p->data[i] = read_UInt32Number(bp);
1992
	}
1993
	icp->al->free(icp->al, buf);
1994
	return 0;
1995
}
1996
 
1997
/* Write the contents of the object. Return 0 on sucess, error code on failure */
1998
static int icmUInt32Array_write(
1999
	icmBase *pp,
2000
	unsigned long of			/* File offset to write from */
2001
) {
2002
	icmUInt32Array *p = (icmUInt32Array *)pp;
2003
	icc *icp = p->icp;
2004
	unsigned long i;
2005
	unsigned int len;
2006
	char *bp, *buf;		/* Buffer to write from */
2007
	int rv = 0;
2008
 
2009
	/* Allocate a file write buffer */
2010
	len = p->get_size((icmBase *)p);
2011
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2012
		sprintf(icp->err,"icmUInt32Array_write malloc() failed");
2013
		return icp->errc = 2;
2014
	}
2015
	bp = buf;
2016
 
2017
	/* Write type descriptor to the buffer */
2018
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2019
		sprintf(icp->err,"icmUInt32Array_write: write_SInt32Number() failed");
2020
		icp->al->free(icp->al, buf);
2021
		return icp->errc = rv;
2022
	}
2023
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
2024
 
2025
	/* Write all the data to the buffer */
2026
	bp += 8;	/* Skip padding */
2027
	for (i = 0; i < p->size; i++, bp += 4) {
2028
		if ((rv = write_UInt32Number(p->data[i],bp)) != 0) {
2029
			sprintf(icp->err,"icmUInt32Array_write: write_UInt32umber() failed");
2030
			icp->al->free(icp->al, buf);
2031
			return icp->errc = rv;
2032
		}
2033
	}
2034
 
2035
	/* Write to the file */
2036
	if (   icp->fp->seek(icp->fp, of) != 0
2037
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
2038
		sprintf(icp->err,"icmUInt32Array_write fseek() or fwrite() failed");
2039
		icp->al->free(icp->al, buf);
2040
		return icp->errc = 2;
2041
	}
2042
	icp->al->free(icp->al, buf);
2043
	return 0;
2044
}
2045
 
2046
/* Dump a text description of the object */
2047
static void icmUInt32Array_dump(
2048
	icmBase *pp,
2049
	FILE *op,		/* Output to dump to */
2050
	int   verb		/* Verbosity level */
2051
) {
2052
	icmUInt32Array *p = (icmUInt32Array *)pp;
2053
	if (verb <= 0)
2054
		return;
2055
 
2056
	fprintf(op,"UInt32Array:\n");
2057
	fprintf(op,"  No. elements = %lu\n",p->size);
2058
	if (verb >= 2) {
2059
		unsigned long i;
2060
		for (i = 0; i < p->size; i++)
2061
			fprintf(op,"    %lu:  %u\n",i,p->data[i]);
2062
	}
2063
}
2064
 
2065
/* Allocate variable sized data elements */
2066
static int icmUInt32Array_allocate(
2067
	icmBase *pp
2068
) {
2069
	icmUInt32Array *p = (icmUInt32Array *)pp;
2070
	icc *icp = p->icp;
2071
 
2072
	if (p->size != p->_size) {
2073
		if (p->data != NULL)
2074
			icp->al->free(icp->al, p->data);
2075
		if ((p->data = (unsigned int *) icp->al->malloc(icp->al, p->size * sizeof(unsigned int))) == NULL) {
2076
			sprintf(icp->err,"icmUInt32Array_alloc: malloc() of icmUInt32Array data failed");
2077
			return icp->errc = 2;
2078
		}
2079
		p->_size = p->size;
2080
	}
2081
	return 0;
2082
}
2083
 
2084
/* Free all storage in the object */
2085
static void icmUInt32Array_delete(
2086
	icmBase *pp
2087
) {
2088
	icmUInt32Array *p = (icmUInt32Array *)pp;
2089
	icc *icp = p->icp;
2090
 
2091
	if (p->data != NULL)
2092
		icp->al->free(icp->al, p->data);
2093
	icp->al->free(icp->al, p);
2094
}
2095
 
2096
/* Create an empty object. Return null on error */
2097
static icmBase *new_icmUInt32Array(
2098
	icc *icp
2099
) {
2100
	icmUInt32Array *p;
2101
	if ((p = (icmUInt32Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt32Array))) == NULL)
2102
		return NULL;
2103
	p->ttype    = icSigUInt32ArrayType;
2104
	p->refcount = 1;
2105
	p->get_size = icmUInt32Array_get_size;
2106
	p->read     = icmUInt32Array_read;
2107
	p->write    = icmUInt32Array_write;
2108
	p->dump     = icmUInt32Array_dump;
2109
	p->allocate = icmUInt32Array_allocate;
2110
	p->del      = icmUInt32Array_delete;
2111
	p->icp      = icp;
2112
 
2113
	return (icmBase *)p;
2114
}
2115
 
2116
/* ---------------------------------------------------------- */
2117
/* icmUInt64Array object */
2118
 
2119
/* Return the number of bytes needed to write this tag */
2120
static unsigned int icmUInt64Array_get_size(
2121
	icmBase *pp
2122
) {
2123
	icmUInt64Array *p = (icmUInt64Array *)pp;
2124
	unsigned int len = 0;
2125
	len += 8;			/* 8 bytes for tag and padding */
2126
	len += p->size * 8;	/* 8 bytes for each UInt64 */
2127
	return len;
2128
}
2129
 
2130
/* read the object, return 0 on success, error code on fail */
2131
static int icmUInt64Array_read(
2132
	icmBase *pp,
2133
	unsigned long len,		/* tag length */
2134
	unsigned long of		/* start offset within file */
2135
) {
2136
	icmUInt64Array *p = (icmUInt64Array *)pp;
2137
	icc *icp = p->icp;
2138
	int rv = 0;
2139
	unsigned long i, size;
2140
	char *bp, *buf;
2141
 
2142
	if (len < 8) {
2143
		sprintf(icp->err,"icmUInt64Array_read: Tag too small to be legal");
2144
		return icp->errc = 1;
2145
	}
2146
 
2147
	/* Allocate a file read buffer */
2148
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2149
		sprintf(icp->err,"icmUInt64Array_read: malloc() failed");
2150
		return icp->errc = 2;
2151
	}
2152
	bp = buf;
2153
 
2154
	/* Read portion of file into buffer */
2155
	if (   icp->fp->seek(icp->fp, of) != 0
2156
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
2157
		sprintf(icp->err,"icmUInt64Array_read: fseek() or fread() failed");
2158
		icp->al->free(icp->al, buf);
2159
		return icp->errc = 1;
2160
	}
2161
	p->size = size = (len - 8)/8;		/* Number of elements in the array */
2162
 
2163
	if ((rv = p->allocate((icmBase *)p)) != 0) {
2164
		icp->al->free(icp->al, buf);
2165
		return rv;
2166
	}
2167
 
2168
	/* Read type descriptor from the buffer */
2169
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2170
		sprintf(icp->err,"icmUInt64Array_read: Wrong tag type for icmUInt64Array");
2171
		icp->al->free(icp->al, buf);
2172
		return icp->errc = 1;
2173
	}
2174
	bp += 8;	/* Skip padding */
2175
 
2176
	/* Read all the data from the buffer */
2177
	for (i = 0; i < size; i++, bp += 8) {
2178
		read_UInt64Number(&p->data[i], bp);
2179
	}
2180
	icp->al->free(icp->al, buf);
2181
	return 0;
2182
}
2183
 
2184
/* Write the contents of the object. Return 0 on sucess, error code on failure */
2185
static int icmUInt64Array_write(
2186
	icmBase *pp,
2187
	unsigned long of			/* File offset to write from */
2188
) {
2189
	icmUInt64Array *p = (icmUInt64Array *)pp;
2190
	icc *icp = p->icp;
2191
	unsigned long i;
2192
	unsigned int len;
2193
	char *bp, *buf;		/* Buffer to write from */
2194
	int rv = 0;
2195
 
2196
	/* Allocate a file write buffer */
2197
	len = p->get_size((icmBase *)p);
2198
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2199
		sprintf(icp->err,"icmUInt64Array_write malloc() failed");
2200
		return icp->errc = 2;
2201
	}
2202
	bp = buf;
2203
 
2204
	/* Write type descriptor to the buffer */
2205
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2206
		sprintf(icp->err,"icmUInt64Array_write: write_SInt32Number() failed");
2207
		icp->al->free(icp->al, buf);
2208
		return icp->errc = rv;
2209
	}
2210
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
2211
 
2212
	/* Write all the data to the buffer */
2213
	bp += 8;	/* Skip padding */
2214
	for (i = 0; i < p->size; i++, bp += 8) {
2215
		if ((rv = write_UInt64Number(&p->data[i],bp)) != 0) {
2216
			sprintf(icp->err,"icmUInt64Array_write: write_UInt64umber() failed");
2217
			icp->al->free(icp->al, buf);
2218
			return icp->errc = rv;
2219
		}
2220
	}
2221
 
2222
	/* Write to the file */
2223
	if (   icp->fp->seek(icp->fp, of) != 0
2224
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
2225
		sprintf(icp->err,"icmUInt64Array_write fseek() or fwrite() failed");
2226
		icp->al->free(icp->al, buf);
2227
		return icp->errc = 2;
2228
	}
2229
	icp->al->free(icp->al, buf);
2230
	return 0;
2231
}
2232
 
2233
/* Dump a text description of the object */
2234
static void icmUInt64Array_dump(
2235
	icmBase *pp,
2236
	FILE *op,		/* Output to dump to */
2237
	int   verb		/* Verbosity level */
2238
) {
2239
	icmUInt64Array *p = (icmUInt64Array *)pp;
2240
	if (verb <= 0)
2241
		return;
2242
 
2243
	fprintf(op,"UInt64Array:\n");
2244
	fprintf(op,"  No. elements = %lu\n",p->size);
2245
	if (verb >= 2) {
2246
		unsigned long i;
2247
		for (i = 0; i < p->size; i++)
2248
			fprintf(op,"    %lu:  h=%lu, l=%lu\n",i,p->data[i].h,p->data[i].l);
2249
	}
2250
}
2251
 
2252
/* Allocate variable sized data elements */
2253
static int icmUInt64Array_allocate(
2254
	icmBase *pp
2255
) {
2256
	icmUInt64Array *p = (icmUInt64Array *)pp;
2257
	icc *icp = p->icp;
2258
 
2259
	if (p->size != p->_size) {
2260
		if (p->data != NULL)
2261
			icp->al->free(icp->al, p->data);
2262
		if ((p->data = (icmUint64 *) icp->al->malloc(icp->al, p->size * sizeof(icmUint64))) == NULL) {
2263
			sprintf(icp->err,"icmUInt64Array_alloc: malloc() of icmUInt64Array data failed");
2264
			return icp->errc = 2;
2265
		}
2266
		p->_size = p->size;
2267
	}
2268
	return 0;
2269
}
2270
 
2271
/* Free all storage in the object */
2272
static void icmUInt64Array_delete(
2273
	icmBase *pp
2274
) {
2275
	icmUInt64Array *p = (icmUInt64Array *)pp;
2276
	icc *icp = p->icp;
2277
 
2278
	if (p->data != NULL)
2279
		icp->al->free(icp->al, p->data);
2280
	icp->al->free(icp->al, p);
2281
}
2282
 
2283
/* Create an empty object. Return null on error */
2284
static icmBase *new_icmUInt64Array(
2285
	icc *icp
2286
) {
2287
	icmUInt64Array *p;
2288
	if ((p = (icmUInt64Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt64Array))) == NULL)
2289
		return NULL;
2290
	p->ttype    = icSigUInt64ArrayType;
2291
	p->refcount = 1;
2292
	p->get_size = icmUInt64Array_get_size;
2293
	p->read     = icmUInt64Array_read;
2294
	p->write    = icmUInt64Array_write;
2295
	p->dump     = icmUInt64Array_dump;
2296
	p->allocate = icmUInt64Array_allocate;
2297
	p->del      = icmUInt64Array_delete;
2298
	p->icp      = icp;
2299
 
2300
	return (icmBase *)p;
2301
}
2302
 
2303
/* ---------------------------------------------------------- */
2304
/* icmU16Fixed16Array object */
2305
 
2306
/* Return the number of bytes needed to write this tag */
2307
static unsigned int icmU16Fixed16Array_get_size(
2308
	icmBase *pp
2309
) {
2310
	icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2311
	unsigned int len = 0;
2312
	len += 8;			/* 8 bytes for tag and padding */
2313
	len += p->size * 4;	/* 4 byte for each U16Fixed16 */
2314
	return len;
2315
}
2316
 
2317
/* read the object, return 0 on success, error code on fail */
2318
static int icmU16Fixed16Array_read(
2319
	icmBase *pp,
2320
	unsigned long len,		/* tag length */
2321
	unsigned long of		/* start offset within file */
2322
) {
2323
	icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2324
	icc *icp = p->icp;
2325
	int rv = 0;
2326
	unsigned long i, size;
2327
	char *bp, *buf;
2328
 
2329
	if (len < 8) {
2330
		sprintf(icp->err,"icmU16Fixed16Array_read: Tag too small to be legal");
2331
		return icp->errc = 1;
2332
	}
2333
 
2334
	/* Allocate a file read buffer */
2335
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2336
		sprintf(icp->err,"icmU16Fixed16Array_read: malloc() failed");
2337
		return icp->errc = 2;
2338
	}
2339
	bp = buf;
2340
 
2341
	/* Read portion of file into buffer */
2342
	if (   icp->fp->seek(icp->fp, of) != 0
2343
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
2344
		sprintf(icp->err,"icmU16Fixed16Array_read: fseek() or fread() failed");
2345
		icp->al->free(icp->al, buf);
2346
		return icp->errc = 1;
2347
	}
2348
	p->size = size = (len - 8)/4;		/* Number of elements in the array */
2349
 
2350
	if ((rv = p->allocate((icmBase *)p)) != 0) {
2351
		icp->al->free(icp->al, buf);
2352
		return rv;
2353
	}
2354
 
2355
	/* Read type descriptor from the buffer */
2356
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2357
		sprintf(icp->err,"icmU16Fixed16Array_read: Wrong tag type for icmU16Fixed16Array");
2358
		icp->al->free(icp->al, buf);
2359
		return icp->errc = 1;
2360
	}
2361
	bp += 8;	/* Skip padding */
2362
 
2363
	/* Read all the data from the buffer */
2364
	for (i = 0; i < size; i++, bp += 4) {
2365
		p->data[i] = read_U16Fixed16Number(bp);
2366
	}
2367
	icp->al->free(icp->al, buf);
2368
	return 0;
2369
}
2370
 
2371
/* Write the contents of the object. Return 0 on sucess, error code on failure */
2372
static int icmU16Fixed16Array_write(
2373
	icmBase *pp,
2374
	unsigned long of			/* File offset to write from */
2375
) {
2376
	icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2377
	icc *icp = p->icp;
2378
	unsigned long i;
2379
	unsigned int len;
2380
	char *bp, *buf;		/* Buffer to write from */
2381
	int rv = 0;
2382
 
2383
	/* Allocate a file write buffer */
2384
	len = p->get_size((icmBase *)p);
2385
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2386
		sprintf(icp->err,"icmU16Fixed16Array_write malloc() failed");
2387
		return icp->errc = 2;
2388
	}
2389
	bp = buf;
2390
 
2391
	/* Write type descriptor to the buffer */
2392
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2393
		sprintf(icp->err,"icmU16Fixed16Array_write: write_SInt32Number() failed");
2394
		icp->al->free(icp->al, buf);
2395
		return icp->errc = rv;
2396
	}
2397
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
2398
 
2399
	/* Write all the data to the buffer */
2400
	bp += 8;	/* Skip padding */
2401
	for (i = 0; i < p->size; i++, bp += 4) {
2402
		if ((rv = write_U16Fixed16Number(p->data[i],bp)) != 0) {
2403
			sprintf(icp->err,"icmU16Fixed16Array_write: write_U16Fixed16umber() failed");
2404
			icp->al->free(icp->al, buf);
2405
			return icp->errc = rv;
2406
		}
2407
	}
2408
 
2409
	/* Write to the file */
2410
	if (   icp->fp->seek(icp->fp, of) != 0
2411
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
2412
		sprintf(icp->err,"icmU16Fixed16Array_write fseek() or fwrite() failed");
2413
		icp->al->free(icp->al, buf);
2414
		return icp->errc = 2;
2415
	}
2416
	icp->al->free(icp->al, buf);
2417
	return 0;
2418
}
2419
 
2420
/* Dump a text description of the object */
2421
static void icmU16Fixed16Array_dump(
2422
	icmBase *pp,
2423
	FILE *op,		/* Output to dump to */
2424
	int   verb		/* Verbosity level */
2425
) {
2426
	icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2427
	if (verb <= 0)
2428
		return;
2429
 
2430
	fprintf(op,"U16Fixed16Array:\n");
2431
	fprintf(op,"  No. elements = %lu\n",p->size);
2432
	if (verb >= 2) {
2433
		unsigned long i;
2434
		for (i = 0; i < p->size; i++)
2435
			fprintf(op,"    %lu:  %f\n",i,p->data[i]);
2436
	}
2437
}
2438
 
2439
/* Allocate variable sized data elements */
2440
static int icmU16Fixed16Array_allocate(
2441
	icmBase *pp
2442
) {
2443
	icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2444
	icc *icp = p->icp;
2445
 
2446
	if (p->size != p->_size) {
2447
		if (p->data != NULL)
2448
			icp->al->free(icp->al, p->data);
2449
		if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) {
2450
			sprintf(icp->err,"icmU16Fixed16Array_alloc: malloc() of icmU16Fixed16Array data failed");
2451
			return icp->errc = 2;
2452
		}
2453
		p->_size = p->size;
2454
	}
2455
	return 0;
2456
}
2457
 
2458
/* Free all storage in the object */
2459
static void icmU16Fixed16Array_delete(
2460
	icmBase *pp
2461
) {
2462
	icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
2463
	icc *icp = p->icp;
2464
 
2465
	if (p->data != NULL)
2466
		icp->al->free(icp->al, p->data);
2467
	icp->al->free(icp->al, p);
2468
}
2469
 
2470
/* Create an empty object. Return null on error */
2471
static icmBase *new_icmU16Fixed16Array(
2472
	icc *icp
2473
) {
2474
	icmU16Fixed16Array *p;
2475
	if ((p = (icmU16Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmU16Fixed16Array))) == NULL)
2476
		return NULL;
2477
	p->ttype    = icSigU16Fixed16ArrayType;
2478
	p->refcount = 1;
2479
	p->get_size = icmU16Fixed16Array_get_size;
2480
	p->read     = icmU16Fixed16Array_read;
2481
	p->write    = icmU16Fixed16Array_write;
2482
	p->dump     = icmU16Fixed16Array_dump;
2483
	p->allocate = icmU16Fixed16Array_allocate;
2484
	p->del      = icmU16Fixed16Array_delete;
2485
	p->icp      = icp;
2486
 
2487
	return (icmBase *)p;
2488
}
2489
 
2490
/* ---------------------------------------------------------- */
2491
/* icmS15Fixed16Array object */
2492
 
2493
/* Return the number of bytes needed to write this tag */
2494
static unsigned int icmS15Fixed16Array_get_size(
2495
	icmBase *pp
2496
) {
2497
	icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2498
	unsigned int len = 0;
2499
	len += 8;			/* 8 bytes for tag and padding */
2500
	len += p->size * 4;	/* 4 byte for each S15Fixed16 */
2501
	return len;
2502
}
2503
 
2504
/* read the object, return 0 on success, error code on fail */
2505
static int icmS15Fixed16Array_read(
2506
	icmBase *pp,
2507
	unsigned long len,		/* tag length */
2508
	unsigned long of		/* start offset within file */
2509
) {
2510
	icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2511
	icc *icp = p->icp;
2512
	int rv = 0;
2513
	unsigned long i, size;
2514
	char *bp, *buf;
2515
 
2516
	if (len < 8) {
2517
		sprintf(icp->err,"icmS15Fixed16Array_read: Tag too small to be legal");
2518
		return icp->errc = 1;
2519
	}
2520
 
2521
	/* Allocate a file read buffer */
2522
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2523
		sprintf(icp->err,"icmS15Fixed16Array_read: malloc() failed");
2524
		return icp->errc = 2;
2525
	}
2526
	bp = buf;
2527
 
2528
	/* Read portion of file into buffer */
2529
	if (   icp->fp->seek(icp->fp, of) != 0
2530
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
2531
		sprintf(icp->err,"icmS15Fixed16Array_read: fseek() or fread() failed");
2532
		icp->al->free(icp->al, buf);
2533
		return icp->errc = 1;
2534
	}
2535
	p->size = size = (len - 8)/4;		/* Number of elements in the array */
2536
 
2537
	if ((rv = p->allocate((icmBase *)p)) != 0) {
2538
		icp->al->free(icp->al, buf);
2539
		return rv;
2540
	}
2541
 
2542
	/* Read type descriptor from the buffer */
2543
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2544
		sprintf(icp->err,"icmS15Fixed16Array_read: Wrong tag type for icmS15Fixed16Array");
2545
		icp->al->free(icp->al, buf);
2546
		return icp->errc = 1;
2547
	}
2548
	bp += 8;	/* Skip padding */
2549
 
2550
	/* Read all the data from the buffer */
2551
	for (i = 0; i < size; i++, bp += 4) {
2552
		p->data[i] = read_S15Fixed16Number(bp);
2553
	}
2554
	icp->al->free(icp->al, buf);
2555
	return 0;
2556
}
2557
 
2558
/* Write the contents of the object. Return 0 on sucess, error code on failure */
2559
static int icmS15Fixed16Array_write(
2560
	icmBase *pp,
2561
	unsigned long of			/* File offset to write from */
2562
) {
2563
	icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2564
	icc *icp = p->icp;
2565
	unsigned long i;
2566
	unsigned int len;
2567
	char *bp, *buf;		/* Buffer to write from */
2568
	int rv = 0;
2569
 
2570
	/* Allocate a file write buffer */
2571
	len = p->get_size((icmBase *)p);
2572
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2573
		sprintf(icp->err,"icmS15Fixed16Array_write malloc() failed");
2574
		return icp->errc = 2;
2575
	}
2576
	bp = buf;
2577
 
2578
	/* Write type descriptor to the buffer */
2579
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2580
		sprintf(icp->err,"icmS15Fixed16Array_write: write_SInt32Number() failed");
2581
		icp->al->free(icp->al, buf);
2582
		return icp->errc = rv;
2583
	}
2584
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
2585
 
2586
	/* Write all the data to the buffer */
2587
	bp += 8;	/* Skip padding */
2588
	for (i = 0; i < p->size; i++, bp += 4) {
2589
		if ((rv = write_S15Fixed16Number(p->data[i],bp)) != 0) {
2590
			sprintf(icp->err,"icmS15Fixed16Array_write: write_S15Fixed16umber() failed");
2591
			icp->al->free(icp->al, buf);
2592
			return icp->errc = rv;
2593
		}
2594
	}
2595
 
2596
	/* Write to the file */
2597
	if (   icp->fp->seek(icp->fp, of) != 0
2598
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
2599
		sprintf(icp->err,"icmS15Fixed16Array_write fseek() or fwrite() failed");
2600
		icp->al->free(icp->al, buf);
2601
		return icp->errc = 2;
2602
	}
2603
	icp->al->free(icp->al, buf);
2604
	return 0;
2605
}
2606
 
2607
/* Dump a text description of the object */
2608
static void icmS15Fixed16Array_dump(
2609
	icmBase *pp,
2610
	FILE *op,		/* Output to dump to */
2611
	int   verb		/* Verbosity level */
2612
) {
2613
	icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2614
	if (verb <= 0)
2615
		return;
2616
 
2617
	fprintf(op,"S15Fixed16Array:\n");
2618
	fprintf(op,"  No. elements = %lu\n",p->size);
2619
	if (verb >= 2) {
2620
		unsigned long i;
2621
		for (i = 0; i < p->size; i++)
2622
			fprintf(op,"    %lu:  %f\n",i,p->data[i]);
2623
	}
2624
}
2625
 
2626
/* Allocate variable sized data elements */
2627
static int icmS15Fixed16Array_allocate(
2628
	icmBase *pp
2629
) {
2630
	icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2631
	icc *icp = p->icp;
2632
 
2633
	if (p->size != p->_size) {
2634
		if (p->data != NULL)
2635
			icp->al->free(icp->al, p->data);
2636
		if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) {
2637
			sprintf(icp->err,"icmS15Fixed16Array_alloc: malloc() of icmS15Fixed16Array data failed");
2638
			return icp->errc = 2;
2639
		}
2640
		p->_size = p->size;
2641
	}
2642
	return 0;
2643
}
2644
 
2645
/* Free all storage in the object */
2646
static void icmS15Fixed16Array_delete(
2647
	icmBase *pp
2648
) {
2649
	icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
2650
	icc *icp = p->icp;
2651
 
2652
	if (p->data != NULL)
2653
		icp->al->free(icp->al, p->data);
2654
	icp->al->free(icp->al, p);
2655
}
2656
 
2657
/* Create an empty object. Return null on error */
2658
static icmBase *new_icmS15Fixed16Array(
2659
	icc *icp
2660
) {
2661
	icmS15Fixed16Array *p;
2662
	if ((p = (icmS15Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmS15Fixed16Array))) == NULL)
2663
		return NULL;
2664
	p->ttype    = icSigS15Fixed16ArrayType;
2665
	p->refcount = 1;
2666
	p->get_size = icmS15Fixed16Array_get_size;
2667
	p->read     = icmS15Fixed16Array_read;
2668
	p->write    = icmS15Fixed16Array_write;
2669
	p->dump     = icmS15Fixed16Array_dump;
2670
	p->allocate = icmS15Fixed16Array_allocate;
2671
	p->del      = icmS15Fixed16Array_delete;
2672
	p->icp      = icp;
2673
 
2674
	return (icmBase *)p;
2675
}
2676
 
2677
/* ---------------------------------------------------------- */
2678
 
2679
/* Data conversion support functions */
2680
static int write_XYZNumber(icmXYZNumber *p, char *d) {
2681
	int rv;
2682
	if ((rv = write_S15Fixed16Number(p->X, d + 0)) != 0)
2683
		return rv;
2684
	if ((rv = write_S15Fixed16Number(p->Y, d + 4)) != 0)
2685
		return rv;
2686
	if ((rv = write_S15Fixed16Number(p->Z, d + 8)) != 0)
2687
		return rv;
2688
	return 0;
2689
}
2690
 
2691
static int read_XYZNumber(icmXYZNumber *p, char *d) {
2692
	p->X = read_S15Fixed16Number(d + 0);
2693
	p->Y = read_S15Fixed16Number(d + 4);
2694
	p->Z = read_S15Fixed16Number(d + 8);
2695
	return 0;
2696
}
2697
 
2698
 
2699
/* Helper: Return a string that shows the XYZ number value */
2700
static char *string_XYZNumber(icmXYZNumber *p) {
2701
	static char buf[40];
2702
 
2703
	sprintf(buf,"%f, %f, %f", p->X, p->Y, p->Z);
2704
	return buf;
2705
}
2706
 
2707
/* Helper: Return a string that shows the XYZ number value, */
2708
/* and the Lab D50 number in paren. */
2709
static char *string_XYZNumber_and_Lab(icmXYZNumber *p) {
2710
	static char buf[50];
2711
	double lab[3];
2712
	lab[0] = p->X;
2713
	lab[1] = p->Y;
2714
	lab[2] = p->Z;
2715
	icmXYZ2Lab(&icmD50, lab, lab);
2716
	sprintf(buf,"%f, %f, %f    [Lab %f, %f, %f]", p->X, p->Y, p->Z, lab[0], lab[1], lab[2]);
2717
	return buf;
2718
}
2719
 
2720
/* icmXYZArray object */
2721
 
2722
/* Return the number of bytes needed to write this tag */
2723
static unsigned int icmXYZArray_get_size(
2724
	icmBase *pp
2725
) {
2726
	icmXYZArray *p = (icmXYZArray *)pp;
2727
	unsigned int len = 0;
2728
	len += 8;				/* 8 bytes for tag and padding */
2729
	len += p->size * 12;	/* 12 bytes for each XYZ */
2730
	return len;
2731
}
2732
 
2733
/* read the object, return 0 on success, error code on fail */
2734
static int icmXYZArray_read(
2735
	icmBase *pp,
2736
	unsigned long len,		/* tag length */
2737
	unsigned long of		/* start offset within file */
2738
) {
2739
	icmXYZArray *p = (icmXYZArray *)pp;
2740
	icc *icp = p->icp;
2741
	int rv = 0;
2742
	unsigned long i, size;
2743
	char *bp, *buf;
2744
 
2745
	if (len < 8) {
2746
		sprintf(icp->err,"icmXYZArray_read: Tag too small to be legal");
2747
		return icp->errc = 1;
2748
	}
2749
 
2750
	/* Allocate a file read buffer */
2751
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2752
		sprintf(icp->err,"icmXYZArray_read: malloc() failed");
2753
		return icp->errc = 2;
2754
	}
2755
	bp = buf;
2756
 
2757
	/* Read portion of file into buffer */
2758
	if (   icp->fp->seek(icp->fp, of) != 0
2759
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
2760
		sprintf(icp->err,"icmXYZArray_read: fseek() or fread() failed");
2761
		icp->al->free(icp->al, buf);
2762
		return icp->errc = 1;
2763
	}
2764
	p->size = size = (len - 8)/12;		/* Number of elements in the array */
2765
 
2766
	if ((rv = p->allocate((icmBase *)p)) != 0) {
2767
		icp->al->free(icp->al, buf);
2768
		return rv;
2769
	}
2770
 
2771
	/* Read type descriptor from the buffer */
2772
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
2773
		sprintf(icp->err,"icmXYZArray_read: Wrong tag type for icmXYZArray");
2774
		icp->al->free(icp->al, buf);
2775
		return icp->errc = 1;
2776
	}
2777
	bp += 8;	/* Skip padding */
2778
 
2779
	/* Read all the data from the buffer */
2780
	for (i = 0; i < size; i++, bp += 12) {
2781
		read_XYZNumber(&p->data[i], bp);
2782
	}
2783
	icp->al->free(icp->al, buf);
2784
	return 0;
2785
}
2786
 
2787
/* Write the contents of the object. Return 0 on sucess, error code on failure */
2788
static int icmXYZArray_write(
2789
	icmBase *pp,
2790
	unsigned long of			/* File offset to write from */
2791
) {
2792
	icmXYZArray *p = (icmXYZArray *)pp;
2793
	icc *icp = p->icp;
2794
	unsigned long i;
2795
	unsigned int len;
2796
	char *bp, *buf;		/* Buffer to write from */
2797
	int rv = 0;
2798
 
2799
	/* Allocate a file write buffer */
2800
	len = p->get_size((icmBase *)p);
2801
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
2802
		sprintf(icp->err,"icmXYZArray_write malloc() failed");
2803
		return icp->errc = 2;
2804
	}
2805
	bp = buf;
2806
 
2807
	/* Write type descriptor to the buffer */
2808
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
2809
		sprintf(icp->err,"icmXYZArray_write: write_SInt32Number() failed");
2810
		icp->al->free(icp->al, buf);
2811
		return icp->errc = rv;
2812
	}
2813
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
2814
 
2815
	/* Write all the data to the buffer */
2816
	bp += 8;	/* Skip padding */
2817
	for (i = 0; i < p->size; i++, bp += 12) {
2818
		if ((rv = write_XYZNumber(&p->data[i],bp)) != 0) {
2819
			sprintf(icp->err,"icmXYZArray_write: write_XYZumber() failed");
2820
			icp->al->free(icp->al, buf);
2821
			return icp->errc = rv;
2822
		}
2823
	}
2824
 
2825
	/* Write to the file */
2826
	if (   icp->fp->seek(icp->fp, of) != 0
2827
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
2828
		sprintf(icp->err,"icmXYZArray_write fseek() or fwrite() failed");
2829
		icp->al->free(icp->al, buf);
2830
		return icp->errc = 2;
2831
	}
2832
	icp->al->free(icp->al, buf);
2833
	return 0;
2834
}
2835
 
2836
/* Dump a text description of the object */
2837
static void icmXYZArray_dump(
2838
	icmBase *pp,
2839
	FILE *op,		/* Output to dump to */
2840
	int   verb		/* Verbosity level */
2841
) {
2842
	icmXYZArray *p = (icmXYZArray *)pp;
2843
	if (verb <= 0)
2844
		return;
2845
 
2846
	fprintf(op,"XYZArray:\n");
2847
	fprintf(op,"  No. elements = %lu\n",p->size);
2848
	if (verb >= 2) {
2849
		unsigned long i;
2850
		for (i = 0; i < p->size; i++) {
2851
			fprintf(op,"    %lu:  %s\n",i,string_XYZNumber_and_Lab(&p->data[i]));
2852
 
2853
		}
2854
	}
2855
}
2856
 
2857
 
2858
/* Allocate variable sized data elements */
2859
static int icmXYZArray_allocate(
2860
	icmBase *pp
2861
) {
2862
	icmXYZArray *p = (icmXYZArray *)pp;
2863
	icc *icp = p->icp;
2864
 
2865
	if (p->size != p->_size) {
2866
		if (p->data != NULL)
2867
			icp->al->free(icp->al, p->data);
2868
		if ((p->data = (icmXYZNumber *) icp->al->malloc(icp->al, p->size * sizeof(icmXYZNumber))) == NULL) {
2869
			sprintf(icp->err,"icmXYZArray_alloc: malloc() of icmXYZArray data failed");
2870
			return icp->errc = 2;
2871
		}
2872
		p->_size = p->size;
2873
	}
2874
	return 0;
2875
}
2876
 
2877
/* Free all storage in the object */
2878
static void icmXYZArray_delete(
2879
	icmBase *pp
2880
) {
2881
	icmXYZArray *p = (icmXYZArray *)pp;
2882
	icc *icp = p->icp;
2883
 
2884
	if (p->data != NULL)
2885
		icp->al->free(icp->al, p->data);
2886
	icp->al->free(icp->al, p);
2887
}
2888
 
2889
/* Create an empty object. Return null on error */
2890
static icmBase *new_icmXYZArray(
2891
	icc *icp
2892
) {
2893
	icmXYZArray *p;
2894
	if ((p = (icmXYZArray *) icp->al->calloc(icp->al,1,sizeof(icmXYZArray))) == NULL)
2895
		return NULL;
2896
	p->ttype    = icSigXYZArrayType;
2897
	p->refcount = 1;
2898
	p->get_size = icmXYZArray_get_size;
2899
	p->read     = icmXYZArray_read;
2900
	p->write    = icmXYZArray_write;
2901
	p->dump     = icmXYZArray_dump;
2902
	p->allocate = icmXYZArray_allocate;
2903
	p->del      = icmXYZArray_delete;
2904
	p->icp      = icp;
2905
 
2906
	return (icmBase *)p;
2907
}
2908
 
2909
/* ---------------------------------------------------------- */
2910
/* icmCurve object */
2911
 
2912
/* Do a forward lookup through the curve */
2913
/* Return 0 on success, 1 if clipping occured, 2 on other error */
2914
static int icmCurve_lookup_fwd(
2915
	icmCurve *p,
2916
	double *out,
2917
	double *in
2918
) {
2919
	int rv = 0;
2920
	if (p->flag == icmCurveLin) {
2921
		*out = *in;
2922
	} else if (p->flag == icmCurveGamma) {
2923
		double val = *in;
2924
		if (val <= 0.0)
2925
			*out = 0.0;
2926
		else
2927
			*out = pow(val, p->data[0]);
2928
	} else { /* Use linear interpolation */
2929
		int ix;
2930
		double val, w;
2931
		double inputEnt_1 = (double)(p->size-1);
2932
 
2933
		val = *in * inputEnt_1;
2934
		if (val < 0.0) {
2935
			val = 0.0;
2936
			rv |= 1;
2937
		} else if (val > inputEnt_1) {
2938
			val = inputEnt_1;
2939
			rv |= 1;
2940
		}
2941
		ix = (int)floor(val);		/* Coordinate */
2942
		if (ix > (p->size-2))
2943
			ix = (p->size-2);
2944
		w = val - (double)ix;		/* weight */
2945
		val = p->data[ix];
2946
		*out = val + w * (p->data[ix+1] - val);
2947
	}
2948
	return rv;
2949
}
2950
 
2951
/* - - - - - - - - - - - - */
2952
/* Support for reverse interpolation of 1D lookup tables */
2953
 
2954
/* Create a reverse curve lookup acceleration table */
2955
/* return non-zero on error, 2 = malloc error. */
2956
static int icmTable_setup_bwd(
2957
	icc          *icp,			/* Base icc object */
2958
	icmRevTable  *rt,			/* Reverse table data to setup */
2959
	unsigned long size,			/* Size of fwd table */
2960
	double       *data			/* Table */
2961
) {
2962
	int i;
2963
 
2964
	rt->size = size;		/* Stash pointers to these away */
2965
	rt->data = data;
2966
 
2967
	/* Find range of output values */
2968
	rt->rmin = 1e300;
2969
	rt->rmax = -1e300;
2970
	for (i = 0; i < rt->size; i++) {
2971
		if (rt->data[i] > rt->rmax)
2972
			rt->rmax = rt->data[i];
2973
		if (rt->data[i] < rt->rmin)
2974
			rt->rmin = rt->data[i];
2975
	}
2976
 
2977
	/* Decide on reverse granularity */
2978
	rt->rsize = (rt->size+2)/2;
2979
	rt->qscale = (double)rt->rsize/(rt->rmax - rt->rmin);	/* Scale factor to quantize to */
2980
 
2981
	/* Initialize the reverse lookup structures, and get overall min/max */
2982
	if ((rt->rlists = (int **) icp->al->calloc(icp->al, 1, rt->rsize * sizeof(int *))) == NULL) {
2983
		return 2;
2984
	}
2985
 
2986
	/* Assign each output value range bucket lists it intersects */
2987
	for (i = 0; i < (rt->size-1); i++) {
2988
		int s, e, j;	/* Start and end indexes (inclusive) */
2989
		s = (int)((rt->data[i] - rt->rmin) * rt->qscale);
2990
		e = (int)((rt->data[i+1] - rt->rmin) * rt->qscale);
2991
		if (s > e) {	/* swap */
2992
			int t;
2993
			t = s; s = e; e = t;
2994
		}
2995
		if (e >= rt->rsize)
2996
			e = rt->rsize-1;
2997
 
2998
		/* For all buckets that may contain this output range, add index of this output */
2999
		for (j = s; j <= e; j++) {
3000
			int as;			/* Allocation size */
3001
			int nf;			/* Next free slot */
3002
			if (rt->rlists[j] == NULL) {	/* No allocation */
3003
				as = 5;						/* Start with space for 5 */
3004
				if ((rt->rlists[j] = (int *) icp->al->malloc(icp->al, sizeof(int) * as)) == NULL) {
3005
					return 2;
3006
				}
3007
				rt->rlists[j][0] = as;
3008
				nf = rt->rlists[j][1] = 2;
3009
			} else {
3010
				as = rt->rlists[j][0];	/* Allocate space for this list */
3011
				nf = rt->rlists[j][1];	/* Next free location in list */
3012
				if (nf >= as) {			/* need to expand space */
3013
					as *= 2;
3014
					rt->rlists[j] = (int *) icp->al->realloc(icp->al,rt->rlists[j], sizeof(int) * as);
3015
					if (rt->rlists[j] == NULL) {
3016
						return 2;
3017
					}
3018
					rt->rlists[j][0] = as;
3019
				}
3020
			}
3021
			rt->rlists[j][nf++] = i;
3022
			rt->rlists[j][1] = nf;
3023
		}
3024
	}
3025
	rt->inited = 1;
3026
	return 0;
3027
}
3028
 
3029
/* Free up any data */
3030
static void icmTable_delete_bwd(
3031
	icc          *icp,			/* Base icc */
3032
	icmRevTable  *rt			/* Reverse table data to setup */
3033
) {
3034
	if (rt->inited != 0) {
3035
		while (rt->rsize > 0)
3036
			icp->al->free(icp->al, rt->rlists[--rt->rsize]);
3037
		icp->al->free(icp->al, rt->rlists);
3038
		rt->size = 0;			/* Don't keep these */
3039
		rt->data = NULL;
3040
	}
3041
}
3042
 
3043
/* Do a reverse lookup through the curve */
3044
/* Return 0 on success, 1 if clipping occured, 2 on other error */
3045
static int icmTable_lookup_bwd(
3046
	icmRevTable *rt,
3047
	double *out,
3048
	double *in
3049
) {
3050
	int rv = 0;
3051
	int ix, i, k;
3052
	double oval, ival = *in, val;
3053
	double rsize_1;
3054
 
3055
	/* Find appropriate reverse list */
3056
	rsize_1 = (double)(rt->rsize-1);
3057
	val = ((ival - rt->rmin) * rt->qscale);
3058
	if (val < 0.0)
3059
		val = 0.0;
3060
	else if (val > rsize_1)
3061
		val = rsize_1;
3062
	ix = (int)floor(val);		/* Coordinate */
3063
 
3064
	if (ix > (rt->size-2))
3065
		ix = (rt->size-2);
3066
	if (rt->rlists[ix] != NULL)  {		/* There is a list of fwd candidates */
3067
		/* For each candidate forward range */
3068
		for (i = 2; i < rt->rlists[ix][1]; i++)  {	/* For all fwd indexes */
3069
			double lv,hv;
3070
			k = rt->rlists[ix][i];					/* Base index */
3071
			lv = rt->data[k];
3072
			hv = rt->data[k+1];
3073
			if ((ival >= lv && ival <= hv)	/* If this slot contains output value */
3074
			 || (ival >= hv && ival <= lv)) {
3075
				/* Reverse linear interpolation */
3076
				if (hv == lv) {	/* Technically non-monotonic - due to quantization ? */
3077
					oval = (k + 0.5)/(rt->size-1.0);
3078
				} else
3079
					oval = (k + ((ival - lv)/(hv - lv)))/(rt->size-1.0);
3080
				/* If we kept looking, we would find multiple */
3081
				/* solution for non-monotonic curve */
3082
				*out = oval;
3083
				return rv;
3084
			}
3085
		}
3086
	}
3087
 
3088
	/* We have failed to find an exact value, so return the nearest value */
3089
	/* (This is slow !) */
3090
	val = fabs(ival - rt->data[0]);
3091
	for (k = 0, i = 1; i < rt->size; i++) {
3092
		double er;
3093
		er = fabs(ival - rt->data[i]);
3094
		if (er < val) {	/* new best */
3095
			val = er;
3096
			k = i;
3097
		}
3098
	}
3099
	*out = k/(rt->size-1.0);
3100
	rv |= 1;
3101
	return rv;
3102
}
3103
 
3104
 
3105
/* - - - - - - - - - - - - */
3106
 
3107
/* Do a reverse lookup through the curve */
3108
/* Return 0 on success, 1 if clipping occured, 2 on other error */
3109
static int icmCurve_lookup_bwd(
3110
	icmCurve *p,
3111
	double *out,
3112
	double *in
3113
) {
3114
	icc *icp = p->icp;
3115
	int rv = 0;
3116
	if (p->flag == icmCurveLin) {
3117
		*out = *in;
3118
	} else if (p->flag == icmCurveGamma) {
3119
		double val = *in;
3120
		if (val <= 0.0)
3121
			*out = 0.0;
3122
		else
3123
			*out = pow(val, 1.0/p->data[0]);
3124
	} else { /* Use linear interpolation */
3125
		if (p->rt.inited == 0) {	
3126
			rv = icmTable_setup_bwd(icp, &p->rt, p->size, p->data);
3127
			if (rv != 0) {
3128
				sprintf(icp->err,"icmCurve_lookup: Malloc failure in reverse lookup init.");
3129
				return icp->errc = rv;
3130
			}
3131
		}
3132
		rv = icmTable_lookup_bwd(&p->rt, out, in);
3133
	}
3134
	return rv;
3135
}
3136
 
3137
/* Return the number of bytes needed to write this tag */
3138
static unsigned int icmCurve_get_size(
3139
	icmBase *pp
3140
) {
3141
	icmCurve *p = (icmCurve *)pp;
3142
	unsigned int len = 0;
3143
	len += 12;			/* 12 bytes for tag, padding and count */
3144
	len += p->size * 2;	/* 2 bytes for each UInt16 */
3145
	return len;
3146
}
3147
 
3148
/* read the object, return 0 on success, error code on fail */
3149
static int icmCurve_read(
3150
	icmBase *pp,
3151
	unsigned long len,		/* tag length */
3152
	unsigned long of		/* start offset within file */
3153
) {
3154
	icmCurve *p = (icmCurve *)pp;
3155
	icc *icp = p->icp;
3156
	int rv = 0;
3157
	unsigned long i;
3158
	char *bp, *buf, *end;
3159
 
3160
	if (len < 12) {
3161
		sprintf(icp->err,"icmCurve_read: Tag too small to be legal");
3162
		return icp->errc = 1;
3163
	}
3164
 
3165
	/* Allocate a file read buffer */
3166
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3167
		sprintf(icp->err,"icmCurve_read: malloc() failed");
3168
		return icp->errc = 2;
3169
	}
3170
	bp = buf;
3171
	end = buf + len;
3172
 
3173
	/* Read portion of file into buffer */
3174
	if (   icp->fp->seek(icp->fp, of) != 0
3175
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
3176
		sprintf(icp->err,"icmCurve_read: fseek() or fread() failed");
3177
		icp->al->free(icp->al, buf);
3178
		return icp->errc = 1;
3179
	}
3180
 
3181
	/* Read type descriptor from the buffer */
3182
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
3183
		sprintf(icp->err,"icmCurve_read: Wrong tag type for icmCurve");
3184
		icp->al->free(icp->al, buf);
3185
		return icp->errc = 1;
3186
	}
3187
 
3188
	p->size = read_UInt32Number(bp+8);
3189
	bp = bp + 12;
3190
 
3191
	/* Set flag up before allocating */
3192
	if (p->size == 0) {		/* Linear curve */
3193
		p->flag = icmCurveLin;
3194
	} else if (p->size == 1) {	/* Gamma curve */
3195
		p->flag = icmCurveGamma;
3196
	} else {
3197
		p->flag = icmCurveSpec;
3198
	}
3199
 
3200
	if ((rv = p->allocate((icmBase *)p)) != 0) {
3201
		icp->al->free(icp->al, buf);
3202
		return rv;
3203
	}
3204
 
3205
	if (p->flag == icmCurveGamma) {	/* Gamma curve */
3206
		if ((bp + 1) > end) {
3207
			sprintf(icp->err,"icmCurve_read: Data too short to curve gamma");
3208
			icp->al->free(icp->al, buf);
3209
			return icp->errc = 1;
3210
		}
3211
		p->data[0] = read_U8Fixed8Number(bp);
3212
	} else if (p->flag == icmCurveSpec) {
3213
		/* Read all the data from the buffer */
3214
		for (i = 0; i < p->size; i++, bp += 2) {
3215
			if ((bp + 2) > end) {
3216
				sprintf(icp->err,"icmData_read: Data too short to curve value");
3217
				icp->al->free(icp->al, buf);
3218
				return icp->errc = 1;
3219
			}
3220
			p->data[i] = read_DCS16Number(bp);
3221
		}
3222
	}
3223
	icp->al->free(icp->al, buf);
3224
	return 0;
3225
}
3226
 
3227
/* Write the contents of the object. Return 0 on sucess, error code on failure */
3228
static int icmCurve_write(
3229
	icmBase *pp,
3230
	unsigned long of			/* File offset to write from */
3231
) {
3232
	icmCurve *p = (icmCurve *)pp;
3233
	icc *icp = p->icp;
3234
	unsigned long i;
3235
	unsigned int len;
3236
	char *bp, *buf;		/* Buffer to write from */
3237
	int rv = 0;
3238
 
3239
	/* Allocate a file write buffer */
3240
	len = p->get_size((icmBase *)p);
3241
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3242
		sprintf(icp->err,"icmCurve_write malloc() failed");
3243
		return icp->errc = 2;
3244
	}
3245
	bp = buf;
3246
 
3247
	/* Write type descriptor to the buffer */
3248
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
3249
		sprintf(icp->err,"icmCurve_write: write_SInt32Number() failed");
3250
		icp->al->free(icp->al, buf);
3251
		return icp->errc = rv;
3252
	}
3253
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
3254
	/* Write count */
3255
	if ((rv = write_UInt32Number(p->size,bp+8)) != 0) {
3256
		sprintf(icp->err,"icmCurve_write: write_UInt32Number() failed");
3257
		icp->al->free(icp->al, buf);
3258
		return icp->errc = rv;
3259
	}
3260
 
3261
	/* Write all the data to the buffer */
3262
	bp += 12;	/* Skip padding */
3263
	if (p->flag == icmCurveLin) {
3264
		if (p->size != 0) {
3265
			sprintf(icp->err,"icmCurve_write: Must be exactly 0 entry for Linear");
3266
			icp->al->free(icp->al, buf);
3267
			return icp->errc = 1;
3268
		}
3269
	} else if (p->flag == icmCurveGamma) {
3270
		if (p->size != 1) {
3271
			sprintf(icp->err,"icmCurve_write: Must be exactly 1 entry for Gamma");
3272
			icp->al->free(icp->al, buf);
3273
			return icp->errc = 1;
3274
		}
3275
		if ((rv = write_U8Fixed8Number(p->data[0],bp)) != 0) {
3276
			sprintf(icp->err,"icmCurve_write: write_U8Fixed8umber(%f) failed",p->data[0]);
3277
			icp->al->free(icp->al, buf);
3278
			return icp->errc = rv;
3279
		}
3280
	} else if (p->flag == icmCurveSpec) {
3281
		if (p->size < 2) {
3282
			sprintf(icp->err,"icmCurve_write: Must be 2 or more entries for Specified curve");
3283
			icp->al->free(icp->al, buf);
3284
			return icp->errc = 1;
3285
		}
3286
		for (i = 0; i < p->size; i++, bp += 2) {
3287
			if ((rv = write_DCS16Number(p->data[i],bp)) != 0) {
3288
				sprintf(icp->err,"icmCurve_write: write_UInt16umber(%f) failed",p->data[i]);
3289
				icp->al->free(icp->al, buf);
3290
				return icp->errc = rv;
3291
			}
3292
		}
3293
	}
3294
 
3295
	/* Write to the file */
3296
	if (   icp->fp->seek(icp->fp, of) != 0
3297
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
3298
		sprintf(icp->err,"icmCurve_write fseek() or fwrite() failed");
3299
		icp->al->free(icp->al, buf);
3300
		return icp->errc = 2;
3301
	}
3302
	icp->al->free(icp->al, buf);
3303
	return 0;
3304
}
3305
 
3306
/* Dump a text description of the object */
3307
static void icmCurve_dump(
3308
	icmBase *pp,
3309
	FILE *op,		/* Output to dump to */
3310
	int   verb		/* Verbosity level */
3311
) {
3312
	icmCurve *p = (icmCurve *)pp;
3313
	if (verb <= 0)
3314
		return;
3315
 
3316
	fprintf(op,"Curve:\n");
3317
 
3318
	if (p->flag == icmCurveLin) {
3319
		fprintf(op,"  Curve is linear\n");
3320
	} else if (p->flag == icmCurveGamma) {
3321
		fprintf(op,"  Curve is gamma of %f\n",p->data[0]);
3322
	} else {
3323
		fprintf(op,"  No. elements = %lu\n",p->size);
3324
		if (verb >= 2) {
3325
			unsigned long i;
3326
			for (i = 0; i < p->size; i++)
3327
				fprintf(op,"    %3lu:  %f\n",i,p->data[i]);
3328
		}
3329
	}
3330
}
3331
 
3332
/* Allocate variable sized data elements */
3333
static int icmCurve_allocate(
3334
	icmBase *pp
3335
) {
3336
	icmCurve *p = (icmCurve *)pp;
3337
	icc *icp = p->icp;
3338
 
3339
	if (p->flag == icmCurveUndef) {
3340
		sprintf(icp->err,"icmCurve_alloc: flag not set");
3341
		return icp->errc = 1;
3342
	} else if (p->flag == icmCurveLin) {
3343
		p->size = 0;
3344
	} else if (p->flag == icmCurveGamma) {
3345
		p->size = 1;
3346
	}
3347
	if (p->size != p->_size) {
3348
		if (p->data != NULL)
3349
			icp->al->free(icp->al, p->data);
3350
		if ((p->data = (double *) icp->al->malloc(icp->al, p->size * sizeof(double))) == NULL) {
3351
			sprintf(icp->err,"icmCurve_alloc: malloc() of icmCurve data failed");
3352
			return icp->errc = 2;
3353
		}
3354
		p->_size = p->size;
3355
	}
3356
	return 0;
3357
}
3358
 
3359
/* Free all storage in the object */
3360
static void icmCurve_delete(
3361
	icmBase *pp
3362
) {
3363
	icmCurve *p = (icmCurve *)pp;
3364
	icc *icp = p->icp;
3365
 
3366
	if (p->data != NULL)
3367
		icp->al->free(icp->al, p->data);
3368
	icmTable_delete_bwd(icp, &p->rt);	/* Free reverse table info */
3369
	icp->al->free(icp->al, p);
3370
}
3371
 
3372
/* Create an empty object. Return null on error */
3373
static icmBase *new_icmCurve(
3374
	icc *icp
3375
) {
3376
	icmCurve *p;
3377
	if ((p = (icmCurve *) icp->al->calloc(icp->al,1,sizeof(icmCurve))) == NULL)
3378
		return NULL;
3379
	p->ttype    = icSigCurveType;
3380
	p->refcount = 1;
3381
	p->get_size = icmCurve_get_size;
3382
	p->read     = icmCurve_read;
3383
	p->write    = icmCurve_write;
3384
	p->dump     = icmCurve_dump;
3385
	p->allocate = icmCurve_allocate;
3386
	p->del      = icmCurve_delete;
3387
	p->icp      = icp;
3388
 
3389
	p->lookup_fwd = icmCurve_lookup_fwd;
3390
	p->lookup_bwd = icmCurve_lookup_bwd;
3391
 
3392
	p->rt.inited = 0;
3393
 
3394
	p->flag = icmCurveUndef;
3395
	return (icmBase *)p;
3396
}
3397
 
3398
/* ---------------------------------------------------------- */
3399
/* icmData object */
3400
 
3401
/* Return the number of bytes needed to write this tag */
3402
static unsigned int icmData_get_size(
3403
	icmBase *pp
3404
) {
3405
	icmData *p = (icmData *)pp;
3406
	unsigned int len = 0;
3407
	len += 12;			/* 12 bytes for tag and padding */
3408
	len += p->size * 1;	/* 1 byte for each data element */
3409
	return len;
3410
}
3411
 
3412
/* read the object, return 0 on success, error code on fail */
3413
static int icmData_read(
3414
	icmBase *pp,
3415
	unsigned long len,		/* tag length */
3416
	unsigned long of		/* start offset within file */
3417
) {
3418
	icmData *p = (icmData *)pp;
3419
	icc *icp = p->icp;
3420
	int rv = 0;
3421
	unsigned size, f;
3422
	char *bp, *buf;
3423
 
3424
	if (len < 12) {
3425
		sprintf(icp->err,"icmData_read: Tag too small to be legal");
3426
		return icp->errc = 1;
3427
	}
3428
 
3429
	/* Allocate a file read buffer */
3430
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3431
		sprintf(icp->err,"icmData_read: malloc() failed");
3432
		return icp->errc = 2;
3433
	}
3434
	bp = buf;
3435
 
3436
	/* Read portion of file into buffer */
3437
	if (   icp->fp->seek(icp->fp, of) != 0
3438
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
3439
		sprintf(icp->err,"icmData_read: fseek() or fread() failed");
3440
		icp->al->free(icp->al, buf);
3441
		return icp->errc = 1;
3442
	}
3443
	p->size = size = (len - 12)/1;		/* Number of elements in the array */
3444
 
3445
	/* Read type descriptor from the buffer */
3446
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
3447
		sprintf(icp->err,"icmData_read: Wrong tag type for icmData");
3448
		icp->al->free(icp->al, buf);
3449
		return icp->errc = 1;
3450
	}
3451
	/* Read the data type flag */
3452
	f = read_UInt32Number(bp+8);
3453
	if (f == 0) {
3454
		p->flag = icmDataASCII;
3455
	} else if (f == 1) {
3456
		p->flag = icmDataBin;
3457
	} else {
3458
		sprintf(icp->err,"icmData_read: Unknown flag value 0x%x",f);
3459
		icp->al->free(icp->al, buf);
3460
		return icp->errc = 1;
3461
	}
3462
	bp += 12;	/* Skip padding and flag */
3463
 
3464
	if (p->size > 0) {
3465
		if (p->flag == icmDataASCII) {
3466
			if (check_null_string(bp,p->size) != 0) {
3467
				sprintf(icp->err,"icmData_read: ACSII is not null terminated");
3468
				icp->al->free(icp->al, buf);
3469
				return icp->errc = 1;
3470
			}
3471
		}
3472
		if ((rv = p->allocate((icmBase *)p)) != 0) {
3473
			icp->al->free(icp->al, buf);
3474
			return rv;
3475
		}
3476
 
3477
		memcpy((void *)p->data, (void *)bp, p->size);
3478
	}
3479
	icp->al->free(icp->al, buf);
3480
	return 0;
3481
}
3482
 
3483
/* Write the contents of the object. Return 0 on sucess, error code on failure */
3484
static int icmData_write(
3485
	icmBase *pp,
3486
	unsigned long of			/* File offset to write from */
3487
) {
3488
	icmData *p = (icmData *)pp;
3489
	icc *icp = p->icp;
3490
	unsigned int len, f;
3491
	char *bp, *buf;		/* Buffer to write from */
3492
	int rv = 0;
3493
 
3494
	/* Allocate a file write buffer */
3495
	len = p->get_size((icmBase *)p);
3496
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3497
		sprintf(icp->err,"icmData_write malloc() failed");
3498
		return icp->errc = 2;
3499
	}
3500
	bp = buf;
3501
 
3502
	/* Write type descriptor to the buffer */
3503
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
3504
		sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
3505
		icp->al->free(icp->al, buf);
3506
		return icp->errc = rv;
3507
	}
3508
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
3509
	switch(p->flag) {
3510
		case icmDataASCII:
3511
			f = 0;
3512
			break;
3513
		case icmDataBin:
3514
			f = 1;
3515
			break;
3516
		default:
3517
			sprintf(icp->err,"icmData_write: Unknown Data Flag value");
3518
			icp->al->free(icp->al, buf);
3519
			return icp->errc = 1;
3520
	}
3521
	/* Write data flag descriptor to the buffer */
3522
	if ((rv = write_UInt32Number(f,bp+8)) != 0) {
3523
		sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
3524
		icp->al->free(icp->al, buf);
3525
		return icp->errc = rv;
3526
	}
3527
	bp += 12;	/* Skip padding */
3528
 
3529
	if (p->data != NULL) {
3530
		if (p->flag == icmDataASCII) {
3531
			if ((rv = check_null_string((char *)p->data, p->size)) != 0) {
3532
				sprintf(icp->err,"icmData_write: ASCII is not null terminated");
3533
				icp->al->free(icp->al, buf);
3534
				return icp->errc = 1;
3535
			}
3536
		}
3537
		memcpy((void *)bp, (void *)p->data, p->size);
3538
	}
3539
 
3540
	/* Write to the file */
3541
	if (   icp->fp->seek(icp->fp, of) != 0
3542
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
3543
		sprintf(icp->err,"icmData_write fseek() or fwrite() failed");
3544
		icp->al->free(icp->al, buf);
3545
		return icp->errc = 2;
3546
	}
3547
	icp->al->free(icp->al, buf);
3548
	return 0;
3549
}
3550
 
3551
/* Dump a text description of the object */
3552
static void icmData_dump(
3553
	icmBase *pp,
3554
	FILE *op,		/* Output to dump to */
3555
	int   verb		/* Verbosity level */
3556
) {
3557
	icmData *p = (icmData *)pp;
3558
	unsigned long i, r, c, size = 0;
3559
 
3560
	if (verb <= 0)
3561
		return;
3562
 
3563
	fprintf(op,"Data:\n");
3564
	switch(p->flag) {
3565
		case icmDataASCII:
3566
			fprintf(op,"  ASCII data\n");
3567
			size = p->size > 0 ? p->size-1 : 0;
3568
			break;
3569
		case icmDataBin:
3570
			fprintf(op,"  Binary data\n");
3571
			size = p->size;
3572
			break;
3573
		case icmDataUndef:
3574
			fprintf(op,"  Undefined data\n");
3575
			size = p->size;
3576
			break;
3577
	}
3578
	fprintf(op,"  No. elements = %lu\n",p->size);
3579
 
3580
	i = 0;
3581
	for (r = 1;; r++) {		/* count rows */
3582
		if (i >= size) {
3583
			fprintf(op,"\n");
3584
			break;
3585
		}
3586
		if (r > 1 && verb < 2) {
3587
			fprintf(op,"...\n");
3588
			break;			/* Print 1 row if not verbose */
3589
		}
3590
		c = 1;
3591
		fprintf(op,"    0x%04lx: ",i);
3592
		c += 10;
3593
		while (i < size && c < 75) {
3594
			if (p->flag == icmDataASCII) {
3595
				if (isprint(p->data[i])) {
3596
					fprintf(op,"%c",p->data[i]);
3597
					c++;
3598
				} else {
3599
					fprintf(op,"\\%03o",p->data[i]);
3600
					c += 4;
3601
				}
3602
			} else {
3603
				fprintf(op,"%02x ",p->data[i]);
3604
				c += 3;
3605
			}
3606
			i++;
3607
		}
3608
		if (i < size)
3609
			fprintf(op,"\n");
3610
	}
3611
}
3612
 
3613
/* Allocate variable sized data elements */
3614
static int icmData_allocate(
3615
	icmBase *pp
3616
) {
3617
	icmData *p = (icmData *)pp;
3618
	icc *icp = p->icp;
3619
 
3620
	if (p->size != p->_size) {
3621
		if (p->data != NULL)
3622
			icp->al->free(icp->al, p->data);
3623
		if ((p->data = (unsigned char *) icp->al->malloc(icp->al, p->size * sizeof(unsigned char))) == NULL) {
3624
			sprintf(icp->err,"icmData_alloc: malloc() of icmData data failed");
3625
			return icp->errc = 2;
3626
		}
3627
		p->_size = p->size;
3628
	}
3629
	return 0;
3630
}
3631
 
3632
/* Free all storage in the object */
3633
static void icmData_delete(
3634
	icmBase *pp
3635
) {
3636
	icmData *p = (icmData *)pp;
3637
	icc *icp = p->icp;
3638
 
3639
	if (p->data != NULL)
3640
		icp->al->free(icp->al, p->data);
3641
	icp->al->free(icp->al, p);
3642
}
3643
 
3644
/* Create an empty object. Return null on error */
3645
static icmBase *new_icmData(
3646
	icc *icp
3647
) {
3648
	icmData *p;
3649
	if ((p = (icmData *) icp->al->calloc(icp->al,1,sizeof(icmData))) == NULL)
3650
		return NULL;
3651
	p->ttype    = icSigDataType;
3652
	p->refcount = 1;
3653
	p->get_size = icmData_get_size;
3654
	p->read     = icmData_read;
3655
	p->write    = icmData_write;
3656
	p->dump     = icmData_dump;
3657
	p->allocate = icmData_allocate;
3658
	p->del      = icmData_delete;
3659
	p->icp      = icp;
3660
 
3661
	p->flag = icmDataUndef;
3662
	return (icmBase *)p;
3663
}
3664
 
3665
/* ---------------------------------------------------------- */
3666
/* icmText object */
3667
 
3668
/* Return the number of bytes needed to write this tag */
3669
static unsigned int icmText_get_size(
3670
	icmBase *pp
3671
) {
3672
	icmText *p = (icmText *)pp;
3673
	unsigned int len = 0;
3674
	len += 8;			/* 8 bytes for tag and padding */
3675
	len += p->size;		/* 1 byte for each character element (inc. null) */
3676
	return len;
3677
}
3678
 
3679
/* read the object, return 0 on success, error code on fail */
3680
static int icmText_read(
3681
	icmBase *pp,
3682
	unsigned long len,		/* tag length */
3683
	unsigned long of		/* start offset within file */
3684
) {
3685
	icmText *p = (icmText *)pp;
3686
	icc *icp = p->icp;
3687
	int rv = 0;
3688
	char *bp, *buf;
3689
 
3690
	if (len < 8) {
3691
		sprintf(icp->err,"icmText_read: Tag too short to be legal");
3692
		return icp->errc = 1;
3693
	}
3694
 
3695
	/* Allocate a file read buffer */
3696
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3697
		sprintf(icp->err,"icmText_read: malloc() failed");
3698
		return icp->errc = 2;
3699
	}
3700
	bp = buf;
3701
 
3702
	/* Read portion of file into buffer */
3703
	if (   icp->fp->seek(icp->fp, of) != 0
3704
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
3705
		sprintf(icp->err,"icmText_read: fseek() or fread() failed");
3706
		icp->al->free(icp->al, buf);
3707
		return icp->errc = 1;
3708
	}
3709
	p->size = (len - 8)/1;		/* Number of elements in the array */
3710
 
3711
	/* Read type descriptor from the buffer */
3712
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
3713
		sprintf(icp->err,"icmText_read: Wrong tag type for icmText");
3714
		icp->al->free(icp->al, buf);
3715
		return icp->errc = 1;
3716
	}
3717
	bp = bp + 8;
3718
 
3719
	if (p->size > 0) {
3720
		if (check_null_string(bp,p->size) != 0) {
3721
			sprintf(icp->err,"icmText_read: text is not null terminated");
3722
			icp->al->free(icp->al, buf);
3723
			return icp->errc = 1;
3724
		}
3725
		if ((rv = p->allocate((icmBase *)p)) != 0) {
3726
			icp->al->free(icp->al, buf);
3727
			return rv;
3728
		}
3729
		memcpy((void *)p->data, (void *)bp, p->size);
3730
	}
3731
	icp->al->free(icp->al, buf);
3732
	return 0;
3733
}
3734
 
3735
/* Write the contents of the object. Return 0 on sucess, error code on failure */
3736
static int icmText_write(
3737
	icmBase *pp,
3738
	unsigned long of			/* File offset to write from */
3739
) {
3740
	icmText *p = (icmText *)pp;
3741
	icc *icp = p->icp;
3742
	unsigned int len;
3743
	char *bp, *buf;		/* Buffer to write from */
3744
	int rv = 0;
3745
 
3746
	/* Allocate a file write buffer */
3747
	len = p->get_size((icmBase *)p);
3748
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3749
		sprintf(icp->err,"icmText_write malloc() failed");
3750
		return icp->errc = 2;
3751
	}
3752
	bp = buf;
3753
 
3754
	/* Write type descriptor to the buffer */
3755
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
3756
		sprintf(icp->err,"icmText_write: write_SInt32Number() failed");
3757
		icp->al->free(icp->al, buf);
3758
		return icp->errc = rv;
3759
	}
3760
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
3761
	bp = bp + 8;
3762
 
3763
	if (p->data != NULL) {
3764
		if ((rv = check_null_string(p->data, p->size)) != 0) {
3765
			sprintf(icp->err,"icmText_write: text is not null terminated");
3766
			icp->al->free(icp->al, buf);
3767
			return icp->errc = 1;
3768
		}
3769
		memcpy((void *)bp, (void *)p->data, p->size);
3770
	}
3771
 
3772
	/* Write to the file */
3773
	if (   icp->fp->seek(icp->fp, of) != 0
3774
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
3775
		sprintf(icp->err,"icmText_write fseek() or fwrite() failed");
3776
		icp->al->free(icp->al, buf);
3777
		return icp->errc = 2;
3778
	}
3779
	icp->al->free(icp->al, buf);
3780
	return 0;
3781
}
3782
 
3783
/* Dump a text description of the object */
3784
static void icmText_dump(
3785
	icmBase *pp,
3786
	FILE *op,		/* Output to dump to */
3787
	int   verb		/* Verbosity level */
3788
) {
3789
	icmText *p = (icmText *)pp;
3790
	unsigned long i, r, c, size;
3791
 
3792
	if (verb <= 0)
3793
		return;
3794
 
3795
	fprintf(op,"Text:\n");
3796
	fprintf(op,"  No. chars = %lu\n",p->size);
3797
 
3798
	size = p->size > 0 ? p->size-1 : 0;
3799
	i = 0;
3800
	for (r = 1;; r++) {		/* count rows */
3801
		if (i >= size) {
3802
			fprintf(op,"\n");
3803
			break;
3804
		}
3805
		if (r > 1 && verb < 2) {
3806
			fprintf(op,"...\n");
3807
			break;			/* Print 1 row if not verbose */
3808
		}
3809
		c = 1;
3810
		fprintf(op,"    0x%04lx: ",i);
3811
		c += 10;
3812
		while (i < size && c < 75) {
3813
			if (isprint(p->data[i])) {
3814
				fprintf(op,"%c",p->data[i]);
3815
				c++;
3816
			} else {
3817
				fprintf(op,"\\%03o",p->data[i]);
3818
				c += 4;
3819
			}
3820
			i++;
3821
		}
3822
		if (i < size)
3823
			fprintf(op,"\n");
3824
	}
3825
}
3826
 
3827
/* Allocate variable sized data elements */
3828
static int icmText_allocate(
3829
	icmBase *pp
3830
) {
3831
	icmText *p = (icmText *)pp;
3832
	icc *icp = p->icp;
3833
 
3834
	if (p->size != p->_size) {
3835
		if (p->data != NULL)
3836
			icp->al->free(icp->al, p->data);
3837
		if ((p->data = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) {
3838
			sprintf(icp->err,"icmText_alloc: malloc() of icmText data failed");
3839
			return icp->errc = 2;
3840
		}
3841
		p->_size = p->size;
3842
	}
3843
	return 0;
3844
}
3845
 
3846
/* Free all storage in the object */
3847
static void icmText_delete(
3848
	icmBase *pp
3849
) {
3850
	icmText *p = (icmText *)pp;
3851
	icc *icp = p->icp;
3852
 
3853
	if (p->data != NULL)
3854
		icp->al->free(icp->al, p->data);
3855
	icp->al->free(icp->al, p);
3856
}
3857
 
3858
/* Create an empty object. Return null on error */
3859
static icmBase *new_icmText(
3860
	icc *icp
3861
) {
3862
	icmText *p;
3863
	if ((p = (icmText *) icp->al->calloc(icp->al,1,sizeof(icmText))) == NULL)
3864
		return NULL;
3865
	p->ttype    = icSigTextType;
3866
	p->refcount = 1;
3867
	p->get_size = icmText_get_size;
3868
	p->read     = icmText_read;
3869
	p->write    = icmText_write;
3870
	p->dump     = icmText_dump;
3871
	p->allocate = icmText_allocate;
3872
	p->del      = icmText_delete;
3873
	p->icp      = icp;
3874
 
3875
	return (icmBase *)p;
3876
}
3877
 
3878
/* ---------------------------------------------------------- */
3879
 
3880
/* Data conversion support functions */
3881
static int write_DateTimeNumber(icmDateTimeNumber *p, char *d) {
3882
	int rv;
3883
	if (p->year < 1900 || p->year > 3000
3884
	 || p->month == 0 || p->month > 12
3885
	 || p->day == 0 || p->day > 31
3886
	 || p->hours > 23
3887
	 || p->minutes > 59
3888
	 || p->seconds > 59)
3889
		return 1;
3890
 
3891
	if ((rv = write_UInt16Number(p->year,    d + 0)) != 0)
3892
		return rv;
3893
	if ((rv = write_UInt16Number(p->month,   d + 2)) != 0)
3894
		return rv;
3895
	if ((rv = write_UInt16Number(p->day,     d + 4)) != 0)
3896
		return rv;
3897
	if ((rv = write_UInt16Number(p->hours,   d + 6)) != 0)
3898
		return rv;
3899
	if ((rv = write_UInt16Number(p->minutes, d + 8)) != 0)
3900
		return rv;
3901
	if ((rv = write_UInt16Number(p->seconds, d + 10)) != 0)
3902
		return rv;
3903
	return 0;
3904
}
3905
 
3906
static int read_DateTimeNumber(icmDateTimeNumber *p, char *d) {
3907
	p->year    = read_UInt16Number(d + 0);
3908
	p->month   = read_UInt16Number(d + 2);
3909
	p->day     = read_UInt16Number(d + 4);
3910
	p->hours   = read_UInt16Number(d + 6);
3911
	p->minutes = read_UInt16Number(d + 8);
3912
	p->seconds = read_UInt16Number(d + 10);
3913
 
3914
	if (p->year < 1900 || p->year > 3000
3915
	 || p->month == 0 || p->month > 12
3916
	 || p->day == 0 || p->day > 31
3917
	 || p->hours > 23
3918
	 || p->minutes > 59
3919
	 || p->seconds > 59) {
3920
		unsigned int tt; 
3921
 
3922
		/* Check for Adobe problem */
3923
		if (p->month < 1900 || p->month > 3000
3924
		 || p->year == 0 || p->year > 12
3925
		 || p->hours == 0 || p->hours > 31
3926
		 || p->day > 23
3927
		 || p->seconds > 59
3928
		 || p->minutes > 59)
3929
			return 1;			/* Nope */
3930
 
3931
		/* Correct Adobe's faulty profile */
3932
		tt = p->month; p->month = p->year; p->year = tt;
3933
		tt = p->hours; p->hours = p->day; p->day = tt;
3934
		tt = p->seconds; p->seconds = p->minutes; p->minutes = tt;
3935
		return 0;
3936
	}
3937
	return 0;
3938
}
3939
 
3940
/* Return a string that shows the given date and time */
3941
static char *string_DateTimeNumber(icmDateTimeNumber *p) {
3942
	static const char *mstring[13] = {"Bad", "Jan","Feb","Mar","Apr","May","Jun",
3943
					  "Jul","Aug","Sep","Oct","Nov","Dec"};
3944
	static char buf[80];
3945
 
3946
	sprintf(buf,"%d %s %4d, %d:%02d:%02d", 
3947
	                p->day, mstring[p->month > 12 ? 0 : p->month], p->year,
3948
	                p->hours, p->minutes, p->seconds);
3949
	return buf;
3950
}
3951
 
3952
/* Set the DateTime structure to the current date and time */
3953
static void setcur_DateTimeNumber(icmDateTimeNumber *p) {
3954
	time_t cclk;
3955
	struct tm *ctm;
3956
 
3957
	cclk = time(NULL);
3958
	ctm = localtime(&cclk);
3959
 
3960
	p->year    = ctm->tm_year + 1900;
3961
	p->month   = ctm->tm_mon + 1;
3962
	p->day     = ctm->tm_mday;
3963
	p->hours   = ctm->tm_hour;
3964
	p->minutes = ctm->tm_min;
3965
	p->seconds = ctm->tm_sec;
3966
}
3967
 
3968
/* Return the number of bytes needed to write this tag */
3969
static unsigned int icmDateTimeNumber_get_size(
3970
	icmBase *pp
3971
) {
3972
	unsigned int len = 0;
3973
	len += 8;			/* 8 bytes for tag and padding */
3974
	len += 12;			/* 12 bytes for Date & Time */
3975
	return len;
3976
}
3977
 
3978
/* read the object, return 0 on success, error code on fail */
3979
static int icmDateTimeNumber_read(
3980
	icmBase *pp,
3981
	unsigned long len,		/* tag length */
3982
	unsigned long of		/* start offset within file */
3983
) {
3984
	icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
3985
	icc *icp = p->icp;
3986
	int rv;
3987
	char *bp, *buf;
3988
 
3989
	if (len < 20) {
3990
		sprintf(icp->err,"icmDateTimeNumber_read: Tag too small to be legal");
3991
		return icp->errc = 1;
3992
	}
3993
 
3994
	/* Allocate a file read buffer */
3995
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
3996
		sprintf(icp->err,"icmDateTimeNumber_read: malloc() failed");
3997
		return icp->errc = 2;
3998
	}
3999
	bp = buf;
4000
 
4001
	/* Read portion of file into buffer */
4002
	if (   icp->fp->seek(icp->fp, of) != 0
4003
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
4004
		sprintf(icp->err,"icmDateTimeNumber_read: fseek() or fread() failed");
4005
		icp->al->free(icp->al, buf);
4006
		return icp->errc = 1;
4007
	}
4008
 
4009
	/* Read type descriptor from the buffer */
4010
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
4011
		sprintf(icp->err,"icmDateTimeNumber_read: Wrong tag type for icmDateTimeNumber");
4012
		icp->al->free(icp->al, buf);
4013
		return icp->errc = 1;
4014
	}
4015
	bp += 8;	/* Skip padding */
4016
 
4017
	/* Read the time and date from buffer */
4018
	if((rv = read_DateTimeNumber(p, bp)) != 0) {
4019
		sprintf(icp->err,"icmDateTimeNumber_read: Corrupted DateTime");
4020
		icp->al->free(icp->al, buf);
4021
		return icp->errc = rv;
4022
	}
4023
 
4024
	icp->al->free(icp->al, buf);
4025
	return 0;
4026
}
4027
 
4028
/* Write the contents of the object. Return 0 on sucess, error code on failure */
4029
static int icmDateTimeNumber_write(
4030
	icmBase *pp,
4031
	unsigned long of			/* File offset to write from */
4032
) {
4033
	icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
4034
	icc *icp = p->icp;
4035
	unsigned int len;
4036
	char *bp, *buf;		/* Buffer to write from */
4037
	int rv = 0;
4038
 
4039
	/* Allocate a file write buffer */
4040
	len = p->get_size((icmBase *)p);
4041
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
4042
		sprintf(icp->err,"icmDateTimeNumber_write malloc() failed");
4043
		return icp->errc = 2;
4044
	}
4045
	bp = buf;
4046
 
4047
	/* Write type descriptor to the buffer */
4048
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
4049
		sprintf(icp->err,"icmDateTimeNumber_write: write_SInt32Number() failed");
4050
		icp->al->free(icp->al, buf);
4051
		return icp->errc = rv;
4052
	}
4053
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
4054
 
4055
	/* Write all the data to the buffer */
4056
	bp += 8;	/* Skip padding */
4057
	if ((rv = write_DateTimeNumber(p, bp)) != 0) {
4058
		sprintf(icp->err,"icmDateTimeNumber_write: write_DateTimeNumber() failed");
4059
		icp->al->free(icp->al, buf);
4060
		return icp->errc = rv;
4061
	}
4062
 
4063
	/* Write to the file */
4064
	if (   icp->fp->seek(icp->fp, of) != 0
4065
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
4066
		sprintf(icp->err,"icmDateTimeNumber_write fseek() or fwrite() failed");
4067
		icp->al->free(icp->al, buf);
4068
		return icp->errc = 2;
4069
	}
4070
	icp->al->free(icp->al, buf);
4071
	return 0;
4072
}
4073
 
4074
/* Dump a text description of the object */
4075
static void icmDateTimeNumber_dump(
4076
	icmBase *pp,
4077
	FILE *op,		/* Output to dump to */
4078
	int   verb		/* Verbosity level */
4079
) {
4080
	icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
4081
	if (verb <= 0)
4082
		return;
4083
 
4084
	fprintf(op,"DateTimeNumber:\n");
4085
	fprintf(op,"  Date = %s\n", string_DateTimeNumber(p));
4086
}
4087
 
4088
/* Allocate variable sized data elements */
4089
static int icmDateTimeNumber_allocate(
4090
	icmBase *pp
4091
) {
4092
	/* Nothing to do */
4093
	return 0;
4094
}
4095
 
4096
/* Free all storage in the object */
4097
static void icmDateTimeNumber_delete(
4098
	icmBase *pp
4099
) {
4100
	icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
4101
	icc *icp = p->icp;
4102
 
4103
	icp->al->free(icp->al, p);
4104
}
4105
 
4106
/* Create an empty object. Return null on error */
4107
static icmBase *new_icmDateTimeNumber(
4108
	icc *icp
4109
) {
4110
	icmDateTimeNumber *p;
4111
	if ((p = (icmDateTimeNumber *) icp->al->calloc(icp->al,1,sizeof(icmDateTimeNumber))) == NULL)
4112
		return NULL;
4113
	p->ttype    = icSigDateTimeType;
4114
	p->refcount = 1;
4115
	p->get_size = icmDateTimeNumber_get_size;
4116
	p->read     = icmDateTimeNumber_read;
4117
	p->write    = icmDateTimeNumber_write;
4118
	p->dump     = icmDateTimeNumber_dump;
4119
	p->allocate = icmDateTimeNumber_allocate;
4120
	p->del      = icmDateTimeNumber_delete;
4121
	p->icp      = icp;
4122
 
4123
	setcur_DateTimeNumber(p);	/* Default to current date and time */
4124
	return (icmBase *)p;
4125
}
4126
 
4127
/* ---------------------------------------------------------- */
4128
/* icmLut object */
4129
 
4130
/* Utility function - raise one integer to an integer power */
4131
static unsigned int uipow(unsigned int a, unsigned int b) {
4132
	unsigned int rv = 1;
4133
	for (; b > 0; b--)
4134
		rv *= a;
4135
	return rv;
4136
}
4137
 
4138
/* - - - - - - - - - - - - - - - - */
4139
/* Check if the matrix is non-zero */
4140
static int icmLut_nu_matrix(
4141
	icmLut *p		/* Pointer to Lut object */
4142
) {
4143
	int i, j;
4144
 
4145
	for (j = 0; j < 3; j++) {		/* Rows */
4146
		for (i = 0; i < 3; i++) {	/* Columns */
4147
			if (   (i == j && p->e[j][i] != 1.0)
4148
			    || (i != j && p->e[j][i] != 0.0))
4149
				return 1;
4150
		}
4151
	}
4152
	return 0;
4153
}
4154
 
4155
/* return the locations of the minimum and */
4156
/* maximum values of the given channel, in the clut */
4157
static void icmLut_min_max(
4158
	icmLut *p,		/* Pointer to Lut object */
4159
	double *minp,	/* Return position of min/max */
4160
	double *maxp,
4161
	int chan		/* Channel, -1 for average of all */
4162
) {
4163
	double *tp;
4164
	double minv, maxv;	/* Values */
4165
	int e, ee, f;
4166
	double gc[MAX_CHAN];	/* Grid coordinate */
4167
 
4168
	minv = 1e6;
4169
	maxv = -1e6;
4170
 
4171
	for (e = 0; e < p->inputChan; e++)
4172
		gc[e] = 0;	/* init coords */
4173
 
4174
	/* Search the whole table */
4175
	for (tp = p->clutTable, e = 0; e < p->inputChan; tp += p->outputChan) {
4176
		double v;
4177
		if (chan == -1) {
4178
			for (v = 0.0, f = 0; f < p->outputChan; f++)
4179
				v += tp[f];
4180
		} else {
4181
			v = tp[chan];
4182
		}
4183
		if (v < minv) {
4184
			minv = v;
4185
			for (ee = 0; ee < p->inputChan; ee++)
4186
				minp[ee] = gc[ee]/(p->clutPoints-1.0);
4187
		}
4188
		if (v > maxv) {
4189
			maxv = v;
4190
			for (ee = 0; ee < p->inputChan; ee++)
4191
				maxp[ee] = gc[ee]/(p->clutPoints-1.0);
4192
		}
4193
 
4194
		/* Increment coord */
4195
		for (e = 0; e < p->inputChan; e++) {
4196
			gc[e]++;
4197
			if (gc[e] < p->clutPoints)
4198
				break;	/* No carry */
4199
			gc[e] = 0;
4200
		}
4201
	}
4202
}
4203
 
4204
/* Convert XYZ throught Luts matrix */
4205
/* Return 0 on success, 1 if clipping occured, 2 on other error */
4206
static int icmLut_lookup_matrix(
4207
icmLut *p,		/* Pointer to Lut object */
4208
double *out,	/* Output array[outputChan] in ICC order - see Table 39 in 6.5.5 */
4209
double *in		/* Input array[inputChan] */
4210
) {
4211
	double t0,t1;	/* Take care if out == in */
4212
	t0     = p->e[0][0] * in[0] + p->e[0][1] * in[1] + p->e[0][2] * in[2];
4213
	t1     = p->e[1][0] * in[0] + p->e[1][1] * in[1] + p->e[1][2] * in[2];
4214
	out[2] = p->e[2][0] * in[0] + p->e[2][1] * in[1] + p->e[2][2] * in[2];
4215
	out[0] = t0;
4216
	out[1] = t1;
4217
 
4218
	return 0;
4219
}
4220
 
4221
/* Convert normalized numbers though this Luts input tables. */
4222
/* Return 0 on success, 1 if clipping occured, 2 on other error */
4223
static int icmLut_lookup_input(
4224
icmLut *p,		/* Pointer to Lut object */
4225
double *out,	/* Output array[inputChan] */
4226
double *in		/* Input array[inputChan] */
4227
) {
4228
	int rv = 0;
4229
	int ix,n;
4230
	double inputEnt_1 = (double)(p->inputEnt-1);
4231
	double *table = p->inputTable;
4232
 
4233
	/* Use linear interpolation */
4234
	for (n = 0; n < p->inputChan; n++, table += p->inputEnt) {
4235
		double val, w;
4236
		val = in[n] * inputEnt_1;
4237
		if (val < 0.0) {
4238
			val = 0.0;
4239
			rv |= 1;
4240
		} else if (val > inputEnt_1) {
4241
			val = inputEnt_1;
4242
			rv |= 1;
4243
		}
4244
		ix = (int)floor(val);		/* Grid coordinate */
4245
		if (ix > (p->inputEnt-2))
4246
			ix = (p->inputEnt-2);
4247
		w = val - (double)ix;		/* weight */
4248
		val = table[ix];
4249
		out[n] = val + w * (table[ix+1] - val);
4250
	}
4251
	return rv;
4252
}
4253
 
4254
/* Convert normalized numbers though this Luts multi-dimensional table. */
4255
/* using n-linear interpolation. */
4256
static int icmLut_lookup_clut_nl(
4257
/* Return 0 on success, 1 if clipping occured, 2 on other error */
4258
icmLut *p,		/* Pointer to Lut object */
4259
double *out,	/* Output array[inputChan] */
4260
double *in		/* Input array[outputChan] */
4261
) {
4262
	icc *icp = p->icp;
4263
	int rv = 0;
4264
	double *gp;					/* Pointer to grid cube base */
4265
	double co[MAX_CHAN];		/* Coordinate offset with the grid cell */
4266
	double *gw, GW[1 << 8];		/* weight for each grid cube corner */
4267
 
4268
	if (p->inputChan <= 8) {
4269
		gw = GW;				/* Use stack allocation */
4270
	} else {
4271
		if ((gw = (double *) icp->al->malloc(icp->al, (1 << p->inputChan) * sizeof(double))) == NULL) {
4272
			sprintf(icp->err,"icmLut_lookup_clut: malloc() failed");
4273
			return icp->errc = 2;
4274
		}
4275
	}
4276
 
4277
	/* We are using an n-linear (ie. Trilinear for 3D input) interpolation. */
4278
	/* The implementation here uses more multiplies that some other schemes, */
4279
	/* (for instance, see "Tri-Linear Interpolation" by Steve Hill, */
4280
	/* Graphics Gems IV, page 521), but has less involved bookeeping, */
4281
	/* needs less local storage for intermediate output values, does fewer */
4282
	/* output and intermediate value reads, and fp multiplies are fast on */
4283
	/* todays processors! */
4284
 
4285
	/* Compute base index into grid and coordinate offsets */
4286
	{
4287
		int e;
4288
		double clutPoints_1 = (double)(p->clutPoints-1);
4289
		int    clutPoints_2 = p->clutPoints-2;
4290
		gp = p->clutTable;		/* Base of grid array */
4291
 
4292
		for (e = 0; e < p->inputChan; e++) {
4293
			int x;
4294
			double val;
4295
			val = in[e] * clutPoints_1;
4296
			if (val < 0.0) {
4297
				val = 0.0;
4298
				rv |= 1;
4299
			} else if (val > clutPoints_1) {
4300
				val = clutPoints_1;
4301
				rv |= 1;
4302
			}
4303
			x = (int)floor(val);		/* Grid coordinate */
4304
			if (x > clutPoints_2)
4305
				x = clutPoints_2;
4306
			co[e] = val - (double)x;	/* 1.0 - weight */
4307
			gp += x * p->dinc[e];		/* Add index offset for base of cube */
4308
		}
4309
	}
4310
	/* Compute corner weights needed for interpolation */
4311
	{
4312
		int e, i, g = 1;
4313
		gw[0] = 1.0;
4314
		for (e = 0; e < p->inputChan; e++) {
4315
			for (i = 0; i < g; i++) {
4316
				gw[g+i] = gw[i] * co[e];
4317
				gw[i] *= (1.0 - co[e]);
4318
			}
4319
			g *= 2;
4320
		}
4321
	}
4322
	/* Now compute the output values */
4323
	{
4324
		int i, f;
4325
		double w = gw[0];
4326
		double *d = gp + p->dcube[0];
4327
		for (f = 0; f < p->outputChan; f++)			/* Base of cube */
4328
			out[f] = w * d[f];
4329
		for (i = 1; i < (1 << p->inputChan); i++) {	/* For all other corners of cube */
4330
			w = gw[i];				/* Strength reduce */
4331
			d = gp + p->dcube[i];
4332
			for (f = 0; f < p->outputChan; f++) {
4333
				out[f] += w * d[f];
4334
			}
4335
		}
4336
	}
4337
	if (gw != GW)
4338
		icp->al->free(icp->al, (void *)gw);
4339
	return rv;
4340
}
4341
 
4342
/* Convert normalized numbers though this Luts multi-dimensional table */
4343
/* using simplex interpolation. */
4344
static int icmLut_lookup_clut_sx(
4345
/* Return 0 on success, 1 if clipping occured, 2 on other error */
4346
icmLut *p,		/* Pointer to Lut object */
4347
double *out,	/* Output array[inputChan] */
4348
double *in		/* Input array[outputChan] */
4349
) {
4350
	int rv = 0;
4351
	double *gp;					/* Pointer to grid cube base */
4352
	double co[MAX_CHAN];		/* Coordinate offset with the grid cell */
4353
	int    si[MAX_CHAN];		/* co[] Sort index, [0] = smalest */
4354
 
4355
	/* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */
4356
	/* This method is more appropriate for XYZ/RGB/CMYK input spaces, */
4357
 
4358
	/* Compute base index into grid and coordinate offsets */
4359
	{
4360
		int e;
4361
		double clutPoints_1 = (double)(p->clutPoints-1);
4362
		int    clutPoints_2 = p->clutPoints-2;
4363
		gp = p->clutTable;		/* Base of grid array */
4364
 
4365
		for (e = 0; e < p->inputChan; e++) {
4366
			int x;
4367
			double val;
4368
			val = in[e] * clutPoints_1;
4369
			if (val < 0.0) {
4370
				val = 0.0;
4371
				rv |= 1;
4372
			} else if (val > clutPoints_1) {
4373
				val = clutPoints_1;
4374
				rv |= 1;
4375
			}
4376
			x = (int)floor(val);		/* Grid coordinate */
4377
			if (x > clutPoints_2)
4378
				x = clutPoints_2;
4379
			co[e] = val - (double)x;	/* 1.0 - weight */
4380
			gp += x * p->dinc[e];		/* Add index offset for base of cube */
4381
		}
4382
	}
4383
	/* Do selection sort on coordinates */
4384
	{
4385
		int e, f;
4386
		for (e = 0; e < p->inputChan; e++)
4387
			si[e] = e;						/* Initial unsorted indexes */
4388
		for (e = 0; e < (p->inputChan-1); e++) {
4389
			double cosn;
4390
			cosn = co[si[e]];				/* Current smallest value */
4391
			for (f = e+1; f < p->inputChan; f++) {	/* Check against rest */
4392
				int tt;
4393
				tt = si[f];
4394
				if (cosn > co[tt]) {
4395
					si[f] = si[e]; 			/* Exchange */
4396
					si[e] = tt;
4397
					cosn = co[tt];
4398
				}
4399
			}
4400
		}
4401
	}
4402
	/* Now compute the weightings, simplex vertices and output values */
4403
	{
4404
		int e, f;
4405
		double w;		/* Current vertex weight */
4406
 
4407
		w = 1.0 - co[si[p->inputChan-1]];		/* Vertex at base of cell */
4408
		for (f = 0; f < p->outputChan; f++)
4409
			out[f] = w * gp[f];
4410
 
4411
		for (e = p->inputChan-1; e > 0; e--) {	/* Middle verticies */
4412
			w = co[si[e]] - co[si[e-1]];
4413
			gp += p->dinc[si[e]];				/* Move to top of cell in next largest dimension */
4414
			for (f = 0; f < p->outputChan; f++)
4415
				out[f] += w * gp[f];
4416
		}
4417
 
4418
		w = co[si[0]];
4419
		gp += p->dinc[si[0]];		/* Far corner from base of cell */
4420
		for (f = 0; f < p->outputChan; f++)
4421
			out[f] += w * gp[f];
4422
	}
4423
	return rv;
4424
}
4425
 
4426
/* Convert normalized numbers though this Luts output tables. */
4427
/* Return 0 on success, 1 if clipping occured, 2 on other error */
4428
static int icmLut_lookup_output(
4429
icmLut *p,		/* Pointer to Lut object */
4430
double *out,	/* Output array[outputChan] */
4431
double *in		/* Input array[outputChan] */
4432
) {
4433
	int rv = 0;
4434
	int ix,n;
4435
	double outputEnt_1 = (double)(p->outputEnt-1);
4436
	double *table = p->outputTable;
4437
 
4438
	/* Use linear interpolation */
4439
	for (n = 0; n < p->outputChan; n++, table += p->outputEnt) {
4440
		double val, w;
4441
		val = in[n] * outputEnt_1;
4442
		if (val < 0.0) {
4443
			val = 0.0;
4444
			rv |= 1;
4445
		} else if (val > outputEnt_1) {
4446
			val = outputEnt_1;
4447
			rv |= 1;
4448
		}
4449
		ix = (int)floor(val);		/* Grid coordinate */
4450
		if (ix > (p->outputEnt-2))
4451
			ix = (p->outputEnt-2);
4452
		w = val - (double)ix;		/* weight */
4453
		val = table[ix];
4454
		out[n] = val + w * (table[ix+1] - val);
4455
	}
4456
	return rv;
4457
}
4458
 
4459
/* ----------------------------------------------- */
4460
/* Pseudo - Hilbert count sequencer */
4461
 
4462
/* This multi-dimensional count sequence is a distributed */
4463
/* Gray code sequence, with direction reversal on every */
4464
/* alternate power of 2 scale. */
4465
/* It is intended to aid cache coherence in multi-dimensional */
4466
/* regular sampling. It approximates the Hilbert curve sequence. */
4467
 
4468
/* Initialise, returns total usable count */
4469
unsigned
4470
psh_init(
4471
psh *p,	/* Pointer to structure to initialise */
4472
int      di,	/* Dimensionality */
4473
unsigned res,	/* Size per coordinate */
4474
int co[]		/* Coordinates to initialise (May be NULL) */
4475
) {
4476
	int e;
4477
 
4478
	p->di = di;
4479
	p->res = res;
4480
 
4481
	/* Compute bits */
4482
	for (p->bits = 0; (1 << p->bits) < res; p->bits++)
4483
		;
4484
 
4485
	/* Compute the total count mask */
4486
	p->tmask = ((((unsigned)1) << (p->bits * di))-1);
4487
 
4488
	/* Compute usable count */
4489
	p->count = 1;
4490
	for (e = 0; e < di; e++)
4491
		p->count *= res;
4492
 
4493
	p->ix = 0;
4494
 
4495
	if (co != NULL) {
4496
		for (e = 0; e < di; e++)
4497
			co[e] = 0;
4498
	}
4499
 
4500
	return p->count;
4501
}
4502
 
4503
/* Reset the counter */
4504
void
4505
psh_reset(
4506
psh *p	/* Pointer to structure */
4507
) {
4508
	p->ix = 0;
4509
}
4510
 
4511
/* Increment pseudo-hilbert coordinates */
4512
/* Return non-zero if count rolls over to 0 */
4513
int
4514
psh_inc(
4515
psh *p,	/* Pointer to structure */
4516
int co[]		/* Coordinates to return */
4517
) {
4518
	int di = p->di;
4519
	int res = p->res;
4520
	int bits = p->bits;
4521
	int e;
4522
 
4523
	do {
4524
		int b;
4525
		int gix;	/* Gray code index */
4526
 
4527
		p->ix = (p->ix + 1) & p->tmask;
4528
 
4529
		gix = p->ix ^ (p->ix >> 1);		/* Convert to gray code index */
4530
 
4531
		for (e = 0; e < di; e++) 
4532
			co[e] = 0;
4533
 
4534
		for (b = 0; b < bits; b++) {	/* Distribute bits */
4535
			if (b & 1) {
4536
				for (e = di-1; e >= 0; e--)  {		/* In reverse order */
4537
					co[e] |= (gix & 1) << b;
4538
					gix >>= 1;
4539
				}
4540
			} else {
4541
				for (e = 0; e < di; e++)  {			/* In normal order */
4542
					co[e] |= (gix & 1) << b;
4543
					gix >>= 1;
4544
				}
4545
			}
4546
		}
4547
 
4548
		/* Convert from Gray to binary coordinates */
4549
		for (e = 0; e < di; e++)  {
4550
			unsigned sh, tv;
4551
 
4552
			for(sh = 1, tv = co[e];; sh <<= 1) {
4553
				unsigned ptv = tv;
4554
				tv ^= (tv >> sh);
4555
				if (ptv <= 1 || sh == 16)
4556
					break;
4557
			}
4558
			if (tv >= res)	/* Dumbo filter - increment again if outside cube range */
4559
				break;
4560
			co[e] = tv;
4561
		}
4562
 
4563
	} while (e < di);
4564
 
4565
	return (p->ix == 0);
4566
}
4567
 
4568
/* ------------------------------------------------------- */
4569
/* Parameter to getNormFunc function */
4570
typedef enum {
4571
    icmFromLuti   = 0,  /* return "fromo Lut normalized index" conversion function */
4572
    icmToLuti     = 1,  /* return "to Lut normalized index" conversion function */
4573
    icmFromLutv   = 2,  /* return "from Lut normalized value" conversion function */
4574
    icmToLutv     = 3   /* return "to Lut normalized value" conversion function */
4575
} icmNormFlag;
4576
 
4577
/* Return an appropriate color space normalization function, */
4578
/* given the color space and Lut type */
4579
/* Return 0 on success, 1 on match failure */
4580
static int getNormFunc(
4581
	icColorSpaceSignature csig, 
4582
	icTagTypeSignature    tagSig,
4583
	icmNormFlag           flag,
4584
	void               (**nfunc)(double *out, double *in)
4585
);
4586
 
4587
/* Helper function to initialize the three tables contents */
4588
/* from supplied transfer functions. */
4589
/* Set errc and return error number */
4590
static int icmLut_set_tables (
4591
icmLut *p,									/* Pointer to Lut object */
4592
void   *cbctx,								/* Opaque callback context pointer value */
4593
icColorSpaceSignature insig, 				/* Input color space */
4594
icColorSpaceSignature outsig, 				/* Output color space */
4595
void (*infunc)(void *cbcntx, double *out, double *in),
4596
								/* Input transfer function, inspace->inspace' (NULL = default) */
4597
double *inmin, double *inmax,				/* Maximum range of inspace' values (NULL = default) */
4598
void (*clutfunc)(void *cbctx, double *out, double *in),
4599
								/* inspace' -> outspace' transfer function */
4600
double *clutmin, double *clutmax,			/* Maximum range of outspace' values (NULL = default) */
4601
void (*outfunc)(void *cbctx, double *out, double *in)
4602
								/* Output transfer function, outspace'->outspace (NULL = deflt) */
4603
) {
4604
	icc *icp = p->icp;
4605
	int n, e;
4606
	int ii[MAX_CHAN];		/* Index value */
4607
	psh counter;			/* Pseudo-Hilbert counter */
4608
	double _iv[2 * MAX_CHAN], *iv = &_iv[MAX_CHAN];	/* Real index value/table value */
4609
	double imin[MAX_CHAN], imax[MAX_CHAN];
4610
	double omin[MAX_CHAN], omax[MAX_CHAN];
4611
	void (*ifromindex)(double *out, double *in);	/* Index to input color space function */
4612
	void (*itoentry)(double *out, double *in);		/* Input color space to entry function */
4613
	void (*ifromentry)(double *out, double *in);	/* Entry to input color space function */
4614
	void (*otoentry)(double *out, double *in);		/* Output colorspace to table value function */
4615
	void (*ofromentry)(double *out, double *in);	/* Table value to output color space function */
4616
 
4617
	if (getNormFunc(insig, p->ttype, icmFromLuti, &ifromindex) != 0) {
4618
		sprintf(icp->err,"icmLut_set_tables index to input colorspace function lookup failed");
4619
		return icp->errc = 1;
4620
	}
4621
	if (getNormFunc(insig, p->ttype, icmToLutv, &itoentry) != 0) {
4622
		sprintf(icp->err,"icmLut_set_tables input colorspace to table entry function lookup failed");
4623
		return icp->errc = 1;
4624
	}
4625
	if (getNormFunc(insig, p->ttype, icmFromLutv, &ifromentry) != 0) {
4626
		sprintf(icp->err,"icmLut_set_tables table entry to input colorspace function lookup failed");
4627
		return icp->errc = 1;
4628
	}
4629
 
4630
	if (getNormFunc(outsig, p->ttype, icmToLutv, &otoentry) != 0) {
4631
		sprintf(icp->err,"icmLut_set_tables output colorspace to table entry function lookup failed");
4632
		return icp->errc = 1;
4633
	}
4634
	if (getNormFunc(outsig, p->ttype, icmFromLutv, &ofromentry) != 0) {
4635
		sprintf(icp->err,"icmLut_set_tables table entry to output colorspace function lookup failed");
4636
		return icp->errc = 1;
4637
	}
4638
 
4639
	/* Setup input table value min-max */
4640
	if (inmin == NULL) {
4641
#ifdef SYMETRICAL_DEFAULT_LAB_RANGE	/* Try symetrical range */
4642
		if (insig == icSigLabData) { /* Special case Lab */
4643
			double mn[3], mx[3];
4644
			/* Because the symetric range will cause slight clipping, */
4645
			/* only do it if the input table has sufficient resolution */
4646
			/* to represent the clipping faithfuly. */
4647
			if (p->inputEnt >= 64) {
4648
				mn[0] =   0.0, mn[1] = -127.0, mn[2] = -127.0;
4649
				mx[0] = 100.0, mx[1] =  127.0, mx[2] =  127.0;
4650
				itoentry(imin, mn);	/* Convert from input color space to table representation */
4651
				itoentry(imax, mx);
4652
			} else {
4653
				for (e = 0; e < p->inputChan; e++) {
4654
					imin[e] = 0.0;
4655
					imax[e] = 1.0;
4656
				}
4657
			}
4658
		} else
4659
#endif
4660
		{
4661
			for (e = 0; e < p->inputChan; e++) {
4662
				imin[e] = 0.0;		/* We are assuming this is true for all other color spaces. */
4663
				imax[e] = 1.0;
4664
			}
4665
		}
4666
	} else {
4667
		itoentry(imin, inmin);	/* Convert from input color space to table representation */
4668
		itoentry(imax, inmax);
4669
	}
4670
 
4671
	/* Setup output table value min-max */
4672
	if (clutmin == NULL) {
4673
#ifdef SYMETRICAL_DEFAULT_LAB_RANGE	/* Try symetrical range */
4674
		if (outsig == icSigLabData) { /* Special case Lab */
4675
			double mn[3], mx[3];
4676
			/* Because the symetric range will cause slight clipping, */
4677
			/* only do it if the output table has sufficient resolution */
4678
			/* to represent the clipping faithfuly. */
4679
			if (p->outputEnt >= 64) {
4680
				mn[0] =   0.0, mn[1] = -127.0, mn[2] = -127.0;
4681
				mx[0] = 100.0, mx[1] =  127.0, mx[2] =  127.0;
4682
				otoentry(omin, mn);/* Convert from output color space to table representation */
4683
				otoentry(omax, mx);
4684
			} else {
4685
				for (e = 0; e < p->inputChan; e++) {
4686
					omin[e] = 0.0;
4687
					omax[e] = 1.0;
4688
				}
4689
			}
4690
		} else
4691
#endif
4692
		{
4693
			for (e = 0; e < p->outputChan; e++) {
4694
				omin[e] = 0.0;		/* We are assuming this is true for all other color spaces. */
4695
				omax[e] = 1.0;
4696
			}
4697
		}
4698
	} else {
4699
		otoentry(omin, clutmin);/* Convert from output color space to table representation */
4700
		otoentry(omax, clutmax);
4701
	}
4702
 
4703
	/* Create the input table entry values */
4704
	for (n = 0; n < p->inputEnt; n++) {
4705
		double fv;
4706
		fv = n/(p->inputEnt-1.0);
4707
		for (e = 0; e < p->inputChan; e++)
4708
			iv[e] = fv;
4709
 
4710
		ifromindex(iv,iv);			/* Convert from index value to input color space value */
4711
 
4712
		if (infunc != NULL)
4713
			infunc(cbctx, iv, iv);	/* In colorspace -> input table -> In colorspace. */
4714
 
4715
		itoentry(iv,iv);			/* Convert from input color space value to table value */
4716
 
4717
		/* Expand used range to 0.0 - 1.0, and clip to legal values */
4718
		/* Note that if the range is reduced, and clipping occurs, */
4719
		/* then there should be enough resolution within the input */
4720
		/* table, to represent the sharp edges of the clipping. */
4721
		for (e = 0; e < p->inputChan; e++) {
4722
			double tt;
4723
			tt = (iv[e] - imin[e])/(imax[e] - imin[e]);
4724
			if (tt < 0.0)
4725
				tt = 0.0;
4726
			else if (tt > 1.0)
4727
				tt = 1.0;
4728
			iv[e] = tt;
4729
		}
4730
 
4731
		for (e = 0; e < p->inputChan; e++) 		/* Input tables */
4732
			p->inputTable[e * p->inputEnt + n] = iv[e];
4733
	}
4734
 
4735
	/* Create the multi-dimensional lookup table values */
4736
 
4737
	/* To make this clut function cache friendly, we use the pseudo-hilbert */
4738
	/* count sequence. This keeps each point close to the last in the */
4739
	/* multi-dimensional space. */ 
4740
 
4741
	psh_init(&counter, p->inputChan, p->clutPoints, ii);	/* Initialise counter */
4742
 
4743
	/* Itterate through all verticies in the grid */
4744
	for (;;) {
4745
		int ti;			/* Table index */
4746
 
4747
		for (ti = e = 0; e < p->inputChan; e++) { 	/* Input tables */
4748
			ti += ii[e] * p->dinc[e];				/* Clut index */
4749
			iv[e] = ii[e]/(p->clutPoints-1.0);		/* Vertex coordinates */
4750
			iv[e] = iv[e] * (imax[e] - imin[e]) + imin[e]; /* Undo expansion to 0.0 - 1.0 */
4751
			*((int *)&iv[-e-1]) = ii[e];			/* Trick to supply grid index in iv[] */
4752
		}
4753
 
4754
		ifromentry(iv,iv);			/* Convert from table value to input color space */
4755
 
4756
		/* Apply incolor -> outcolor function we want to represent */
4757
		clutfunc(cbctx, iv, iv);
4758
 
4759
		otoentry(iv,iv);			/* Convert from output color space value to table value */
4760
 
4761
		/* Expand used range to 0.0 - 1.0, and clip to legal values */
4762
		for (e = 0; e < p->outputChan; e++) {
4763
			double tt;
4764
			tt = (iv[e] - omin[e])/(omax[e] - omin[e]);
4765
			if (tt < 0.0)
4766
				tt = 0.0;
4767
			else if (tt > 1.0)
4768
				tt = 1.0;
4769
			iv[e] = tt;
4770
		}
4771
 
4772
		for (e = 0; e < p->outputChan; e++) 	/* Output chans */
4773
			p->clutTable[ti++] = iv[e];
4774
 
4775
		/* Increment index within block (Reverse index significancd) */
4776
		if (psh_inc(&counter, ii))
4777
			break;
4778
	}
4779
 
4780
	/* Create the output table entry values */
4781
	for (n = 0; n < p->outputEnt; n++) {
4782
		double fv;
4783
		fv = n/(p->outputEnt-1.0);
4784
		for (e = 0; e < p->outputChan; e++)
4785
			iv[e] = fv;
4786
 
4787
		/* Undo expansion to 0.0 - 1.0 */
4788
		for (e = 0; e < p->outputChan; e++) 		/* Output tables */
4789
			iv[e] = iv[e] * (omax[e] - omin[e]) + omin[e];
4790
 
4791
		ofromentry(iv,iv);			/* Convert from table value to output color space value */
4792
 
4793
		if (outfunc != NULL)
4794
			outfunc(cbctx, iv, iv);	/* Out colorspace -> output table -> out colorspace. */
4795
 
4796
		otoentry(iv,iv);			/* Convert from output color space value to table value */
4797
 
4798
		/* Clip to legal values */
4799
		for (e = 0; e < p->outputChan; e++) {
4800
			double tt;
4801
			tt = iv[e];
4802
			if (tt < 0.0)
4803
				tt = 0.0;
4804
			else if (tt > 1.0)
4805
				tt = 1.0;
4806
			iv[e] = tt;
4807
		}
4808
 
4809
		for (e = 0; e < p->outputChan; e++) 		/* Input tables */
4810
			p->outputTable[e * p->outputEnt + n] = iv[e];
4811
	}
4812
	return 0;
4813
}
4814
 
4815
/* - - - - - - - - - - - - - - - - */
4816
/* Return the number of bytes needed to write this tag */
4817
static unsigned int icmLut_get_size(
4818
	icmBase *pp
4819
) {
4820
	icmLut *p = (icmLut *)pp;
4821
	unsigned int len = 0;
4822
 
4823
	if (p->ttype == icSigLut8Type) {
4824
		len += 48;			/* tag and header */
4825
		len += 1 * (p->inputChan * p->inputEnt);
4826
		len += 1 * (p->outputChan * uipow(p->clutPoints,p->inputChan));
4827
		len += 1 * (p->outputChan * p->outputEnt);
4828
	} else {
4829
		len += 52;			/* tag and header */
4830
		len += 2 * (p->inputChan * p->inputEnt);
4831
		len += 2 * (p->outputChan * uipow(p->clutPoints,p->inputChan));
4832
		len += 2 * (p->outputChan * p->outputEnt);
4833
	}
4834
	return len;
4835
}
4836
 
4837
/* read the object, return 0 on success, error code on fail */
4838
static int icmLut_read(
4839
	icmBase *pp,
4840
	unsigned long len,		/* tag length */
4841
	unsigned long of		/* start offset within file */
4842
) {
4843
	icmLut *p = (icmLut *)pp;
4844
	icc *icp = p->icp;
4845
	int rv = 0;
4846
	unsigned long i, j, g, size;
4847
	char *bp, *buf;
4848
 
4849
	if (len < 4) {
4850
		sprintf(icp->err,"icmLut_read: Tag too small to be legal");
4851
		return icp->errc = 1;
4852
	}
4853
 
4854
	/* Allocate a file read buffer */
4855
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
4856
		sprintf(icp->err,"icmLut_read: malloc() failed");
4857
		return icp->errc = 2;
4858
	}
4859
	bp = buf;
4860
 
4861
	/* Read portion of file into buffer */
4862
	if (   icp->fp->seek(icp->fp, of) != 0
4863
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
4864
		sprintf(icp->err,"icmLut_read: fseek() or fread() failed");
4865
		icp->al->free(icp->al, buf);
4866
		return icp->errc = 1;
4867
	}
4868
 
4869
	/* Read type descriptor from the buffer */
4870
	p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
4871
	if (p->ttype != icSigLut8Type && p->ttype != icSigLut16Type) {
4872
		sprintf(icp->err,"icmLut_read: Wrong tag type for icmLut");
4873
		icp->al->free(icp->al, buf);
4874
		return icp->errc = 1;
4875
	}
4876
 
4877
	if (p->ttype == icSigLut8Type) {
4878
		if (len < 48) {
4879
			sprintf(icp->err,"icmLut_read: Tag too small to be legal");
4880
			icp->al->free(icp->al, buf);
4881
			return icp->errc = 1;
4882
		}
4883
	} else {
4884
		if (len < 52) {
4885
			sprintf(icp->err,"icmLut_read: Tag too small to be legal");
4886
			icp->al->free(icp->al, buf);
4887
			return icp->errc = 1;
4888
		}
4889
	}
4890
 
4891
	/* Read in the info common to 8 and 16 bit Lut */
4892
	p->inputChan = read_UInt8Number(bp+8);
4893
	p->outputChan = read_UInt8Number(bp+9);
4894
	p->clutPoints = read_UInt8Number(bp+10);
4895
 
4896
	/* Sanity check */
4897
	if (p->inputChan > MAX_CHAN) {
4898
		sprintf(icp->err,"icmLut_read: Can't handle > %d input channels\n",MAX_CHAN);
4899
		return icp->errc = 1;
4900
	}
4901
 
4902
	if (p->outputChan > MAX_CHAN) {
4903
		sprintf(icp->err,"icmLut_read: Can't handle > %d output channels\n",MAX_CHAN);
4904
		return icp->errc = 1;
4905
	}
4906
 
4907
	/* Read 3x3 transform matrix */
4908
	for (j = 0; j < 3; j++) {		/* Rows */
4909
		for (i = 0; i < 3; i++) {	/* Columns */
4910
			p->e[j][i] = read_S15Fixed16Number(bp + 12 + ((j * 3 + i) * 4));
4911
		}
4912
	}
4913
	/* Read 16 bit specific stuff */
4914
	if (p->ttype == icSigLut8Type) {
4915
		p->inputEnt  = 256;	/* By definition */
4916
		p->outputEnt = 256;	/* By definition */
4917
		bp = buf+48;
4918
	} else {
4919
		p->inputEnt  = read_UInt16Number(bp+48);
4920
		p->outputEnt = read_UInt16Number(bp+50);
4921
		bp = buf+52;
4922
	}
4923
 
4924
	if (len < icmLut_get_size((icmBase *)p)) {
4925
		sprintf(icp->err,"icmLut_read: Tag too small for contents");
4926
		icp->al->free(icp->al, buf);
4927
		return icp->errc = 1;
4928
	}
4929
 
4930
	/* Read the input tables */
4931
	size = (p->inputChan * p->inputEnt);
4932
	if ((rv = p->allocate((icmBase *)p)) != 0) {
4933
		icp->al->free(icp->al, buf);
4934
		return rv;
4935
	}
4936
	if (p->ttype == icSigLut8Type) {
4937
		for (i = 0; i < size; i++, bp += 1)
4938
			p->inputTable[i] = read_DCS8Number(bp);
4939
	} else {
4940
		for (i = 0; i < size; i++, bp += 2)
4941
			p->inputTable[i] = read_DCS16Number(bp);
4942
	}
4943
 
4944
	/* Read the clut table */
4945
	size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
4946
	if ((rv = p->allocate((icmBase *)p)) != 0) {
4947
		icp->al->free(icp->al, buf);
4948
		return rv;
4949
	}
4950
	if (p->ttype == icSigLut8Type) {
4951
		for (i = 0; i < size; i++, bp += 1)
4952
			p->clutTable[i] = read_DCS8Number(bp);
4953
	} else {
4954
		for (i = 0; i < size; i++, bp += 2)
4955
			p->clutTable[i] = read_DCS16Number(bp);
4956
	}
4957
 
4958
	/* Read the output tables */
4959
	size = (p->outputChan * p->outputEnt);
4960
	if ((rv = p->allocate((icmBase *)p)) != 0) {
4961
		icp->al->free(icp->al, buf);
4962
		return rv;
4963
	}
4964
	if (p->ttype == icSigLut8Type) {
4965
		for (i = 0; i < size; i++, bp += 1)
4966
			p->outputTable[i] = read_DCS8Number(bp);
4967
	} else {
4968
		for (i = 0; i < size; i++, bp += 2)
4969
			p->outputTable[i] = read_DCS16Number(bp);
4970
	}
4971
 
4972
	/* Private: compute dimensional increment though clut */
4973
	/* Note that first channel varies least rapidly. */
4974
	i = p->inputChan-1;
4975
	p->dinc[i--] = p->outputChan;
4976
	for (; i < p->inputChan; i--)
4977
		p->dinc[i] = p->dinc[i+1] * p->clutPoints;
4978
 
4979
	/* Private: compute offsets from base of cube to other corners */
4980
	for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
4981
		for (i = 0; i < g; i++)
4982
			p->dcube[g+i] = p->dcube[i] + p->dinc[j];
4983
		g *= 2;
4984
	}
4985
 
4986
	icp->al->free(icp->al, buf);
4987
	return 0;
4988
}
4989
 
4990
/* Write the contents of the object. Return 0 on sucess, error code on failure */
4991
static int icmLut_write(
4992
	icmBase *pp,
4993
	unsigned long of			/* File offset to write from */
4994
) {
4995
	icmLut *p = (icmLut *)pp;
4996
	icc *icp = p->icp;
4997
	unsigned long i,j;
4998
	unsigned int len, size;
4999
	char *bp, *buf;		/* Buffer to write from */
5000
	int rv = 0;
5001
 
5002
	/* Allocate a file write buffer */
5003
	len = p->get_size((icmBase *)p);
5004
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5005
		sprintf(icp->err,"icmLut_write malloc() failed");
5006
		return icp->errc = 2;
5007
	}
5008
	bp = buf;
5009
 
5010
	/* Write type descriptor to the buffer */
5011
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
5012
		sprintf(icp->err,"icmLut_write: write_SInt32Number() failed");
5013
		icp->al->free(icp->al, buf);
5014
		return icp->errc = rv;
5015
	}
5016
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
5017
 
5018
	/* Write the info common to 8 and 16 bit Lut */
5019
	if ((rv = write_UInt8Number(p->inputChan, bp+8)) != 0) {
5020
		sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
5021
		icp->al->free(icp->al, buf);
5022
		return icp->errc = rv;
5023
	}
5024
	if ((rv = write_UInt8Number(p->outputChan, bp+9)) != 0) {
5025
		sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
5026
		icp->al->free(icp->al, buf);
5027
		return icp->errc = rv;
5028
	}
5029
	if ((rv = write_UInt8Number(p->clutPoints, bp+10)) != 0) {
5030
		sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
5031
		icp->al->free(icp->al, buf);
5032
		return icp->errc = rv;
5033
	}
5034
 
5035
	/* Write 3x3 transform matrix */
5036
	for (j = 0; j < 3; j++) {		/* Rows */
5037
		for (i = 0; i < 3; i++) {	/* Columns */
5038
			if ((rv = write_S15Fixed16Number(p->e[j][i],bp + 12 + ((j * 3 + i) * 4))) != 0) {
5039
				sprintf(icp->err,"icmLut_write: write_S15Fixed16Number() failed");
5040
				icp->al->free(icp->al, buf);
5041
				return icp->errc = rv;
5042
			}
5043
		}
5044
	}
5045
 
5046
	/* Write 16 bit specific stuff */
5047
	if (p->ttype == icSigLut8Type) {
5048
		if (p->inputEnt != 256 || p->outputEnt != 256) {
5049
			sprintf(icp->err,"icmLut_write: 8 bit Input and Output tables must be 256 entries");
5050
			icp->al->free(icp->al, buf);
5051
			return icp->errc = 1;
5052
		}
5053
		bp = buf+48;
5054
	} else {
5055
		if ((rv = write_UInt16Number(p->inputEnt, bp+48)) != 0) {
5056
			sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
5057
			icp->al->free(icp->al, buf);
5058
			return icp->errc = rv;
5059
		}
5060
		if ((rv = write_UInt16Number(p->outputEnt, bp+50)) != 0) {
5061
			sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
5062
			icp->al->free(icp->al, buf);
5063
			return icp->errc = rv;
5064
		}
5065
		bp = buf+52;
5066
	}
5067
 
5068
	/* Write the input tables */
5069
	size = (p->inputChan * p->inputEnt);
5070
	if (p->ttype == icSigLut8Type) {
5071
		for (i = 0; i < size; i++, bp += 1) {
5072
			if ((rv = write_DCS8Number(p->inputTable[i], bp)) != 0) {
5073
				sprintf(icp->err,"icmLut_write: inputTable write_DCS8Number() failed");
5074
				icp->al->free(icp->al, buf);
5075
				return icp->errc = rv;
5076
			}
5077
		}
5078
	} else {
5079
		for (i = 0; i < size; i++, bp += 2) {
5080
			if ((rv = write_DCS16Number(p->inputTable[i], bp)) != 0) {
5081
				sprintf(icp->err,"icmLut_write: inputTable write_DCS16Number(%f) failed",p->inputTable[i]);
5082
				icp->al->free(icp->al, buf);
5083
				return icp->errc = rv;
5084
			}
5085
		}
5086
	}
5087
 
5088
	/* Write the clut table */
5089
	size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
5090
	if (p->ttype == icSigLut8Type) {
5091
		for (i = 0; i < size; i++, bp += 1) {
5092
			if ((rv = write_DCS8Number(p->clutTable[i], bp)) != 0) {
5093
				sprintf(icp->err,"icmLut_write: clutTable write_DCS8Number() failed");
5094
				icp->al->free(icp->al, buf);
5095
				return icp->errc = rv;
5096
			}
5097
		}
5098
	} else {
5099
		for (i = 0; i < size; i++, bp += 2) {
5100
			if ((rv = write_DCS16Number(p->clutTable[i], bp)) != 0) {
5101
				sprintf(icp->err,"icmLut_write: clutTable write_DCS16Number(%f) failed",p->clutTable[i]);
5102
				icp->al->free(icp->al, buf);
5103
				return icp->errc = rv;
5104
			}
5105
		}
5106
	}
5107
 
5108
	/* Write the output tables */
5109
	size = (p->outputChan * p->outputEnt);
5110
	if (p->ttype == icSigLut8Type) {
5111
		for (i = 0; i < size; i++, bp += 1) {
5112
			if ((rv = write_DCS8Number(p->outputTable[i], bp)) != 0) {
5113
				sprintf(icp->err,"icmLut_write: outputTable write_DCS8Number() failed");
5114
				icp->al->free(icp->al, buf);
5115
				return icp->errc = rv;
5116
			}
5117
		}
5118
	} else {
5119
		for (i = 0; i < size; i++, bp += 2) {
5120
			if ((rv = write_DCS16Number(p->outputTable[i], bp)) != 0) {
5121
				sprintf(icp->err,"icmLut_write: outputTable write_DCS16Number(%f) failed",p->outputTable[i]);
5122
				icp->al->free(icp->al, buf);
5123
				return icp->errc = rv;
5124
			}
5125
		}
5126
	}
5127
 
5128
	/* Write buffer to the file */
5129
	if (   icp->fp->seek(icp->fp, of) != 0
5130
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
5131
		sprintf(icp->err,"icmLut_write fseek() or fwrite() failed");
5132
		icp->al->free(icp->al, buf);
5133
		return icp->errc = 2;
5134
	}
5135
	icp->al->free(icp->al, buf);
5136
	return 0;
5137
}
5138
 
5139
/* Dump a text description of the object */
5140
static void icmLut_dump(
5141
	icmBase *pp,
5142
	FILE *op,		/* Output to dump to */
5143
	int   verb		/* Verbosity level */
5144
) {
5145
	icmLut *p = (icmLut *)pp;
5146
	if (verb <= 0)
5147
		return;
5148
 
5149
	if (p->ttype == icSigLut8Type) {
5150
		fprintf(op,"Lut8:\n");
5151
	} else {
5152
		fprintf(op,"Lut16:\n");
5153
	}
5154
	fprintf(op,"  Input Channels = %u\n",p->inputChan);
5155
	fprintf(op,"  Output Channels = %u\n",p->outputChan);
5156
	fprintf(op,"  CLUT resolution = %u\n",p->clutPoints);
5157
	fprintf(op,"  Input Table entries = %u\n",p->inputEnt);
5158
	fprintf(op,"  Output Table entries = %u\n",p->outputEnt);
5159
	fprintf(op,"  XYZ matrix =  %f, %f, %f\n",p->e[0][0],p->e[0][1],p->e[0][2]);
5160
	fprintf(op,"                %f, %f, %f\n",p->e[1][0],p->e[1][1],p->e[1][2]);
5161
	fprintf(op,"                %f, %f, %f\n",p->e[2][0],p->e[2][1],p->e[2][2]);
5162
 
5163
	if (verb >= 2) {
5164
		unsigned int i,size;
5165
		int j;
5166
		unsigned int ii[MAX_CHAN];	/* maximum no of input channels */
5167
 
5168
		fprintf(op,"  Input table:\n");
5169
		for (i = 0; i < p->inputEnt; i++) {
5170
			fprintf(op,"    %3u: ",i);
5171
			for (j = 0; j < p->inputChan; j++)
5172
				fprintf(op," %1.10f",p->inputTable[j * p->inputEnt + i]);
5173
			fprintf(op,"\n");
5174
		}
5175
 
5176
		fprintf(op,"\n  CLUT table:\n");
5177
		if (p->inputChan > MAX_CHAN) {
5178
			fprintf(op,"  !!Can't dump > %d input channel CLUT table!!\n",MAX_CHAN);
5179
		} else {
5180
			size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
5181
			for (j = 0; j < p->inputChan; j++)
5182
				ii[j] = 0;
5183
			for (i = 0; i < size;) {
5184
				int k;
5185
				/* Print table entry index */
5186
				fprintf(op,"   ");
5187
				for (j = p->inputChan-1; j >= 0; j--)
5188
					fprintf(op," %2u",ii[j]);
5189
				fprintf(op,":");
5190
				/* Print table entry contents */
5191
				for (k = 0; k < p->outputChan; k++, i++)
5192
					fprintf(op," %1.10f",p->clutTable[i]);
5193
				fprintf(op,"\n");
5194
 
5195
				for (j = 0; j < p->inputChan; j++) { /* Increment index */
5196
					ii[j]++;
5197
					if (ii[j] < p->clutPoints)
5198
						break;	/* No carry */
5199
					ii[j] = 0;
5200
				}
5201
			}
5202
		}
5203
 
5204
		fprintf(op,"\n  Output table:\n");
5205
		for (i = 0; i < p->outputEnt; i++) {
5206
			fprintf(op,"    %3u: ",i);
5207
			for (j = 0; j < p->outputChan; j++)
5208
				fprintf(op," %1.10f",p->outputTable[j * p->outputEnt + i]);
5209
			fprintf(op,"\n");
5210
		}
5211
 
5212
	}
5213
}
5214
 
5215
/* Allocate variable sized data elements */
5216
static int icmLut_allocate(
5217
	icmBase *pp
5218
) {
5219
	unsigned int i, j, g, size;
5220
	icmLut *p = (icmLut *)pp;
5221
	icc *icp = p->icp;
5222
 
5223
	/* Sanity check */
5224
	if (p->inputChan > MAX_CHAN) {
5225
		sprintf(icp->err,"icmLut_alloc: Can't handle > %d input channels\n",MAX_CHAN);
5226
		return icp->errc = 1;
5227
	}
5228
 
5229
	if (p->outputChan > MAX_CHAN) {
5230
		sprintf(icp->err,"icmLut_alloc: Can't handle > %d output channels\n",MAX_CHAN);
5231
		return icp->errc = 1;
5232
	}
5233
 
5234
	size = (p->inputChan * p->inputEnt);
5235
	if (size != p->inputTable_size) {
5236
		if (p->inputTable != NULL)
5237
			icp->al->free(icp->al, p->inputTable);
5238
		if ((p->inputTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) {
5239
			sprintf(icp->err,"icmLut_alloc: calloc() of Lut inputTable data failed");
5240
			return icp->errc = 2;
5241
		}
5242
		p->inputTable_size = size;
5243
	}
5244
	size = (p->outputChan * uipow(p->clutPoints,p->inputChan));
5245
	if (size != p->clutTable_size) {
5246
		if (p->clutTable != NULL)
5247
			icp->al->free(icp->al, p->clutTable);
5248
		if ((p->clutTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) {
5249
			sprintf(icp->err,"icmLut_alloc: calloc() of Lut clutTable data failed");
5250
			return icp->errc = 2;
5251
		}
5252
		p->clutTable_size = size;
5253
	}
5254
	size = (p->outputChan * p->outputEnt);
5255
	if (size != p->outputTable_size) {
5256
		if (p->outputTable != NULL)
5257
			icp->al->free(icp->al, p->outputTable);
5258
		if ((p->outputTable = (double *) icp->al->calloc(icp->al,sizeof(double), size)) == NULL) {
5259
			sprintf(icp->err,"icmLut_alloc: calloc() of Lut outputTable data failed");
5260
			return icp->errc = 2;
5261
		}
5262
		p->outputTable_size = size;
5263
	}
5264
 
5265
	/* Private: compute dimensional increment though clut */
5266
	/* Note that first channel varies least rapidly. */
5267
	i = p->inputChan-1;
5268
	p->dinc[i--] = p->outputChan;
5269
	for (; i < p->inputChan; i--)
5270
		p->dinc[i] = p->dinc[i+1] * p->clutPoints;
5271
 
5272
	/* Private: compute offsets from base of cube to other corners */
5273
	for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
5274
		for (i = 0; i < g; i++)
5275
			p->dcube[g+i] = p->dcube[i] + p->dinc[j];
5276
		g *= 2;
5277
	}
5278
 
5279
	return 0;
5280
}
5281
 
5282
/* Free all storage in the object */
5283
static void icmLut_delete(
5284
	icmBase *pp
5285
) {
5286
	icmLut *p = (icmLut *)pp;
5287
	icc *icp = p->icp;
5288
 
5289
	if (p->inputTable != NULL)
5290
		icp->al->free(icp->al, p->inputTable);
5291
	if (p->clutTable != NULL)
5292
		icp->al->free(icp->al, p->clutTable);
5293
	if (p->outputTable != NULL)
5294
		icp->al->free(icp->al, p->outputTable);
5295
	icmTable_delete_bwd(icp, &p->rit);
5296
	icmTable_delete_bwd(icp, &p->rot);
5297
	icp->al->free(icp->al, p);
5298
}
5299
 
5300
/* Create an empty object. Return null on error */
5301
static icmBase *new_icmLut(
5302
	icc *icp
5303
) {
5304
	int i,j;
5305
	icmLut *p;
5306
	if ((p = (icmLut *) icp->al->calloc(icp->al,1,sizeof(icmLut))) == NULL)
5307
		return NULL;
5308
	p->ttype    = icSigLut16Type;
5309
	p->refcount = 1;
5310
	p->get_size = icmLut_get_size;
5311
	p->read     = icmLut_read;
5312
	p->write    = icmLut_write;
5313
	p->dump     = icmLut_dump;
5314
	p->allocate = icmLut_allocate;
5315
	p->del      = icmLut_delete;
5316
 
5317
	/* Lookup methods */
5318
	p->nu_matrix      = icmLut_nu_matrix;
5319
	p->min_max        = icmLut_min_max;
5320
	p->lookup_matrix  = icmLut_lookup_matrix;
5321
	p->lookup_input   = icmLut_lookup_input;
5322
	p->lookup_clut_nl = icmLut_lookup_clut_nl;
5323
	p->lookup_clut_sx = icmLut_lookup_clut_sx;
5324
	p->lookup_output  = icmLut_lookup_output;
5325
 
5326
	/* Set method */
5327
	p->set_tables = icmLut_set_tables;
5328
 
5329
	p->icp      = icp;
5330
 
5331
	/* Set matrix to reasonable default */
5332
	for (i = 0; i < 3; i++)
5333
		for (j = 0; j < 3; j++) {
5334
			if (i == j)
5335
				p->e[i][j] = 1.0;
5336
			else
5337
				p->e[i][j] = 0.0;
5338
		}
5339
 
5340
	/* Init lookups to non-dangerous values */
5341
	for (i = 0; i < MAX_CHAN; i++)
5342
		p->dinc[i] = 0;
5343
 
5344
	for (i = 0; i < (1 << MAX_CHAN); i++)
5345
		p->dcube[i] = 0;
5346
 
5347
	p->rit.inited = 0;
5348
	p->rot.inited = 0;
5349
 
5350
	return (icmBase *)p;
5351
}
5352
 
5353
/* ---------------------------------------------------------- */
5354
/* Measurement */
5355
 
5356
/* Return the number of bytes needed to write this tag */
5357
static unsigned int icmMeasurement_get_size(
5358
	icmBase *pp
5359
) {
5360
	unsigned int len = 0;
5361
	len += 8;			/* 8 bytes for tag and padding */
5362
	len += 4;			/* 4 for standard observer */
5363
	len += 12;			/* 12 for XYZ of measurement backing */
5364
	len += 4;			/* 4 for measurement geometry */
5365
	len += 4;			/* 4 for measurement flare */
5366
	len += 4;			/* 4 for standard illuminant */
5367
	return len;
5368
}
5369
 
5370
/* read the object, return 0 on success, error code on fail */
5371
static int icmMeasurement_read(
5372
	icmBase *pp,
5373
	unsigned long len,		/* tag length */
5374
	unsigned long of		/* start offset within file */
5375
) {
5376
	icmMeasurement *p = (icmMeasurement *)pp;
5377
	icc *icp = p->icp;
5378
	int rv;
5379
	char *bp, *buf;
5380
 
5381
	if (len < 36) {
5382
		sprintf(icp->err,"icmMeasurement_read: Tag too small to be legal");
5383
		return icp->errc = 1;
5384
	}
5385
 
5386
	/* Allocate a file read buffer */
5387
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5388
		sprintf(icp->err,"icmMeasurement_read: malloc() failed");
5389
		return icp->errc = 2;
5390
	}
5391
	bp = buf;
5392
 
5393
	/* Read portion of file into buffer */
5394
	if (   icp->fp->seek(icp->fp, of) != 0
5395
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
5396
		sprintf(icp->err,"icmMeasurement_read: fseek() or fread() failed");
5397
		icp->al->free(icp->al, buf);
5398
		return icp->errc = 1;
5399
	}
5400
 
5401
	/* Read type descriptor from the buffer */
5402
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
5403
		sprintf(icp->err,"icmMeasurement_read: Wrong tag type for icmMeasurement");
5404
		icp->al->free(icp->al, buf);
5405
		return icp->errc = 1;
5406
	}
5407
 
5408
	/* Read the encoded standard observer */
5409
	p->observer = (icStandardObserver)read_SInt32Number(bp + 8);
5410
 
5411
	/* Read the XYZ values for measurement backing */
5412
	if ((rv = read_XYZNumber(&p->backing, bp+12)) != 0) {
5413
		sprintf(icp->err,"icmMeasurement: read_XYZNumber error");
5414
		icp->al->free(icp->al, buf);
5415
		return icp->errc = rv;
5416
	}
5417
 
5418
	/* Read the encoded measurement geometry */
5419
	p->geometry = (icMeasurementGeometry)read_SInt32Number(bp + 24);
5420
 
5421
	/* Read the proportion of flare  */
5422
	p->flare = read_U16Fixed16Number(bp + 28);
5423
 
5424
	/* Read the encoded standard illuminant */
5425
	p->illuminant = (icIlluminant)read_SInt32Number(bp + 32);
5426
 
5427
	icp->al->free(icp->al, buf);
5428
	return 0;
5429
}
5430
 
5431
/* Write the contents of the object. Return 0 on sucess, error code on failure */
5432
static int icmMeasurement_write(
5433
	icmBase *pp,
5434
	unsigned long of			/* File offset to write from */
5435
) {
5436
	icmMeasurement *p = (icmMeasurement *)pp;
5437
	icc *icp = p->icp;
5438
	unsigned int len;
5439
	char *bp, *buf;		/* Buffer to write from */
5440
	int rv = 0;
5441
 
5442
	/* Allocate a file write buffer */
5443
	len = p->get_size((icmBase *)p);
5444
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5445
		sprintf(icp->err,"icmMeasurement_write malloc() failed");
5446
		return icp->errc = 2;
5447
	}
5448
	bp = buf;
5449
 
5450
	/* Write type descriptor to the buffer */
5451
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
5452
		sprintf(icp->err,"icmMeasurement_write, type: write_SInt32Number() failed");
5453
		icp->al->free(icp->al, buf);
5454
		return icp->errc = rv;
5455
	}
5456
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
5457
 
5458
	/* Write the encoded standard observer */
5459
	if ((rv = write_SInt32Number((int)p->observer, bp + 8)) != 0) {
5460
		sprintf(icp->err,"icmMeasurementa_write, observer: write_SInt32Number() failed");
5461
		icp->al->free(icp->al, buf);
5462
		return icp->errc = rv;
5463
	}
5464
 
5465
	/* Write the XYZ values for measurement backing */
5466
	if ((rv = write_XYZNumber(&p->backing, bp+12)) != 0) {
5467
		sprintf(icp->err,"icmMeasurement, backing: write_XYZNumber error");
5468
		icp->al->free(icp->al, buf);
5469
		return icp->errc = rv;
5470
	}
5471
 
5472
	/* Write the encoded measurement geometry */
5473
	if ((rv = write_SInt32Number((int)p->geometry, bp + 24)) != 0) {
5474
		sprintf(icp->err,"icmMeasurementa_write, geometry: write_SInt32Number() failed");
5475
		icp->al->free(icp->al, buf);
5476
		return icp->errc = rv;
5477
	}
5478
 
5479
	/* Write the proportion of flare */
5480
	if ((rv = write_U16Fixed16Number(p->flare, bp + 28)) != 0) {
5481
		sprintf(icp->err,"icmMeasurementa_write, flare: write_U16Fixed16Number() failed");
5482
		icp->al->free(icp->al, buf);
5483
		return icp->errc = rv;
5484
	}
5485
 
5486
	/* Write the encoded standard illuminant */
5487
	if ((rv = write_SInt32Number((int)p->illuminant, bp + 32)) != 0) {
5488
		sprintf(icp->err,"icmMeasurementa_write, illuminant: write_SInt32Number() failed");
5489
		icp->al->free(icp->al, buf);
5490
		return icp->errc = rv;
5491
	}
5492
 
5493
	/* Write to the file */
5494
	if (   icp->fp->seek(icp->fp, of) != 0
5495
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
5496
		sprintf(icp->err,"icmMeasurement_write fseek() or fwrite() failed");
5497
		icp->al->free(icp->al, buf);
5498
		return icp->errc = 2;
5499
	}
5500
	icp->al->free(icp->al, buf);
5501
	return 0;
5502
}
5503
 
5504
/* Dump a text description of the object */
5505
static void icmMeasurement_dump(
5506
	icmBase *pp,
5507
	FILE *op,		/* Output to dump to */
5508
	int   verb		/* Verbosity level */
5509
) {
5510
	icmMeasurement *p = (icmMeasurement *)pp;
5511
	if (verb <= 0)
5512
		return;
5513
 
5514
	fprintf(op,"Measurement:\n");
5515
	fprintf(op,"  Standard Observer = %s\n", string_StandardObserver(p->observer));
5516
	fprintf(op,"  XYZ for Measurement Backing = %s\n", string_XYZNumber_and_Lab(&p->backing));
5517
	fprintf(op,"  Measurement Geometry = %s\n", string_MeasurementGeometry(p->geometry));
5518
	fprintf(op,"  Measurement Flare = %5.1f%%\n", p->flare * 100.0);
5519
	fprintf(op,"  Standard Illuminant = %s\n", string_Illuminant(p->illuminant));
5520
}
5521
 
5522
/* Allocate variable sized data elements */
5523
static int icmMeasurement_allocate(
5524
	icmBase *pp
5525
) {
5526
	/* Nothing to do */
5527
	return 0;
5528
}
5529
 
5530
/* Free all storage in the object */
5531
static void icmMeasurement_delete(
5532
	icmBase *pp
5533
) {
5534
	icmMeasurement *p = (icmMeasurement *)pp;
5535
	icc *icp = p->icp;
5536
 
5537
	icp->al->free(icp->al, p);
5538
}
5539
 
5540
/* Create an empty object. Return null on error */
5541
static icmBase *new_icmMeasurement(
5542
	icc *icp
5543
) {
5544
	icmMeasurement *p;
5545
	if ((p = (icmMeasurement *) icp->al->calloc(icp->al,1,sizeof(icmMeasurement))) == NULL)
5546
		return NULL;
5547
	p->ttype    = icSigMeasurementType;
5548
	p->refcount = 1;
5549
	p->get_size = icmMeasurement_get_size;
5550
	p->read     = icmMeasurement_read;
5551
	p->write    = icmMeasurement_write;
5552
	p->dump     = icmMeasurement_dump;
5553
	p->allocate = icmMeasurement_allocate;
5554
	p->del      = icmMeasurement_delete;
5555
	p->icp      = icp;
5556
 
5557
	return (icmBase *)p;
5558
}
5559
 
5560
/* ---------------------------------------------------------- */
5561
 
5562
/* Named color structure read/write support */
5563
static int read_NamedColorVal(
5564
	icmNamedColorVal *p,
5565
	char *bp,
5566
	char *end,
5567
	icColorSpaceSignature pcs,		/* Header Profile Connection Space */
5568
	unsigned int ndc				/* Number of device corrds */
5569
) {
5570
	icc *icp = p->icp;
5571
	int i;
5572
	unsigned int mxl;	/* Max possible string length */
5573
 
5574
	mxl = (end - bp) < 32 ? (end - bp) : 32;
5575
	if (check_null_string(bp,mxl)) {
5576
		sprintf(icp->err,"icmNamedColorVal_read: Root name string not terminated");
5577
		return icp->errc = 1;
5578
	}
5579
	strcpy((void *)p->root, (void *)bp);
5580
	bp += strlen(p->root) + 1;
5581
	if ((bp + ndc) > end) {
5582
		sprintf(icp->err,"icmNamedColorVal_read: Data too short to read device coords");
5583
		return icp->errc = 1;
5584
	}
5585
	for (i = 0; i < ndc; i++) {
5586
		p->deviceCoords[i] = read_DCS8Number(bp);
5587
		bp += 1;
5588
	}
5589
	return 0;
5590
}
5591
 
5592
static int read_NamedColorVal2(
5593
	icmNamedColorVal *p,
5594
	char *bp,
5595
	char *end,
5596
	icColorSpaceSignature pcs,		/* Header Profile Connection Space */
5597
	unsigned int ndc				/* Number of device corrds */
5598
) {
5599
	icc *icp = p->icp;
5600
	int i;
5601
	if ((bp + 32 + 6 + ndc * 2) > end) {
5602
		sprintf(icp->err,"icmNamedColorVal2_read: Data too short to read");
5603
		return icp->errc = 1;
5604
	}
5605
	if (check_null_string(bp,32)) {
5606
		sprintf(icp->err,"icmNamedColorVal2_read: Root name string not terminated");
5607
		return icp->errc = 1;
5608
	}
5609
	memcpy((void *)p->root,(void *)(bp + 0),32);
5610
	switch(pcs) {
5611
		case icSigXYZData:
5612
				p->pcsCoords[0] = read_PCSXYZ16Number(bp+32);
5613
				p->pcsCoords[1] = read_PCSXYZ16Number(bp+34);
5614
				p->pcsCoords[2] = read_PCSXYZ16Number(bp+36);
5615
			break;
5616
	   	case icSigLabData:
5617
				p->pcsCoords[0] =  read_PCSL16Number(bp+32);
5618
				p->pcsCoords[1] = read_PCSab16Number(bp+34);
5619
				p->pcsCoords[2] = read_PCSab16Number(bp+36);
5620
			break;
5621
		default:
5622
			return 1;		/* Unknown PCS */
5623
	}
5624
	for (i = 0; i < ndc; i++)
5625
		p->deviceCoords[i] = read_DCS16Number(bp + 32 + 6 + 2 * i);
5626
	return 0;
5627
}
5628
 
5629
static int write_NamedColorVal(
5630
	icmNamedColorVal *p,
5631
	char *d,
5632
	icColorSpaceSignature pcs,		/* Header Profile Connection Space */
5633
	unsigned int ndc				/* Number of device corrds */
5634
) {
5635
	icc *icp = p->icp;
5636
	int i, rv = 0;
5637
	if (check_null_string(p->root,32) != 0) {
5638
		sprintf(icp->err,"icmNamedColorVal_write: Root string names is unterminated");
5639
		return icp->errc = 1;
5640
	}
5641
	strcpy((void *)d,(void *)p->root);
5642
	d += strlen(p->root) + 1;
5643
	for (i = 0; i < ndc; i++) {
5644
		if ((rv = write_DCS8Number(p->deviceCoords[i], d)) != 0) {
5645
			sprintf(icp->err,"icmNamedColorVal_write: write of device coord failed");
5646
			return icp->errc = 1;
5647
		}
5648
		d += 1;
5649
	}
5650
	return 0;
5651
}
5652
 
5653
static int write_NamedColorVal2(
5654
	icmNamedColorVal *p,
5655
	char *bp,
5656
	icColorSpaceSignature pcs,		/* Header Profile Connection Space */
5657
	unsigned int ndc				/* Number of device corrds */
5658
) {
5659
	icc *icp = p->icp;
5660
	int i, rv = 0;
5661
	if (check_null_string(p->root,32)) {
5662
		sprintf(icp->err,"icmNamedColorVal2_write: Root string names is unterminated");
5663
		return icp->errc = 1;
5664
	}
5665
	memcpy((void *)(bp + 0),(void *)p->root,32);
5666
	switch(pcs) {
5667
		case icSigXYZData:
5668
				rv |= write_PCSXYZ16Number(p->pcsCoords[0], bp+32);
5669
				rv |= write_PCSXYZ16Number(p->pcsCoords[1], bp+34);
5670
				rv |= write_PCSXYZ16Number(p->pcsCoords[2], bp+36);
5671
			break;
5672
    	case icSigLabData:
5673
				rv |=  write_PCSL16Number(p->pcsCoords[0], bp+32);
5674
				rv |= write_PCSab16Number(p->pcsCoords[1], bp+34);
5675
				rv |= write_PCSab16Number(p->pcsCoords[2], bp+36);
5676
			break;
5677
		default:
5678
			sprintf(icp->err,"icmNamedColorVal2_write: Unknown PCS");
5679
			return icp->errc = 1;
5680
	}
5681
	if (rv) {
5682
		sprintf(icp->err,"icmNamedColorVal2_write: write of PCS coord failed");
5683
		return icp->errc = 1;
5684
	}
5685
	for (i = 0; i < ndc; i++) {
5686
		if ((rv = write_DCS16Number(p->deviceCoords[i], bp + 32 + 6 + 2 * i)) != 0) {
5687
			sprintf(icp->err,"icmNamedColorVal2_write: write of device coord failed");
5688
			return icp->errc = 1;
5689
		}
5690
	}
5691
	return 0;
5692
}
5693
 
5694
/* - - - - - - - - - - - */
5695
/* icmNamedColor object */
5696
 
5697
/* Return the number of bytes needed to write this tag */
5698
static unsigned int icmNamedColor_get_size(
5699
	icmBase *pp
5700
) {
5701
	icmNamedColor *p = (icmNamedColor *)pp;
5702
	unsigned int len = 0;
5703
	if (p->ttype == icSigNamedColorType) {
5704
		unsigned int i;
5705
		len += 8;			/* 8 bytes for tag and padding */
5706
		len += 4;			/* 4 for vendor specific flags */
5707
		len += 4;			/* 4 for count of named colors */
5708
		len += strlen(p->prefix) + 1; /* prefix of color names */
5709
		len += strlen(p->suffix) + 1; /* suffix of color names */
5710
		for (i = 0; i < p->count; i++) {
5711
			len += strlen(p->data[i].root) + 1; /* color names */
5712
			len += p->nDeviceCoords * 1;	/* bytes for each named color */
5713
		}
5714
	} else {	/* Named Color 2 */
5715
		len += 8;			/* 8 bytes for tag and padding */
5716
		len += 4;			/* 4 for vendor specific flags */
5717
		len += 4;			/* 4 for count of named colors */
5718
		len += 4;			/* 4 for number of device coords */
5719
		len += 32;			/* 32 for prefix of color names */
5720
		len += 32;			/* 32 for suffix of color names */
5721
		len += p->count * (32 + 6 + p->nDeviceCoords * 2);	/* bytes for each named color */
5722
	}
5723
	return len;
5724
}
5725
 
5726
/* read the object, return 0 on success, error code on fail */
5727
static int icmNamedColor_read(
5728
	icmBase *pp,
5729
	unsigned long len,		/* tag length */
5730
	unsigned long of		/* start offset within file */
5731
) {
5732
	icmNamedColor *p = (icmNamedColor *)pp;
5733
	icc *icp = p->icp;
5734
	unsigned long i;
5735
	char *bp, *buf, *end;
5736
	int rv = 0;
5737
 
5738
	if (len < 4) {
5739
		sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
5740
		return icp->errc = 1;
5741
	}
5742
 
5743
	/* Allocate a file read buffer */
5744
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5745
		sprintf(icp->err,"icmNamedColor_read: malloc() failed");
5746
		return icp->errc = 2;
5747
	}
5748
	bp = buf;
5749
	end = buf + len;
5750
 
5751
	/* Read portion of file into buffer */
5752
	if (   icp->fp->seek(icp->fp, of) != 0
5753
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
5754
		sprintf(icp->err,"icmNamedColor_read: fseek() or fread() failed");
5755
		icp->al->free(icp->al, buf);
5756
		return icp->errc = 1;
5757
	}
5758
 
5759
	/* Read type descriptor from the buffer */
5760
	p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
5761
	if (p->ttype != icSigNamedColorType && p->ttype != icSigNamedColor2Type) {
5762
		sprintf(icp->err,"icmNamedColor_read: Wrong tag type for icmNamedColor");
5763
		icp->al->free(icp->al, buf);
5764
		return icp->errc = 1;
5765
	}
5766
 
5767
	if (p->ttype == icSigNamedColorType) {
5768
		if (len < 16) {
5769
			sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
5770
			icp->al->free(icp->al, buf);
5771
			return icp->errc = 1;
5772
		}
5773
		/* Make sure that the number of device coords in known */
5774
		p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
5775
		if (p->nDeviceCoords > MAX_CHAN) {
5776
			sprintf(icp->err,"icmNamedColor_read: Can't handle more than %d device channels",MAX_CHAN);
5777
			icp->al->free(icp->al, buf);
5778
			return icp->errc = 1;
5779
		}
5780
 
5781
	} else {	/* icmNC2 */
5782
		if (len < 84) {
5783
			sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
5784
			icp->al->free(icp->al, buf);
5785
			return icp->errc = 1;
5786
		}
5787
	}
5788
 
5789
	/* Read vendor specific flag */
5790
	p->vendorFlag = read_UInt32Number(bp+8);
5791
 
5792
	/* Read count of named colors */
5793
	p->count = read_UInt32Number(bp+12);
5794
 
5795
	if (p->ttype == icSigNamedColorType) {
5796
		unsigned int mxl;	/* Max possible string length */
5797
		bp = bp + 16;
5798
 
5799
		/* Prefix for each color name */
5800
		mxl = (end - bp) < 32 ? (end - bp) : 32;
5801
		if (check_null_string(bp,mxl) != 0) {
5802
			sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
5803
			icp->al->free(icp->al, buf);
5804
			return icp->errc = 1;
5805
		}
5806
		strcpy((void *)p->prefix, (void *)bp);
5807
		bp += strlen(p->prefix) + 1;
5808
 
5809
		/* Suffix for each color name */
5810
		mxl = (end - bp) < 32 ? (end - bp) : 32;
5811
		if (check_null_string(bp,mxl) != 0) {
5812
			sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
5813
			icp->al->free(icp->al, buf);
5814
			return icp->errc = 1;
5815
		}
5816
		strcpy((void *)p->suffix, (void *)bp);
5817
		bp += strlen(p->suffix) + 1;
5818
 
5819
		if ((rv = p->allocate((void *)p)) != 0) {
5820
			icp->al->free(icp->al, buf);
5821
			return rv;
5822
		}
5823
 
5824
		/* Read all the data from the buffer */
5825
		for (i = 0; i < p->count; i++) {
5826
			if ((rv = read_NamedColorVal(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
5827
				icp->al->free(icp->al, buf);
5828
				return rv;
5829
			}
5830
			bp += strlen(p->data[i].root) + 1;
5831
			bp += p->nDeviceCoords * 1;
5832
		}
5833
	} else {  /* icmNC2 */
5834
		/* Number of device coords per color */
5835
		p->nDeviceCoords = read_UInt32Number(bp+16);
5836
 
5837
		/* Prefix for each color name */
5838
		memcpy((void *)p->prefix, (void *)(bp + 20), 32);
5839
		if (check_null_string(p->prefix,32) != 0) {
5840
			sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
5841
			icp->al->free(icp->al, buf);
5842
			return icp->errc = 1;
5843
		}
5844
 
5845
		/* Suffix for each color name */
5846
		memcpy((void *)p->suffix, (void *)(bp + 52), 32);
5847
		if (check_null_string(p->suffix,32) != 0) {
5848
			sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
5849
			icp->al->free(icp->al, buf);
5850
			return icp->errc = 1;
5851
		}
5852
 
5853
		if ((rv = p->allocate((icmBase *)p)) != 0) {
5854
			icp->al->free(icp->al, buf);
5855
			return rv;
5856
		}
5857
 
5858
		/* Read all the data from the buffer */
5859
		bp = bp + 84;
5860
		for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) {
5861
			if ((rv = read_NamedColorVal2(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
5862
				icp->al->free(icp->al, buf);
5863
				return rv;
5864
			}
5865
		}
5866
	}
5867
	icp->al->free(icp->al, buf);
5868
	return rv;
5869
}
5870
 
5871
/* Write the contents of the object. Return 0 on sucess, error code on failure */
5872
static int icmNamedColor_write(
5873
	icmBase *pp,
5874
	unsigned long of			/* File offset to write from */
5875
) {
5876
	icmNamedColor *p = (icmNamedColor *)pp;
5877
	icc *icp = p->icp;
5878
	unsigned long i;
5879
	unsigned int len;
5880
	char *bp, *buf;		/* Buffer to write from */
5881
	int rv = 0;
5882
 
5883
	/* Allocate a file write buffer */
5884
	len = p->get_size((icmBase *)p);
5885
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
5886
		sprintf(icp->err,"icmNamedColor_write malloc() failed");
5887
		return icp->errc = 2;
5888
	}
5889
	bp = buf;
5890
 
5891
	/* Write type descriptor to the buffer */
5892
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
5893
		sprintf(icp->err,"icmNamedColor_write: write_SInt32Number() failed");
5894
		icp->al->free(icp->al, buf);
5895
		return icp->errc = rv;
5896
	}
5897
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
5898
 
5899
	/* Write vendor specific flag */
5900
	if ((rv = write_UInt32Number(p->vendorFlag, bp+8)) != 0) {
5901
		sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
5902
		icp->al->free(icp->al, buf);
5903
		return icp->errc = rv;
5904
	}
5905
 
5906
	/* Write count of named colors */
5907
	if ((rv = write_UInt32Number(p->count, bp+12)) != 0) {
5908
		sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
5909
		icp->al->free(icp->al, buf);
5910
		return icp->errc = rv;
5911
	}
5912
 
5913
	if (p->ttype == icSigNamedColorType) {
5914
		bp = bp + 16;
5915
 
5916
		/* Prefix for each color name */
5917
		if ((rv = check_null_string(p->prefix,32)) != 0) {
5918
			sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
5919
			icp->al->free(icp->al, buf);
5920
			return icp->errc = 1;
5921
		}
5922
		strcpy((void *)bp, (void *)p->prefix);
5923
		bp += strlen(p->prefix) + 1;
5924
 
5925
		/* Suffix for each color name */
5926
		if (check_null_string(p->suffix,32)) {
5927
			sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
5928
			icp->al->free(icp->al, buf);
5929
			return icp->errc = 1;
5930
		}
5931
		strcpy((void *)bp, (void *)p->suffix);
5932
		bp += strlen(p->suffix) + 1;
5933
 
5934
		/* Write all the data to the buffer */
5935
 
5936
		for (i = 0; i < p->count; i++) {
5937
			if ((rv = write_NamedColorVal(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
5938
				icp->al->free(icp->al, buf);
5939
				return rv;
5940
			}
5941
			bp += strlen(p->data[i].root) + 1;
5942
			bp += p->nDeviceCoords * 1;
5943
		}
5944
	} else {	/* icmNC2 */
5945
		/* Number of device coords per color */
5946
		if ((rv = write_UInt32Number(p->nDeviceCoords, bp+16)) != 0) {
5947
			sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
5948
			icp->al->free(icp->al, buf);
5949
			return icp->errc = rv;
5950
		}
5951
 
5952
		/* Prefix for each color name */
5953
		if ((rv = check_null_string(p->prefix,32)) != 0) {
5954
			sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
5955
			icp->al->free(icp->al, buf);
5956
			return icp->errc = 1;
5957
		}
5958
		memcpy((void *)(bp + 20), (void *)p->prefix, 32);
5959
 
5960
		/* Suffix for each color name */
5961
		if (check_null_string(p->suffix,32)) {
5962
			sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
5963
			icp->al->free(icp->al, buf);
5964
			return icp->errc = 1;
5965
		}
5966
		memcpy((void *)(bp + 52), (void *)p->suffix, 32);
5967
 
5968
		/* Write all the data to the buffer */
5969
		bp = bp + 84;
5970
		for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) {
5971
			if ((rv = write_NamedColorVal2(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
5972
				icp->al->free(icp->al, buf);
5973
				return rv;
5974
			}
5975
		}
5976
	}
5977
 
5978
	/* Write to the file */
5979
	if (   icp->fp->seek(icp->fp, of) != 0
5980
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
5981
		sprintf(icp->err,"icmNamedColor_write fseek() or fwrite() failed");
5982
		icp->al->free(icp->al, buf);
5983
		return icp->errc = 2;
5984
	}
5985
	icp->al->free(icp->al, buf);
5986
	return 0;
5987
}
5988
 
5989
/* Dump a text description of the object */
5990
static void icmNamedColor_dump(
5991
	icmBase *pp,
5992
	FILE *op,		/* Output to dump to */
5993
	int   verb		/* Verbosity level */
5994
) {
5995
	icmNamedColor *p = (icmNamedColor *)pp;
5996
	icc *icp = p->icp;
5997
	if (verb <= 0)
5998
		return;
5999
 
6000
	if (p->ttype == icSigNamedColorType)
6001
		fprintf(op,"NamedColor:\n");
6002
	else
6003
		fprintf(op,"NamedColor2:\n");
6004
	fprintf(op,"  Vendor Flag = 0x%x\n",p->vendorFlag);
6005
	fprintf(op,"  No. colors  = %u\n",p->count);
6006
	fprintf(op,"  No. dev. coords = %u\n",p->nDeviceCoords);
6007
	fprintf(op,"  Name prefix = '%s'\n",p->prefix);
6008
	fprintf(op,"  Name suffix = '%s'\n",p->suffix);
6009
	if (verb >= 2) {
6010
		unsigned long i, n;
6011
		icmNamedColorVal *vp;
6012
		for (i = 0; i < p->count; i++) {
6013
			vp = p->data + i;
6014
			fprintf(op,"    Color %lu:\n",i);
6015
			fprintf(op,"      Name root = '%s'\n",vp->root);
6016
 
6017
			if (p->ttype == icSigNamedColor2Type) {
6018
				switch(icp->header->pcs) {
6019
					case icSigXYZData:
6020
							fprintf(op,"      XYZ = %f, %f, %f'\n",
6021
							        vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
6022
						break;
6023
			    	case icSigLabData:
6024
							fprintf(op,"      Lab = %f, %f, %f'\n",
6025
							        vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
6026
						break;
6027
					default:
6028
							fprintf(op,"      Unexpected PCS\n");
6029
						break;
6030
				}
6031
			}
6032
			if (p->nDeviceCoords > 0) {
6033
				fprintf(op,"      Device Coords = ");
6034
				for (n = 0; n < p->nDeviceCoords; n++) {
6035
					if (n > 0)
6036
						printf(", ");
6037
					printf("%f",vp->deviceCoords[n]);
6038
				}
6039
				printf("\n");
6040
			}
6041
		}
6042
	}
6043
}
6044
 
6045
/* Allocate variable sized data elements */
6046
static int icmNamedColor_allocate(
6047
	icmBase *pp
6048
) {
6049
	icmNamedColor *p = (icmNamedColor *)pp;
6050
	icc *icp = p->icp;
6051
 
6052
	if (p->count != p->_count) {
6053
		unsigned int i;
6054
		if (p->data != NULL)
6055
			icp->al->free(icp->al, p->data);
6056
		if ((p->data = (icmNamedColorVal *) icp->al->calloc(icp->al,p->count, sizeof(icmNamedColorVal))) == NULL) {
6057
			sprintf(icp->err,"icmNamedColor_alloc: malloc() of icmNamedColor data failed");
6058
			return icp->errc = 2;
6059
		}
6060
		for (i = 0; i < p->count; i++) {
6061
			p->data[i].icp = icp;	/* Do init */
6062
		}
6063
		p->_count = p->count;
6064
	}
6065
	return 0;
6066
}
6067
 
6068
/* Free all storage in the object */
6069
static void icmNamedColor_delete(
6070
	icmBase *pp
6071
) {
6072
	icmNamedColor *p = (icmNamedColor *)pp;
6073
	icc *icp = p->icp;
6074
 
6075
	if (p->data != NULL)
6076
		icp->al->free(icp->al, p->data);
6077
	icp->al->free(icp->al, p);
6078
}
6079
 
6080
/* Create an empty object. Return null on error */
6081
static icmBase *new_icmNamedColor(
6082
	icc *icp
6083
) {
6084
	icmNamedColor *p;
6085
	if ((p = (icmNamedColor *) icp->al->calloc(icp->al,1,sizeof(icmNamedColor))) == NULL)
6086
		return NULL;
6087
	p->ttype    = icSigNamedColor2Type;
6088
	p->refcount = 1;
6089
	p->get_size = icmNamedColor_get_size;
6090
	p->read     = icmNamedColor_read;
6091
	p->write    = icmNamedColor_write;
6092
	p->dump     = icmNamedColor_dump;
6093
	p->allocate = icmNamedColor_allocate;
6094
	p->del      = icmNamedColor_delete;
6095
	p->icp      = icp;
6096
 
6097
	/* Default the the number of device coords appropriately for NamedColorType */
6098
	p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
6099
 
6100
	return (icmBase *)p;
6101
}
6102
 
6103
/* ---------------------------------------------------------- */
6104
/* textDescription */
6105
 
6106
/* Return the number of bytes needed to write this tag */
6107
static unsigned int icmTextDescription_get_size(
6108
	icmBase *pp
6109
) {
6110
	icmTextDescription *p = (icmTextDescription *)pp;
6111
	unsigned int len = 0;
6112
	len += 8;			/* 8 bytes for tag and padding */
6113
	len += 4 + p->size;	/* Ascii string length + ascii string */
6114
	len += 8 + 2 * p->ucSize;	/* Unicode language code + length + string */
6115
	len += 3 + 67;		/* ScriptCode code, length string */
6116
	return len;
6117
}
6118
 
6119
/* read the object, return 0 on success, error code on fail */
6120
static int icmTextDescription_read(
6121
	icmBase *pp,
6122
	unsigned long len,		/* tag length */
6123
	unsigned long of		/* start offset within file */
6124
) {
6125
	icmTextDescription *p = (icmTextDescription *)pp;
6126
	icc *icp = p->icp;
6127
	int rv;
6128
	char *bp, *buf, *end;
6129
 
6130
#ifdef ICM_STRICT
6131
	if (len < (8 + 4 + 8 + 3 /* + 67 */)) {
6132
#else
6133
	if (len < (8 + 4 + 8 + 3)) {
6134
#endif
6135
		sprintf(icp->err,"icmTextDescription_read: Tag too small to be legal");
6136
		return icp->errc = 1;
6137
	}
6138
 
6139
	/* Allocate a file read buffer */
6140
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6141
		sprintf(icp->err,"icmTextDescription_read: malloc() failed");
6142
		return icp->errc = 2;
6143
	}
6144
	bp = buf;
6145
	end = buf + len;
6146
 
6147
	/* Read portion of file into buffer */
6148
	if (   icp->fp->seek(icp->fp, of) != 0
6149
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
6150
		sprintf(icp->err,"icmTextDescription_read: fseek() or fread() failed");
6151
		icp->al->free(icp->al, buf);
6152
		return icp->errc = 1;
6153
	}
6154
 
6155
	/* Read from the buffer into the structure */
6156
	if ((rv = p->core_read(p, &bp, end)) != 0) {
6157
		icp->al->free(icp->al, buf);
6158
		return rv;
6159
	}
6160
 
6161
	icp->al->free(icp->al, buf);
6162
	return 0;
6163
}
6164
 
6165
/* core read the object, return 0 on success, error code on fail */
6166
static int icmTextDescription_core_read(
6167
	icmTextDescription *p,
6168
	char **bpp,				/* Pointer to buffer pointer, returns next after read */
6169
	char *end				/* Pointer to past end of read buffer */
6170
) {
6171
	icc *icp = p->icp;
6172
	int rv = 0;
6173
	char *bp = *bpp;
6174
 
6175
	if ((bp + 8) > end) {
6176
		sprintf(icp->err,"icmTextDescription_read: Data too short to type descriptor");
6177
		*bpp = bp;
6178
		return icp->errc = 1;
6179
	}
6180
 
6181
	p->size = read_UInt32Number(bp);
6182
	/* Read type descriptor from the buffer */
6183
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
6184
		*bpp = bp;
6185
		sprintf(icp->err,"icmTextDescription_read: Wrong tag type ('%s') for icmTextDescription",
6186
		        tag2str((icTagTypeSignature)read_SInt32Number(bp)));
6187
		return icp->errc = 1;
6188
	}
6189
	bp = bp + 8;
6190
 
6191
	/* Read the Ascii string */
6192
	if ((bp + 4) > end) {
6193
		*bpp = bp;
6194
		sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii header");
6195
		return icp->errc = 1;
6196
	}
6197
	p->size = read_UInt32Number(bp);
6198
	bp += 4;
6199
	if (p->size > 0) {
6200
		if ((bp + p->size) > end) {
6201
			*bpp = bp;
6202
			sprintf(icp->err,"icmTextDescription_read: Data to short to read Ascii string");
6203
			return icp->errc = 1;
6204
		}
6205
		if (check_null_string(bp,p->size)) {
6206
			*bpp = bp;
6207
			sprintf(icp->err,"icmTextDescription_read: ascii string is not terminated");
6208
			return icp->errc = 1;
6209
		}
6210
		if ((rv = p->allocate((icmBase *)p)) != 0) {
6211
			return rv;
6212
		}
6213
		strcpy((void *)p->desc, (void *)bp);
6214
		bp += p->size;
6215
	}
6216
 
6217
	/* Read the Unicode string */
6218
	if ((bp + 8) > end) {
6219
		*bpp = bp;
6220
		sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
6221
		return icp->errc = 1;
6222
	}
6223
	p->ucLangCode = read_UInt32Number(bp);
6224
	bp += 4;
6225
	p->ucSize = read_UInt32Number(bp);
6226
	bp += 4;
6227
	if (p->ucSize > 0) {
6228
		ORD16 *up;
6229
		if ((bp + 2 * p->ucSize) > end) {
6230
			*bpp = bp;
6231
			sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
6232
			return icp->errc = 1;
6233
		}
6234
		if (check_null_string16(bp,p->ucSize)) {
6235
			*bpp = bp;
6236
			sprintf(icp->err,"icmTextDescription_read: Unicode string is not terminated");
6237
			return icp->errc = 1;
6238
		}
6239
		if ((rv = p->allocate((icmBase *)p)) != 0) {
6240
			return rv;
6241
		}
6242
		for(up = p->ucDesc; bp[0] != 0 || bp[1] != 0; up++, bp += 2)
6243
			*up = read_UInt16Number(bp);
6244
		*up = 0;	/* Unicode null */
6245
		bp += 2;
6246
	}
6247
 
6248
	/* Read the ScriptCode string */
6249
	if ((bp + 3) > end) {
6250
		*bpp = bp;
6251
		sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode header");
6252
		return icp->errc = 1;
6253
	}
6254
	p->scCode = read_UInt16Number(bp);
6255
	bp += 2;
6256
	p->scSize = read_UInt8Number(bp);
6257
	bp += 1;
6258
	if (p->scSize > 0) {
6259
		if (p->scSize > 67) {
6260
			*bpp = bp;
6261
			sprintf(icp->err,"icmTextDescription_read: ScriptCode string too long");
6262
			return icp->errc = 1;
6263
		}
6264
		if ((bp + p->scSize) > end) {
6265
			*bpp = bp;
6266
			sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode string");
6267
			return icp->errc = 1;
6268
		}
6269
		if (check_null_string(bp,p->scSize)) {
6270
			*bpp = bp;
6271
			sprintf(icp->err,"icmTextDescription_read: ScriptCode string is not terminated");
6272
			return icp->errc = 1;
6273
		}
6274
		memcpy((void *)p->scDesc, (void *)bp, p->scSize);
6275
	} else {
6276
		memset((void *)p->scDesc, 0, 67);
6277
	}
6278
	bp += 67;
6279
 
6280
	*bpp = bp;
6281
	return 0;
6282
}
6283
 
6284
/* Write the contents of the object. Return 0 on sucess, error code on failure */
6285
static int icmTextDescription_write(
6286
	icmBase *pp,
6287
	unsigned long of			/* File offset to write from */
6288
) {
6289
	icmTextDescription *p = (icmTextDescription *)pp;
6290
	icc *icp = p->icp;
6291
	unsigned int len;
6292
	char *bp, *buf;		/* Buffer to write from */
6293
	int rv = 0;
6294
 
6295
	/* Allocate a file write buffer */
6296
	len = p->get_size((icmBase *)p);
6297
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6298
		sprintf(icp->err,"icmTextDescription_write malloc() failed");
6299
		return icp->errc = 2;
6300
	}
6301
	bp = buf;
6302
 
6303
	/* Write to the buffer from the structure */
6304
	if ((rv = p->core_write(p, &bp)) != 0) {
6305
		icp->al->free(icp->al, buf);
6306
		return rv;
6307
	}
6308
 
6309
	/* Write to the file */
6310
	if (   icp->fp->seek(icp->fp, of) != 0
6311
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
6312
		sprintf(icp->err,"icmTextDescription_write fseek() or fwrite() failed");
6313
		icp->al->free(icp->al, buf);
6314
		return icp->errc = 2;
6315
	}
6316
	icp->al->free(icp->al, buf);
6317
	return 0;
6318
}
6319
 
6320
/* Core write the contents of the object. Return 0 on sucess, error code on failure */
6321
static int icmTextDescription_core_write(
6322
	icmTextDescription *p,
6323
	char **bpp				/* Pointer to buffer pointer, returns next after read */
6324
) {
6325
	icc *icp = p->icp;
6326
	char *bp = *bpp;
6327
	int rv = 0;
6328
 
6329
	/* Write type descriptor to the buffer */
6330
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
6331
		sprintf(icp->err,"icmTextDescription_write: write_SInt32Number() failed");
6332
		*bpp = bp;
6333
		return icp->errc = rv;
6334
	}
6335
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
6336
	bp = bp + 8;
6337
 
6338
	/* Write the Ascii string */
6339
	if ((rv = write_UInt32Number(p->size,bp)) != 0) {
6340
		sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
6341
		*bpp = bp;
6342
		return icp->errc = rv;
6343
	}
6344
	bp += 4;
6345
	if (p->size > 0) {
6346
		if (check_null_string(p->desc,p->size)) {
6347
			*bpp = bp;
6348
			sprintf(icp->err,"icmTextDescription_write: ascii string is not terminated");
6349
			return icp->errc = 1;
6350
		}
6351
		strcpy((void *)bp, (void *)p->desc);
6352
		bp += p->size;
6353
	}
6354
 
6355
	/* Write the Unicode string */
6356
	if ((rv = write_UInt32Number(p->ucLangCode, bp)) != 0) {
6357
		sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
6358
		*bpp = bp;
6359
		return icp->errc = rv;
6360
	}
6361
	bp += 4;
6362
	if ((rv = write_UInt32Number(p->ucSize, bp)) != 0) {
6363
		sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
6364
		*bpp = bp;
6365
		return icp->errc = rv;
6366
	}
6367
	bp += 4;
6368
	if (p->ucSize > 0) {
6369
		ORD16 *up;
6370
		if (check_null_string16((char *)p->ucDesc,p->ucSize)) {
6371
			*bpp = bp;
6372
			sprintf(icp->err,"icmTextDescription_write: Unicode string is not terminated");
6373
			return icp->errc = 1;
6374
		}
6375
		for(up = p->ucDesc; *up != 0; up++, bp += 2) {
6376
			if ((rv = write_UInt16Number(((unsigned int)*up), bp)) != 0) {
6377
				sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
6378
				*bpp = bp;
6379
				return icp->errc = rv;
6380
			}
6381
		}
6382
		bp[0] = 0;	/* null */
6383
		bp[1] = 0;
6384
		bp += 2;
6385
	}
6386
 
6387
	/* Write the ScriptCode string */
6388
	if ((rv = write_UInt16Number(p->scCode, bp)) != 0) {
6389
		sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
6390
		*bpp = bp;
6391
		return icp->errc = rv;
6392
	}
6393
	bp += 2;
6394
	if ((rv = write_UInt8Number(p->scSize, bp)) != 0) {
6395
		sprintf(icp->err,"icmTextDescription_write: write_UInt8Number() failed");
6396
		*bpp = bp;
6397
		return icp->errc = rv;
6398
	}
6399
	bp += 1;
6400
	if (p->scSize > 0) {
6401
		if (p->scSize > 67) {
6402
			*bpp = bp;
6403
			sprintf(icp->err,"icmTextDescription_write: ScriptCode string too long");
6404
			return icp->errc = 1;
6405
		}
6406
		if (check_null_string((char *)p->scDesc,p->scSize)) {
6407
			*bpp = bp;
6408
			sprintf(icp->err,"icmTextDescription_write: ScriptCode string is not terminated");
6409
			return icp->errc = 1;
6410
		}
6411
		memcpy((void *)bp, (void *)p->scDesc, 67);
6412
	} else {
6413
		memset((void *)bp, 0, 67);
6414
	}
6415
	bp += 67;
6416
 
6417
	*bpp = bp;
6418
	return 0;
6419
}
6420
 
6421
/* Dump a text description of the object */
6422
static void icmTextDescription_dump(
6423
	icmBase *pp,
6424
	FILE *op,		/* Output to dump to */
6425
	int   verb		/* Verbosity level */
6426
) {
6427
	icmTextDescription *p = (icmTextDescription *)pp;
6428
	unsigned long i, r, c;
6429
 
6430
	if (verb <= 0)
6431
		return;
6432
 
6433
	fprintf(op,"TextDescription:\n");
6434
 
6435
	if (p->size > 0) {
6436
		unsigned long size = p->size > 0 ? p->size-1 : 0;
6437
		fprintf(op,"  ASCII data, length %lu chars:\n",p->size);
6438
 
6439
		i = 0;
6440
		for (r = 1;; r++) {		/* count rows */
6441
			if (i >= size) {
6442
				fprintf(op,"\n");
6443
				break;
6444
			}
6445
			if (r > 1 && verb < 2) {
6446
				fprintf(op,"...\n");
6447
				break;			/* Print 1 row if not verbose */
6448
			}
6449
			c = 1;
6450
			fprintf(op,"    0x%04lx: ",i);
6451
			c += 10;
6452
			while (i < size && c < 75) {
6453
				if (isprint(p->desc[i])) {
6454
					fprintf(op,"%c",p->desc[i]);
6455
					c++;
6456
				} else {
6457
					fprintf(op,"\\%03o",p->desc[i]);
6458
					c += 4;
6459
				}
6460
				i++;
6461
			}
6462
			if (i < size)
6463
				fprintf(op,"\n");
6464
		}
6465
	} else {
6466
		fprintf(op,"  No ASCII data\n");
6467
	}
6468
 
6469
	/* Can't dump Unicode or ScriptCode as text with portable code */
6470
	if (p->ucSize > 0) {
6471
		unsigned long size = p->ucSize;
6472
		fprintf(op,"  Unicode Data, Language code 0x%x, length %lu chars\n",
6473
		        p->ucLangCode, p->ucSize);
6474
		i = 0;
6475
		for (r = 1;; r++) {		/* count rows */
6476
			if (i >= size) {
6477
				fprintf(op,"\n");
6478
				break;
6479
			}
6480
			if (r > 1 && verb < 2) {
6481
				fprintf(op,"...\n");
6482
				break;			/* Print 1 row if not verbose */
6483
			}
6484
			c = 1;
6485
			fprintf(op,"    0x%04lx: ",i);
6486
			c += 10;
6487
			while (i < size && c < 75) {
6488
				fprintf(op,"%04x ",p->ucDesc[i]);
6489
				c += 5;
6490
				i++;
6491
			}
6492
			if (i < size)
6493
				fprintf(op,"\n");
6494
		}
6495
	} else {
6496
		fprintf(op,"  No Unicode data\n");
6497
	}
6498
	if (p->scSize > 0) {
6499
		unsigned long size = p->scSize;
6500
		fprintf(op,"  ScriptCode Data, Code 0x%x, length %lu chars\n",
6501
		        p->scCode, p->scSize);
6502
		i = 0;
6503
		for (r = 1;; r++) {		/* count rows */
6504
			if (i >= size) {
6505
				fprintf(op,"\n");
6506
				break;
6507
			}
6508
			if (r > 1 && verb < 2) {
6509
				fprintf(op,"...\n");
6510
				break;			/* Print 1 row if not verbose */
6511
			}
6512
			c = 1;
6513
			fprintf(op,"    0x%04lx: ",i);
6514
			c += 10;
6515
			while (i < size && c < 75) {
6516
				fprintf(op,"%02x ",p->scDesc[i]);
6517
				c += 3;
6518
				i++;
6519
			}
6520
			if (i < size)
6521
				fprintf(op,"\n");
6522
		}
6523
	} else {
6524
		fprintf(op,"  No ScriptCode data\n");
6525
	}
6526
}
6527
 
6528
/* Allocate variable sized data elements */
6529
static int icmTextDescription_allocate(
6530
	icmBase *pp
6531
) {
6532
	icmTextDescription *p = (icmTextDescription *)pp;
6533
	icc *icp = p->icp;
6534
 
6535
	if (p->size != p->_size) {
6536
		if (p->desc != NULL)
6537
			icp->al->free(icp->al, p->desc);
6538
		if ((p->desc = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) {
6539
			sprintf(icp->err,"icmTextDescription_alloc: malloc() of Ascii description failed");
6540
			return icp->errc = 2;
6541
		}
6542
		p->_size = p->size;
6543
	}
6544
	if (p->ucSize != p->uc_size) {
6545
		if (p->ucDesc != NULL)
6546
			icp->al->free(icp->al, p->ucDesc);
6547
		if ((p->ucDesc = (ORD16 *) icp->al->malloc(icp->al, p->ucSize * sizeof(ORD16))) == NULL) {
6548
			sprintf(icp->err,"icmTextDescription_alloc: malloc() of Unicode description failed");
6549
			return icp->errc = 2;
6550
		}
6551
		p->uc_size = p->ucSize;
6552
	}
6553
	return 0;
6554
}
6555
 
6556
/* Free all variable sized elements */
6557
static void icmTextDescription_unallocate(
6558
	icmTextDescription *p
6559
) {
6560
	icc *icp = p->icp;
6561
 
6562
	if (p->desc != NULL)
6563
		icp->al->free(icp->al, p->desc);
6564
	if (p->ucDesc != NULL)
6565
		icp->al->free(icp->al, p->ucDesc);
6566
}
6567
 
6568
/* Free all storage in the object */
6569
static void icmTextDescription_delete(
6570
	icmBase *pp
6571
) {
6572
	icmTextDescription *p = (icmTextDescription *)pp;
6573
	icc *icp = p->icp;
6574
 
6575
	icmTextDescription_unallocate(p);
6576
	icp->al->free(icp->al, p);
6577
}
6578
 
6579
/* Initialze a named object */
6580
static void icmTextDescription_init(
6581
	icmTextDescription *p,
6582
	icc *icp
6583
) {
6584
	memset((void *)p, 0, sizeof(icmTextDescription));	/* Imitate calloc */
6585
 
6586
	p->ttype    = icSigTextDescriptionType;
6587
	p->refcount = 1;
6588
	p->get_size = icmTextDescription_get_size;
6589
	p->read     = icmTextDescription_read;
6590
	p->write    = icmTextDescription_write;
6591
	p->dump     = icmTextDescription_dump;
6592
	p->allocate = icmTextDescription_allocate;
6593
	p->del      = icmTextDescription_delete;
6594
	p->icp      = icp;
6595
 
6596
	p->core_read  = icmTextDescription_core_read;
6597
	p->core_write = icmTextDescription_core_write;
6598
}
6599
 
6600
/* Create an empty object. Return null on error */
6601
static icmBase *new_icmTextDescription(
6602
	icc *icp
6603
) {
6604
	icmTextDescription *p;
6605
	if ((p = (icmTextDescription *) icp->al->calloc(icp->al,1,sizeof(icmTextDescription))) == NULL)
6606
		return NULL;
6607
 
6608
	icmTextDescription_init(p,icp);
6609
	return (icmBase *)p;
6610
}
6611
 
6612
/* ---------------------------------------------------------- */
6613
 
6614
/* Support for icmDescStruct */
6615
 
6616
/* Return the number of bytes needed to write this tag */
6617
static unsigned int icmDescStruct_get_size(
6618
	icmDescStruct *p
6619
) {
6620
	unsigned int len = 0;
6621
	len += 20;				/* 20 bytes for header info */
6622
	len += p->device.get_size((icmBase *)&p->device);
6623
	len += p->model.get_size((icmBase *)&p->model);
6624
	return len;
6625
}
6626
 
6627
/* read the object, return 0 on success, error code on fail */
6628
static int icmDescStruct_read(
6629
	icmDescStruct *p,
6630
	char **bpp,				/* Pointer to buffer pointer, returns next after read */
6631
	char *end				/* Pointer to past end of read buffer */
6632
) {
6633
	icc *icp = p->icp;
6634
	char *bp = *bpp;
6635
	int rv = 0;
6636
 
6637
	if ((bp + 20) > end) {
6638
		sprintf(icp->err,"icmDescStruct_read: Data too short read header");
6639
		*bpp = bp;
6640
		return icp->errc = 1;
6641
	}
6642
 
6643
    p->deviceMfg = read_SInt32Number(bp + 0);
6644
    p->deviceModel = read_UInt32Number(bp + 4);
6645
    read_UInt64Number(&p->attributes, bp + 8);
6646
	p->technology = read_UInt32Number(bp + 16);
6647
	*bpp = bp += 20;
6648
 
6649
	/* Read the device text description */
6650
	if ((rv = p->device.core_read(&p->device, bpp, end)) != 0) {
6651
		return rv;
6652
	}
6653
 
6654
	/* Read the model text description */
6655
	if ((rv = p->model.core_read(&p->model, bpp, end)) != 0) {
6656
		return rv;
6657
	}
6658
 
6659
	return 0;
6660
}
6661
 
6662
/* Write the contents of the object. Return 0 on sucess, error code on failure */
6663
static int icmDescStruct_write(
6664
	icmDescStruct *p,
6665
	char **bpp				/* Pointer to buffer pointer, returns next after read */
6666
) {
6667
	icc *icp = p->icp;
6668
	char *bp = *bpp;
6669
	int rv = 0;
6670
 
6671
    if ((rv = write_SInt32Number(p->deviceMfg, bp + 0)) != 0) {
6672
		sprintf(icp->err,"icmDescStruct_write: write_SInt32Number() failed");
6673
		*bpp = bp;
6674
		return icp->errc = rv;
6675
	}
6676
    if ((rv = write_UInt32Number(p->deviceModel, bp + 4)) != 0) {
6677
		sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
6678
		*bpp = bp;
6679
		return icp->errc = rv;
6680
	}
6681
    if ((rv = write_UInt64Number(&p->attributes, bp + 8)) != 0) {
6682
		sprintf(icp->err,"icmDescStruct_write: write_UInt64Number() failed");
6683
		*bpp = bp;
6684
		return icp->errc = rv;
6685
	}
6686
	if ((rv = write_UInt32Number(p->technology, bp + 16)) != 0) {
6687
		sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
6688
		*bpp = bp;
6689
		return icp->errc = rv;
6690
	}
6691
	*bpp = bp += 20;
6692
 
6693
	/* Write the device text description */
6694
	if ((rv = p->device.core_write(&p->device, bpp)) != 0) {
6695
		return rv;
6696
	}
6697
 
6698
	/* Write the model text description */
6699
	if ((rv = p->model.core_write(&p->model, bpp)) != 0) {
6700
		return rv;
6701
	}
6702
 
6703
	return 0;
6704
}
6705
 
6706
/* Dump a text description of the object */
6707
static void icmDescStruct_dump(
6708
	icmDescStruct *p,
6709
	FILE *op,		/* Output to dump to */
6710
	int   verb,		/* Verbosity level */
6711
	int   index		/* Description index */
6712
) {
6713
	if (verb <= 0)
6714
		return;
6715
 
6716
	fprintf(op,"DescStruct %u:\n",index);
6717
	if (verb >= 1) {
6718
		fprintf(op,"  Dev. Mnfctr.    = %s\n",tag2str(p->deviceMfg));	/* ~~~ */
6719
		fprintf(op,"  Dev. Model      = %s\n",tag2str(p->deviceModel));	/* ~~~ */
6720
		fprintf(op,"  Dev. Attrbts    = %s\n", string_DeviceAttributes(p->attributes.l));
6721
		fprintf(op,"  Dev. Technology = %s\n", string_TechnologySignature(p->technology));
6722
		p->device.dump((icmBase *)&p->device, op,verb);
6723
		p->model.dump((icmBase *)&p->model, op,verb);
6724
		fprintf(op,"\n");
6725
	}
6726
}
6727
 
6728
/* Allocate variable sized data elements (ie. descriptions) */
6729
static int icmDescStruct_allocate(
6730
	icmDescStruct *p
6731
) {
6732
	int rv;
6733
 
6734
	if ((rv = p->device.allocate((icmBase *)&p->device)) != 0) {
6735
		return rv;
6736
	}
6737
	if ((rv = p->model.allocate((icmBase *)&p->model)) != 0) {
6738
		return rv;
6739
	}
6740
	return 0;
6741
}
6742
 
6743
/* Free all storage in the object */
6744
static void icmDescStruct_delete(
6745
	icmDescStruct *p
6746
) {
6747
	icmTextDescription_unallocate(&p->device);
6748
	icmTextDescription_unallocate(&p->model);
6749
}
6750
 
6751
/* Init a DescStruct object */
6752
static void icmDescStruct_init(
6753
	icmDescStruct *p,
6754
	icc *icp
6755
) {
6756
 
6757
	p->allocate = icmDescStruct_allocate;
6758
	p->icp = icp;
6759
 
6760
	icmTextDescription_init(&p->device, icp);
6761
	icmTextDescription_init(&p->model, icp);
6762
}
6763
 
6764
/* - - - - - - - - - - - - - - - */
6765
/* icmProfileSequenceDesc object */
6766
 
6767
/* Return the number of bytes needed to write this tag */
6768
static unsigned int icmProfileSequenceDesc_get_size(
6769
	icmBase *pp
6770
) {
6771
	icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6772
	unsigned int len = 0;
6773
	unsigned int i;
6774
	len += 12;				/* 8 bytes for tag, padding and count */
6775
	for (i = 0; i < p->count; i++) {	/* All the description structures */
6776
		len += icmDescStruct_get_size(&p->data[i]);
6777
	}
6778
	return len;
6779
}
6780
 
6781
/* read the object, return 0 on success, error code on fail */
6782
static int icmProfileSequenceDesc_read(
6783
	icmBase *pp,
6784
	unsigned long len,		/* tag length */
6785
	unsigned long of		/* start offset within file */
6786
) {
6787
	icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6788
	icc *icp = p->icp;
6789
	unsigned long i;
6790
	char *bp, *buf, *end;
6791
	int rv = 0;
6792
 
6793
	if (len < 12) {
6794
		sprintf(icp->err,"icmProfileSequenceDesc_read: Tag too small to be legal");
6795
		return icp->errc = 1;
6796
	}
6797
 
6798
	/* Allocate a file read buffer */
6799
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6800
		sprintf(icp->err,"icmProfileSequenceDesc_read: malloc() failed");
6801
		return icp->errc = 2;
6802
	}
6803
	bp = buf;
6804
	end = buf + len;
6805
 
6806
	/* Read portion of file into buffer */
6807
	if (   icp->fp->seek(icp->fp, of) != 0
6808
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
6809
		sprintf(icp->err,"icmProfileSequenceDesc_read: fseek() or fread() failed");
6810
		icp->al->free(icp->al, buf);
6811
		return icp->errc = 1;
6812
	}
6813
 
6814
	/* Read type descriptor from the buffer */
6815
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
6816
		sprintf(icp->err,"icmProfileSequenceDesc_read: Wrong tag type for icmProfileSequenceDesc");
6817
		icp->al->free(icp->al, buf);
6818
		return icp->errc = 1;
6819
	}
6820
	bp += 8;	/* Skip padding */
6821
 
6822
	p->count = read_UInt32Number(bp);	/* Number of sequence descriptions */
6823
	bp += 4;
6824
 
6825
	/* Read all the sequence descriptions */
6826
	if ((rv = p->allocate((icmBase *)p)) != 0) {
6827
		icp->al->free(icp->al, buf);
6828
		return rv;
6829
	}
6830
	for (i = 0; i < p->count; i++) {
6831
		if ((rv = icmDescStruct_read(&p->data[i], &bp, end)) != 0) {
6832
			icp->al->free(icp->al, buf);
6833
			return rv;
6834
		}
6835
	}
6836
 
6837
	icp->al->free(icp->al, buf);
6838
	return 0;
6839
}
6840
 
6841
/* Write the contents of the object. Return 0 on sucess, error code on failure */
6842
static int icmProfileSequenceDesc_write(
6843
	icmBase *pp,
6844
	unsigned long of			/* File offset to write from */
6845
) {
6846
	icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6847
	icc *icp = p->icp;
6848
	unsigned long i;
6849
	unsigned int len;
6850
	char *bp, *buf;		/* Buffer to write from */
6851
	int rv = 0;
6852
 
6853
	/* Allocate a file write buffer */
6854
	len = p->get_size((icmBase *)p);
6855
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
6856
		sprintf(icp->err,"icmProfileSequenceDesc_write malloc() failed");
6857
		return icp->errc = 2;
6858
	}
6859
	bp = buf;
6860
 
6861
	/* Write type descriptor to the buffer */
6862
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
6863
		sprintf(icp->err,"icmProfileSequenceDesc_write: write_SInt32Number() failed");
6864
		icp->al->free(icp->al, buf);
6865
		return icp->errc = rv;
6866
	}
6867
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
6868
 
6869
	if ((rv = write_UInt32Number(p->count,bp+8)) != 0) {
6870
		sprintf(icp->err,"icmProfileSequenceDesc_write: write_UInt32Number() failed");
6871
		icp->al->free(icp->al, buf);
6872
		return icp->errc = rv;
6873
	}
6874
	bp = bp + 12;
6875
 
6876
	/* Write all the description structures */
6877
	for (i = 0; i < p->count; i++) {
6878
		if ((rv = icmDescStruct_write(&p->data[i], &bp)) != 0) {
6879
			icp->al->free(icp->al, buf);
6880
			return rv;
6881
		}
6882
	}
6883
 
6884
	/* Write to the file */
6885
	if (   icp->fp->seek(icp->fp, of) != 0
6886
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
6887
		sprintf(icp->err,"icmProfileSequenceDesc_write fseek() or fwrite() failed");
6888
		icp->al->free(icp->al, buf);
6889
		return icp->errc = 2;
6890
	}
6891
	icp->al->free(icp->al, buf);
6892
	return 0;
6893
}
6894
 
6895
/* Dump a text description of the object */
6896
static void icmProfileSequenceDesc_dump(
6897
	icmBase *pp,
6898
	FILE *op,		/* Output to dump to */
6899
	int   verb		/* Verbosity level */
6900
) {
6901
	icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6902
	if (verb <= 0)
6903
		return;
6904
 
6905
	fprintf(op,"ProfileSequenceDesc:\n");
6906
	fprintf(op,"  No. elements = %u\n",p->count);
6907
	if (verb >= 2) {
6908
		unsigned long i;
6909
		for (i = 0; i < p->count; i++)
6910
			icmDescStruct_dump(&p->data[i], op, verb-1, i);
6911
	}
6912
}
6913
 
6914
/* Allocate variable sized data elements (ie. count of profile descriptions) */
6915
static int icmProfileSequenceDesc_allocate(
6916
	icmBase *pp
6917
) {
6918
	icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6919
	icc *icp = p->icp;
6920
	unsigned int i;
6921
 
6922
	if (p->count != p->_count) {
6923
		if (p->data != NULL)
6924
			icp->al->free(icp->al, p->data);
6925
		if ((p->data = (icmDescStruct *) icp->al->malloc(icp->al, p->count * sizeof(icmDescStruct))) == NULL) {
6926
			sprintf(icp->err,"icmProfileSequenceDesc_allocate Allocation of DescStruct array failed");
6927
			return icp->errc = 2;
6928
		}
6929
		/* Now init the DescStructs */
6930
		for (i = 0; i < p->count; i++) {
6931
			icmDescStruct_init(&p->data[i], icp);
6932
		}
6933
		p->_count = p->count;
6934
	}
6935
	return 0;
6936
}
6937
 
6938
/* Free all storage in the object */
6939
static void icmProfileSequenceDesc_delete(
6940
	icmBase *pp
6941
) {
6942
	icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
6943
	icc *icp = p->icp;
6944
	unsigned int i;
6945
 
6946
	for (i = 0; i < p->count; i++) {
6947
		icmDescStruct_delete(&p->data[i]);	/* Free allocated contents */
6948
	}
6949
	if (p->data != NULL)
6950
		icp->al->free(icp->al, p->data);
6951
	icp->al->free(icp->al, p);
6952
}
6953
 
6954
/* Create an empty object. Return null on error */
6955
static icmBase *new_icmProfileSequenceDesc(
6956
	icc *icp
6957
) {
6958
	icmProfileSequenceDesc *p;
6959
	if ((p = (icmProfileSequenceDesc *) icp->al->calloc(icp->al,1,sizeof(icmProfileSequenceDesc))) == NULL)
6960
		return NULL;
6961
	p->ttype    = icSigProfileSequenceDescType;
6962
	p->refcount = 1;
6963
	p->get_size = icmProfileSequenceDesc_get_size;
6964
	p->read     = icmProfileSequenceDesc_read;
6965
	p->write    = icmProfileSequenceDesc_write;
6966
	p->dump     = icmProfileSequenceDesc_dump;
6967
	p->allocate = icmProfileSequenceDesc_allocate;
6968
	p->del      = icmProfileSequenceDesc_delete;
6969
	p->icp      = icp;
6970
 
6971
	return (icmBase *)p;
6972
}
6973
 
6974
/* ---------------------------------------------------------- */
6975
/* Signature */
6976
 
6977
/* Return the number of bytes needed to write this tag */
6978
static unsigned int icmSignature_get_size(
6979
	icmBase *pp
6980
) {
6981
	unsigned int len = 0;
6982
	len += 8;			/* 8 bytes for tag and padding */
6983
	len += 4;			/* 4 for signature */
6984
	return len;
6985
}
6986
 
6987
/* read the object, return 0 on success, error code on fail */
6988
static int icmSignature_read(
6989
	icmBase *pp,
6990
	unsigned long len,		/* tag length */
6991
	unsigned long of		/* start offset within file */
6992
) {
6993
	icmSignature *p = (icmSignature *)pp;
6994
	icc *icp = p->icp;
6995
	char *bp, *buf;
6996
 
6997
	if (len < 12) {
6998
		sprintf(icp->err,"icmSignature_read: Tag too small to be legal");
6999
		return icp->errc = 1;
7000
	}
7001
 
7002
	/* Allocate a file read buffer */
7003
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7004
		sprintf(icp->err,"icmSignature_read: malloc() failed");
7005
		return icp->errc = 2;
7006
	}
7007
	bp = buf;
7008
 
7009
	/* Read portion of file into buffer */
7010
	if (   icp->fp->seek(icp->fp, of) != 0
7011
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
7012
		sprintf(icp->err,"icmSignature_read: fseek() or fread() failed");
7013
		icp->al->free(icp->al, buf);
7014
		return icp->errc = 1;
7015
	}
7016
 
7017
	/* Read type descriptor from the buffer */
7018
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7019
		sprintf(icp->err,"icmSignaturSignatureng tag type for icmSignature");
7020
		icp->al->free(icp->al, buf);
7021
		return icp->errc = 1;
7022
	}
7023
 
7024
	/* Read the encoded measurement geometry */
7025
	p->sig = (icTechnologySignature)read_SInt32Number(bp + 8);
7026
 
7027
	icp->al->free(icp->al, buf);
7028
	return 0;
7029
}
7030
 
7031
/* Write the contents of the object. Return 0 on sucess, error code on failure */
7032
static int icmSignature_write(
7033
	icmBase *pp,
7034
	unsigned long of			/* File offset to write from */
7035
) {
7036
	icmSignature *p = (icmSignature *)pp;
7037
	icc *icp = p->icp;
7038
	unsigned int len;
7039
	char *bp, *buf;		/* Buffer to write from */
7040
	int rv = 0;
7041
 
7042
	/* Allocate a file write buffer */
7043
	len = p->get_size((icmBase *)p);
7044
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7045
		sprintf(icp->err,"icmSignature_write malloc() failed");
7046
		return icp->errc = 2;
7047
	}
7048
	bp = buf;
7049
 
7050
	/* Write type descriptor to the buffer */
7051
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7052
		sprintf(icp->err,"icmSignature_write: write_SInt32Number() failed");
7053
		icp->al->free(icp->al, buf);
7054
		return icp->errc = rv;
7055
	}
7056
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
7057
 
7058
	/* Write the signature */
7059
	if ((rv = write_SInt32Number((int)p->sig, bp + 8)) != 0) {
7060
		sprintf(icp->err,"icmSignaturea_write: write_SInt32Number() failed");
7061
		icp->al->free(icp->al, buf);
7062
		return icp->errc = rv;
7063
	}
7064
 
7065
	/* Write to the file */
7066
	if (   icp->fp->seek(icp->fp, of) != 0
7067
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
7068
		sprintf(icp->err,"icmSignature_write fseek() or fwrite() failed");
7069
		icp->al->free(icp->al, buf);
7070
		return icp->errc = 2;
7071
	}
7072
	icp->al->free(icp->al, buf);
7073
	return 0;
7074
}
7075
 
7076
/* Dump a text description of the object */
7077
static void icmSignature_dump(
7078
	icmBase *pp,
7079
	FILE *op,		/* Output to dump to */
7080
	int   verb		/* Verbosity level */
7081
) {
7082
	icmSignature *p = (icmSignature *)pp;
7083
	if (verb <= 0)
7084
		return;
7085
 
7086
	fprintf(op,"Signature\n");
7087
	fprintf(op,"  Technology = %s\n", string_TechnologySignature(p->sig));
7088
}
7089
 
7090
/* Allocate variable sized data elements */
7091
static int icmSignature_allocate(
7092
	icmBase *pp
7093
) {
7094
	/* Nothing to do */
7095
	return 0;
7096
}
7097
 
7098
/* Free all storage in the object */
7099
static void icmSignature_delete(
7100
	icmBase *pp
7101
) {
7102
	icmSignature *p = (icmSignature *)pp;
7103
	icc *icp = p->icp;
7104
 
7105
	icp->al->free(icp->al, p);
7106
}
7107
 
7108
/* Create an empty object. Return null on error */
7109
static icmBase *new_icmSignature(
7110
	icc *icp
7111
) {
7112
	icmSignature *p;
7113
	if ((p = (icmSignature *) icp->al->calloc(icp->al,1,sizeof(icmSignature))) == NULL)
7114
		return NULL;
7115
	p->ttype    = icSigSignatureType;
7116
	p->refcount = 1;
7117
	p->get_size = icmSignature_get_size;
7118
	p->read     = icmSignature_read;
7119
	p->write    = icmSignature_write;
7120
	p->dump     = icmSignature_dump;
7121
	p->allocate = icmSignature_allocate;
7122
	p->del      = icmSignature_delete;
7123
	p->icp      = icp;
7124
 
7125
	return (icmBase *)p;
7126
}
7127
 
7128
/* ---------------------------------------------------------- */
7129
 
7130
/* Data conversion support functions */
7131
static int read_ScreeningData(icmScreeningData *p, char *d) {
7132
	p->frequency = read_S15Fixed16Number(d + 0);
7133
	p->angle     = read_S15Fixed16Number(d + 4);
7134
	p->spotShape = (icSpotShape)read_SInt32Number(d + 8);
7135
	return 0;
7136
}
7137
 
7138
static int write_ScreeningData(icmScreeningData *p, char *d) {
7139
	int rv;
7140
	if ((rv = write_S15Fixed16Number(p->frequency, d + 0)) != 0)
7141
		return rv;
7142
	if ((rv = write_S15Fixed16Number(p->angle, d + 4)) != 0)
7143
		return rv;
7144
	if ((rv = write_SInt32Number((int)p->spotShape, d + 8)) != 0)
7145
		return rv;
7146
	return 0;
7147
}
7148
 
7149
 
7150
/* icmScreening object */
7151
 
7152
/* Return the number of bytes needed to write this tag */
7153
static unsigned int icmScreening_get_size(
7154
	icmBase *pp
7155
) {
7156
	icmScreening *p = (icmScreening *)pp;
7157
	unsigned int len = 0;
7158
	len += 16;				/* 16 bytes for tag, padding, flag & channeles */
7159
	len += p->channels * 12;	/* 12 bytes for each channel */
7160
	return len;
7161
}
7162
 
7163
/* read the object, return 0 on success, error code on fail */
7164
static int icmScreening_read(
7165
	icmBase *pp,
7166
	unsigned long len,		/* tag length */
7167
	unsigned long of		/* start offset within file */
7168
) {
7169
	icmScreening *p = (icmScreening *)pp;
7170
	icc *icp = p->icp;
7171
	int rv = 0;
7172
	unsigned long i;
7173
	char *bp, *buf, *end;
7174
 
7175
	if (len < 12) {
7176
		sprintf(icp->err,"icmScreening_read: Tag too small to be legal");
7177
		return icp->errc = 1;
7178
	}
7179
 
7180
	/* Allocate a file read buffer */
7181
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7182
		sprintf(icp->err,"icmScreening_read: malloc() failed");
7183
		return icp->errc = 2;
7184
	}
7185
	bp = buf;
7186
	end = buf + len;
7187
 
7188
	/* Read portion of file into buffer */
7189
	if (   icp->fp->seek(icp->fp, of) != 0
7190
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
7191
		sprintf(icp->err,"icmScreening_read: fseek() or fread() failed");
7192
		icp->al->free(icp->al, buf);
7193
		return icp->errc = 1;
7194
	}
7195
 
7196
	/* Read type descriptor from the buffer */
7197
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7198
		sprintf(icp->err,"icmScreening_read: Wrong tag type for icmScreening");
7199
		icp->al->free(icp->al, buf);
7200
		return icp->errc = 1;
7201
	}
7202
	p->screeningFlag = read_UInt32Number(bp+8);		/* Flags */
7203
	p->channels      = read_UInt32Number(bp+12);	/* Number of channels */
7204
	bp = bp + 16;
7205
 
7206
	if ((rv = p->allocate((icmBase *)p)) != 0) {
7207
		icp->al->free(icp->al, buf);
7208
		return rv;
7209
	}
7210
 
7211
	/* Read all the data from the buffer */
7212
	for (i = 0; i < p->channels; i++, bp += 12) {
7213
		if ((bp + 12) > end) {
7214
			sprintf(icp->err,"icmScreening_read: Data too short to read Screening Data");
7215
			icp->al->free(icp->al, buf);
7216
			return icp->errc = 1;
7217
		}
7218
		read_ScreeningData(&p->data[i], bp);
7219
	}
7220
	icp->al->free(icp->al, buf);
7221
	return 0;
7222
}
7223
 
7224
/* Write the contents of the object. Return 0 on sucess, error code on failure */
7225
static int icmScreening_write(
7226
	icmBase *pp,
7227
	unsigned long of			/* File offset to write from */
7228
) {
7229
	icmScreening *p = (icmScreening *)pp;
7230
	icc *icp = p->icp;
7231
	unsigned long i;
7232
	unsigned int len;
7233
	char *bp, *buf;		/* Buffer to write from */
7234
	int rv = 0;
7235
 
7236
	/* Allocate a file write buffer */
7237
	len = p->get_size((icmBase *)p);
7238
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7239
		sprintf(icp->err,"icmScreening_write malloc() failed");
7240
		return icp->errc = 2;
7241
	}
7242
	bp = buf;
7243
 
7244
	/* Write type descriptor to the buffer */
7245
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7246
		sprintf(icp->err,"icmScreening_write: write_SInt32Number() failed");
7247
		icp->al->free(icp->al, buf);
7248
		return icp->errc = rv;
7249
	}
7250
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
7251
 
7252
	if ((rv = write_UInt32Number(p->screeningFlag,bp+8)) != 0) {
7253
			sprintf(icp->err,"icmScreening_write: write_UInt32Number() failed");
7254
			icp->al->free(icp->al, buf);
7255
			return icp->errc = rv;
7256
		}
7257
	if ((rv = write_UInt32Number(p->channels,bp+12)) != 0) {
7258
			sprintf(icp->err,"icmScreening_write: write_UInt32NumberXYZumber() failed");
7259
			icp->al->free(icp->al, buf);
7260
			return icp->errc = rv;
7261
		}
7262
	bp = bp + 16;
7263
 
7264
	/* Write all the data to the buffer */
7265
	for (i = 0; i < p->channels; i++, bp += 12) {
7266
		if ((rv = write_ScreeningData(&p->data[i],bp)) != 0) {
7267
			sprintf(icp->err,"icmScreening_write: write_ScreeningData() failed");
7268
			icp->al->free(icp->al, buf);
7269
			return icp->errc = rv;
7270
		}
7271
	}
7272
 
7273
	/* Write to the file */
7274
	if (   icp->fp->seek(icp->fp, of) != 0
7275
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
7276
		sprintf(icp->err,"icmScreening_write fseek() or fwrite() failed");
7277
		icp->al->free(icp->al, buf);
7278
		return icp->errc = 2;
7279
	}
7280
	icp->al->free(icp->al, buf);
7281
	return 0;
7282
}
7283
 
7284
/* Dump a text description of the object */
7285
static void icmScreening_dump(
7286
	icmBase *pp,
7287
	FILE *op,		/* Output to dump to */
7288
	int   verb		/* Verbosity level */
7289
) {
7290
	icmScreening *p = (icmScreening *)pp;
7291
	if (verb <= 0)
7292
		return;
7293
 
7294
	fprintf(op,"Screening:\n");
7295
	fprintf(op,"  Flags = %s\n", string_ScreenEncodings(p->screeningFlag));
7296
	fprintf(op,"  No. channels = %u\n",p->channels);
7297
	if (verb >= 2) {
7298
		unsigned long i;
7299
		for (i = 0; i < p->channels; i++) {
7300
			fprintf(op,"    %lu:\n",i);
7301
			fprintf(op,"      Frequency:  %f\n",p->data[i].frequency);
7302
			fprintf(op,"      Angle:      %f\n",p->data[i].angle);
7303
			fprintf(op,"      Spot shape: %s\n", string_SpotShape(p->data[i].spotShape));
7304
		}
7305
	}
7306
}
7307
 
7308
/* Allocate variable sized data elements */
7309
static int icmScreening_allocate(
7310
	icmBase *pp
7311
) {
7312
	icmScreening *p = (icmScreening *)pp;
7313
	icc *icp = p->icp;
7314
 
7315
	if (p->channels != p->_channels) {
7316
		if (p->data != NULL)
7317
			icp->al->free(icp->al, p->data);
7318
		if ((p->data = (icmScreeningData *) icp->al->malloc(icp->al, p->channels * sizeof(icmScreeningData))) == NULL) {
7319
			sprintf(icp->err,"icmScreening_alloc: malloc() of icmScreening data failed");
7320
			return icp->errc = 2;
7321
		}
7322
		p->_channels = p->channels;
7323
	}
7324
	return 0;
7325
}
7326
 
7327
/* Free all storage in the object */
7328
static void icmScreening_delete(
7329
	icmBase *pp
7330
) {
7331
	icmScreening *p = (icmScreening *)pp;
7332
	icc *icp = p->icp;
7333
 
7334
	if (p->data != NULL)
7335
		icp->al->free(icp->al, p->data);
7336
	icp->al->free(icp->al, p);
7337
}
7338
 
7339
/* Create an empty object. Return null on error */
7340
static icmBase *new_icmScreening(
7341
	icc *icp
7342
) {
7343
	icmScreening *p;
7344
	if ((p = (icmScreening *) icp->al->calloc(icp->al,1,sizeof(icmScreening))) == NULL)
7345
		return NULL;
7346
	p->ttype    = icSigScreeningType;
7347
	p->refcount = 1;
7348
	p->get_size = icmScreening_get_size;
7349
	p->read     = icmScreening_read;
7350
	p->write    = icmScreening_write;
7351
	p->dump     = icmScreening_dump;
7352
	p->allocate = icmScreening_allocate;
7353
	p->del      = icmScreening_delete;
7354
	p->icp      = icp;
7355
 
7356
	return (icmBase *)p;
7357
}
7358
 
7359
/* ---------------------------------------------------------- */
7360
/* icmUcrBg object */
7361
 
7362
/* Return the number of bytes needed to write this tag */
7363
static unsigned int icmUcrBg_get_size(
7364
	icmBase *pp
7365
) {
7366
	icmUcrBg *p = (icmUcrBg *)pp;
7367
	unsigned int len = 0;
7368
	len += 8;			/* 8 bytes for tag and padding */
7369
	len += 4 + p->UCRcount * 2;	/* Undercolor Removal */
7370
	len += 4 + p->BGcount * 2;	/* Black Generation */
7371
	len += p->size;				/* Description string */
7372
	return len;
7373
}
7374
 
7375
/* read the object, return 0 on success, error code on fail */
7376
static int icmUcrBg_read(
7377
	icmBase *pp,
7378
	unsigned long len,		/* tag length */
7379
	unsigned long of		/* start offset within file */
7380
) {
7381
	icmUcrBg *p = (icmUcrBg *)pp;
7382
	icc *icp = p->icp;
7383
	unsigned long i;
7384
	int rv = 0;
7385
	char *bp, *buf, *end;
7386
 
7387
	if (len < 16) {
7388
		sprintf(icp->err,"icmUcrBg_read: Tag too small to be legal");
7389
		return icp->errc = 1;
7390
	}
7391
 
7392
	/* Allocate a file read buffer */
7393
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7394
		sprintf(icp->err,"icmUcrBg_read: malloc() failed");
7395
		return icp->errc = 2;
7396
	}
7397
	bp = buf;
7398
	end = buf + len;
7399
 
7400
	/* Read portion of file into buffer */
7401
	if (   icp->fp->seek(icp->fp, of) != 0
7402
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
7403
		sprintf(icp->err,"icmUcrBg_read: fseek() or fread() failed");
7404
		icp->al->free(icp->al, buf);
7405
		return icp->errc = 1;
7406
	}
7407
 
7408
	/* Read type descriptor from the buffer */
7409
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7410
		sprintf(icp->err,"icmUcrBg_read: Wrong tag type for icmUcrBg");
7411
		icp->al->free(icp->al, buf);
7412
		return icp->errc = 1;
7413
	}
7414
	p->UCRcount = read_UInt32Number(bp+8);	/* First curve count */
7415
	bp = bp + 12;
7416
 
7417
	if (p->UCRcount > 0) {
7418
		if ((rv = p->allocate((icmBase *)p)) != 0) {
7419
			icp->al->free(icp->al, buf);
7420
			return rv;
7421
		}
7422
		for (i = 0; i < p->UCRcount; i++, bp += 2) {
7423
			if ((bp + 2) > end) {
7424
				sprintf(icp->err,"icmUcrBg_read: Data too short to read UCR Data");
7425
				icp->al->free(icp->al, buf);
7426
				return icp->errc = 1;
7427
			}
7428
			if (p->UCRcount == 1)	/* % */
7429
				p->UCRcurve[i] = (double)read_UInt16Number(bp);
7430
			else					/* 0.0 - 1.0 */
7431
				p->UCRcurve[i] = read_DCS16Number(bp);
7432
		}
7433
	} else {
7434
		p->UCRcurve = NULL;
7435
	}
7436
 
7437
	if ((bp + 4) > end) {
7438
		sprintf(icp->err,"icmData_read: Data too short to read Black Gen count");
7439
		icp->al->free(icp->al, buf);
7440
		return icp->errc = 1;
7441
	}
7442
	p->BGcount = read_UInt32Number(bp);	/* First curve count */
7443
	bp += 4;
7444
 
7445
	if (p->BGcount > 0) {
7446
		if ((rv = p->allocate((icmBase *)p)) != 0) {
7447
			icp->al->free(icp->al, buf);
7448
			return rv;
7449
		}
7450
		for (i = 0; i < p->BGcount; i++, bp += 2) {
7451
			if ((bp + 2) > end) {
7452
				sprintf(icp->err,"icmUcrBg_read: Data too short to read BG Data");
7453
				icp->al->free(icp->al, buf);
7454
				return icp->errc = 1;
7455
			}
7456
			if (p->BGcount == 1)	/* % */
7457
				p->BGcurve[i] = (double)read_UInt16Number(bp);
7458
			else					/* 0.0 - 1.0 */
7459
				p->BGcurve[i] = read_DCS16Number(bp);
7460
		}
7461
	} else {
7462
		p->BGcurve = NULL;
7463
	}
7464
 
7465
	p->size = end - bp;		/* Nominal string length */
7466
	if (p->size > 0) {
7467
		if (check_null_string(bp, p->size) != 0) {
7468
			sprintf(icp->err,"icmUcrBg_read: string is not null terminated");
7469
			icp->al->free(icp->al, buf);
7470
			return icp->errc = 1;
7471
		}
7472
		p->size = strlen(bp) + 1;
7473
		if ((rv = p->allocate((icmBase *)p)) != 0) {
7474
			icp->al->free(icp->al, buf);
7475
			return rv;
7476
		}
7477
		memcpy((void *)p->string, (void *)bp, p->size);
7478
		bp += p->size;
7479
	} else {
7480
		p->string = NULL;
7481
	}
7482
 
7483
	icp->al->free(icp->al, buf);
7484
	return 0;
7485
}
7486
 
7487
/* Write the contents of the object. Return 0 on sucess, error code on failure */
7488
static int icmUcrBg_write(
7489
	icmBase *pp,
7490
	unsigned long of			/* File offset to write from */
7491
) {
7492
	icmUcrBg *p = (icmUcrBg *)pp;
7493
	icc *icp = p->icp;
7494
	unsigned long i;
7495
	unsigned int len;
7496
	char *bp, *buf;		/* Buffer to write from */
7497
	int rv = 0;
7498
 
7499
	/* Allocate a file write buffer */
7500
	len = p->get_size((icmBase *)p);
7501
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7502
		sprintf(icp->err,"icmUcrBg_write malloc() failed");
7503
		return icp->errc = 2;
7504
	}
7505
	bp = buf;
7506
 
7507
	/* Write type descriptor to the buffer */
7508
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7509
		sprintf(icp->err,"icmUcrBg_write: write_SInt32Number() failed");
7510
		icp->al->free(icp->al, buf);
7511
		return icp->errc = rv;
7512
	}
7513
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
7514
	bp = bp + 8;
7515
 
7516
	/* Write UCR curve */
7517
	if ((rv = write_UInt32Number(p->UCRcount,bp)) != 0) {
7518
		sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
7519
		icp->al->free(icp->al, buf);
7520
		return icp->errc = rv;
7521
	}
7522
	bp += 4;
7523
 
7524
	for (i = 0; i < p->UCRcount; i++, bp += 2) {
7525
		if (p->UCRcount == 1) { /* % */
7526
			if ((rv = write_UInt16Number((unsigned int)(p->UCRcurve[i]+0.5),bp)) != 0) {
7527
				sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
7528
				icp->al->free(icp->al, buf);
7529
				return icp->errc = rv;
7530
			}
7531
		} else {
7532
			if ((rv = write_DCS16Number(p->UCRcurve[i],bp)) != 0) {
7533
				sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->UCRcurve[i]);
7534
				icp->al->free(icp->al, buf);
7535
				return icp->errc = rv;
7536
			}
7537
		}
7538
	}
7539
 
7540
	/* Write BG curve */
7541
	if ((rv = write_UInt32Number(p->BGcount,bp)) != 0) {
7542
		sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
7543
		icp->al->free(icp->al, buf);
7544
		return icp->errc = rv;
7545
	}
7546
	bp += 4;
7547
 
7548
	for (i = 0; i < p->BGcount; i++, bp += 2) {
7549
		if (p->BGcount == 1) { /* % */
7550
			if ((rv = write_UInt16Number((unsigned int)(p->BGcurve[i]+0.5),bp)) != 0) {
7551
				sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
7552
				icp->al->free(icp->al, buf);
7553
				return icp->errc = rv;
7554
			}
7555
		} else {
7556
			if ((rv = write_DCS16Number(p->BGcurve[i],bp)) != 0) {
7557
				sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->BGcurve[i]);
7558
				icp->al->free(icp->al, buf);
7559
				return icp->errc = rv;
7560
			}
7561
		}
7562
	}
7563
 
7564
	if (p->string != NULL) {
7565
		if ((rv = check_null_string(p->string,p->size)) != 0) {
7566
			sprintf(icp->err,"icmUcrBg_write: text is not null terminated");
7567
			icp->al->free(icp->al, buf);
7568
			return icp->errc = 1;
7569
		}
7570
		memcpy((void *)bp, (void *)p->string, p->size);
7571
	}
7572
 
7573
	/* Write to the file */
7574
	if (   icp->fp->seek(icp->fp, of) != 0
7575
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
7576
		sprintf(icp->err,"icmUcrBg_write fseek() or fwrite() failed");
7577
		icp->al->free(icp->al, buf);
7578
		return icp->errc = 2;
7579
	}
7580
	icp->al->free(icp->al, buf);
7581
	return 0;
7582
}
7583
 
7584
/* Dump a text description of the object */
7585
static void icmUcrBg_dump(
7586
	icmBase *pp,
7587
	FILE *op,		/* Output to dump to */
7588
	int   verb		/* Verbosity level */
7589
) {
7590
	icmUcrBg *p = (icmUcrBg *)pp;
7591
	if (verb <= 0)
7592
		return;
7593
 
7594
	fprintf(op,"Undercolor Removal Curve & Black Generation:\n");
7595
 
7596
	if (p->UCRcount == 0) {
7597
		fprintf(op,"  UCR: Not specified\n");
7598
	} else if (p->UCRcount == 1) {
7599
		fprintf(op,"  UCR: %f%%\n",p->UCRcurve[0]);
7600
	} else {
7601
		fprintf(op,"  UCR curve no. elements = %u\n",p->UCRcount);
7602
		if (verb >= 2) {
7603
			unsigned long i;
7604
			for (i = 0; i < p->UCRcount; i++)
7605
				fprintf(op,"  %3lu:  %f\n",i,p->UCRcurve[i]);
7606
		}
7607
	}
7608
	if (p->BGcount == 0) {
7609
		fprintf(op,"  BG: Not specified\n");
7610
	} else if (p->BGcount == 1) {
7611
		fprintf(op,"  BG: %f%%\n",p->BGcurve[0]);
7612
	} else {
7613
		fprintf(op,"  BG curve no. elements = %u\n",p->BGcount);
7614
		if (verb >= 2) {
7615
			unsigned long i;
7616
			for (i = 0; i < p->BGcount; i++)
7617
				fprintf(op,"  %3lu:  %f\n",i,p->BGcurve[i]);
7618
		}
7619
	}
7620
 
7621
	{
7622
		unsigned long i, r, c, size;
7623
		fprintf(op,"  Description:\n");
7624
		fprintf(op,"    No. chars = %lu\n",p->size);
7625
 
7626
		size = p->size > 0 ? p->size-1 : 0;
7627
		i = 0;
7628
		for (r = 1;; r++) {		/* count rows */
7629
			if (i >= size) {
7630
				fprintf(op,"\n");
7631
				break;
7632
			}
7633
			if (r > 1 && verb < 2) {
7634
				fprintf(op,"...\n");
7635
				break;			/* Print 1 row if not verbose */
7636
			}
7637
			c = 1;
7638
			fprintf(op,"      0x%04lx: ",i);
7639
			c += 10;
7640
			while (i < size && c < 73) {
7641
				if (isprint(p->string[i])) {
7642
					fprintf(op,"%c",p->string[i]);
7643
					c++;
7644
				} else {
7645
					fprintf(op,"\\%03o",p->string[i]);
7646
					c += 4;
7647
				}
7648
				i++;
7649
			}
7650
			if (i < size)
7651
				fprintf(op,"\n");
7652
		}
7653
	}
7654
}
7655
 
7656
/* Allocate variable sized data elements */
7657
static int icmUcrBg_allocate(
7658
	icmBase *pp
7659
) {
7660
	icmUcrBg *p = (icmUcrBg *)pp;
7661
	icc *icp = p->icp;
7662
 
7663
	if (p->UCRcount != p->UCR_count) {
7664
		if (p->UCRcurve != NULL)
7665
			icp->al->free(icp->al, p->UCRcurve);
7666
		if ((p->UCRcurve = (double *) icp->al->malloc(icp->al, p->UCRcount * sizeof(double))) == NULL) {
7667
			sprintf(icp->err,"icmUcrBg_allocate: malloc() of UCR curve data failed");
7668
			return icp->errc = 2;
7669
		}
7670
		p->UCR_count = p->UCRcount;
7671
	}
7672
	if (p->BGcount != p->BG_count) {
7673
		if (p->BGcurve != NULL)
7674
			icp->al->free(icp->al, p->BGcurve);
7675
		if ((p->BGcurve = (double *) icp->al->malloc(icp->al, p->BGcount * sizeof(double))) == NULL) {
7676
			sprintf(icp->err,"icmUcrBg_allocate: malloc() of BG curve data failed");
7677
			return icp->errc = 2;
7678
		}
7679
		p->BG_count = p->BGcount;
7680
	}
7681
	if (p->size != p->_size) {
7682
		if (p->string != NULL)
7683
			icp->al->free(icp->al, p->string);
7684
		if ((p->string = (char *) icp->al->malloc(icp->al, p->size * sizeof(char))) == NULL) {
7685
			sprintf(icp->err,"icmUcrBg_allocate: malloc() of string data failed");
7686
			return icp->errc = 2;
7687
		}
7688
		p->_size = p->size;
7689
	}
7690
	return 0;
7691
}
7692
 
7693
/* Free all storage in the object */
7694
static void icmUcrBg_delete(
7695
	icmBase *pp
7696
) {
7697
	icmUcrBg *p = (icmUcrBg *)pp;
7698
	icc *icp = p->icp;
7699
 
7700
	if (p->UCRcurve != NULL)
7701
		icp->al->free(icp->al, p->UCRcurve);
7702
	if (p->BGcurve != NULL)
7703
		icp->al->free(icp->al, p->BGcurve);
7704
	if (p->string != NULL)
7705
		icp->al->free(icp->al, p->string);
7706
	icp->al->free(icp->al, p);
7707
}
7708
 
7709
/* Create an empty object. Return null on error */
7710
static icmBase *new_icmUcrBg(
7711
	icc *icp
7712
) {
7713
	icmUcrBg *p;
7714
	if ((p = (icmUcrBg *) icp->al->calloc(icp->al,1,sizeof(icmUcrBg))) == NULL)
7715
		return NULL;
7716
	p->ttype    = icSigUcrBgType;
7717
	p->refcount = 1;
7718
	p->get_size = icmUcrBg_get_size;
7719
	p->read     = icmUcrBg_read;
7720
	p->write    = icmUcrBg_write;
7721
	p->dump     = icmUcrBg_dump;
7722
	p->allocate = icmUcrBg_allocate;
7723
	p->del      = icmUcrBg_delete;
7724
	p->icp      = icp;
7725
 
7726
	return (icmBase *)p;
7727
}
7728
 
7729
/* ---------------------------------------------------------- */
7730
/* VideoCardGamma (ColorSync 2.5 specific - c/o Neil Okamoto) */
7731
 
7732
static unsigned int icmVideoCardGamma_get_size(
7733
	icmBase *pp
7734
) {
7735
	icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
7736
	unsigned int len = 0;
7737
 
7738
	len += 8;			/* 8 bytes for tag and padding */
7739
	len += 4;			/* 4 for gamma type */
7740
 
7741
	/* compute size of remainder */
7742
	if (p->tagType == icmVideoCardGammaTableType) {
7743
		len += 2;       /* 2 bytes for channels */
7744
		len += 2;       /* 2 for entry count */
7745
		len += 2;       /* 2 for entry size */
7746
		len += ( p->u.table.channels *     /* compute table size */
7747
				 p->u.table.entryCount *
7748
				 p->u.table.entrySize );
7749
	}
7750
	else if (p->tagType == icmVideoCardGammaFormulaType) {
7751
		len += 12;		/* 4 bytes each for red gamma, min, & max */
7752
		len += 12;		/* 4 bytes each for green gamma, min & max */
7753
		len += 12;		/* 4 bytes each for blue gamma, min & max */
7754
	}
7755
	return len;
7756
}
7757
/* read the object, return 0 on success, error code on fail */
7758
static int icmVideoCardGamma_read(
7759
	icmBase *pp,
7760
	unsigned long len,		/* tag length */
7761
	unsigned long of		/* start offset within file */
7762
) {
7763
	icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
7764
	icc *icp = p->icp;
7765
	int rv, c;
7766
	char *bp, *buf;
7767
	unsigned char *pchar;
7768
	unsigned short *pshort;
7769
 
7770
	if (len < 18) {
7771
		sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
7772
		return icp->errc = 1;
7773
	}
7774
 
7775
	/* Allocate a file read buffer */
7776
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7777
		sprintf(icp->err,"icmVideoCardGamma_read: malloc() failed");
7778
		return icp->errc = 2;
7779
	}
7780
	bp = buf;
7781
 
7782
	/* Read portion of file into buffer */
7783
	if (   icp->fp->seek(icp->fp, of) != 0
7784
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
7785
		sprintf(icp->err,"icmVideoCardGamma_read: fseek() or fread() failed");
7786
		icp->al->free(icp->al, buf);
7787
		return icp->errc = 1;
7788
	}
7789
 
7790
	/* Read type descriptor from the buffer */
7791
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
7792
		sprintf(icp->err,"icmVideoCardGamma_read: Wrong tag type for icmVideoCardGamma");
7793
		icp->al->free(icp->al, buf);
7794
		return icp->errc = 1;
7795
	}
7796
 
7797
	/* Read gamma format (eg. table or formula) from the buffer */
7798
	p->tagType = read_UInt32Number(bp+8);
7799
 
7800
	/* Read remaining gamma data based on format */
7801
	switch ((int)p->tagType) {
7802
	case icmVideoCardGammaTableType:
7803
		p->u.table.channels   = read_UInt16Number(bp+12);
7804
		p->u.table.entryCount = read_UInt16Number(bp+14);
7805
		p->u.table.entrySize  = read_UInt16Number(bp+16);
7806
		if (len-18 < p->u.table.channels*p->u.table.entryCount*p->u.table.entrySize) {
7807
			sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
7808
			return icp->errc = 1;
7809
		}
7810
		if ((rv = pp->allocate(pp)) != 0) {  /* make space for table */
7811
			icp->al->free(icp->al, buf);
7812
			return icp->errc = rv;
7813
		}
7814
		pchar = (unsigned char*)p->u.table.data;
7815
		pshort = (unsigned short*)p->u.table.data;
7816
		for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
7817
			switch (p->u.table.entrySize) {
7818
			case 1:
7819
				*pchar++ = read_UInt8Number(bp);
7820
				bp++;
7821
				break;
7822
			case 2:
7823
				*pshort++ = read_UInt16Number(bp);
7824
				bp+=2;
7825
				break;
7826
			default:
7827
				sprintf(icp->err,"icmVideoCardGamma_read: unsupported table entry size");
7828
				pp->del(pp);
7829
				icp->al->free(icp->al, buf);
7830
				return icp->errc = 1;
7831
			}
7832
		}
7833
		break;
7834
	case icmVideoCardGammaFormulaType:
7835
		if (len < 48) {
7836
			sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
7837
			return icp->errc = 1;
7838
		}
7839
		p->u.formula.redGamma   = read_S15Fixed16Number(bp+12);
7840
		p->u.formula.redMin     = read_S15Fixed16Number(bp+16);
7841
		p->u.formula.redMax     = read_S15Fixed16Number(bp+20);
7842
		p->u.formula.greenGamma = read_S15Fixed16Number(bp+24);
7843
		p->u.formula.greenMin   = read_S15Fixed16Number(bp+28);
7844
		p->u.formula.greenMax   = read_S15Fixed16Number(bp+32);
7845
		p->u.formula.blueGamma  = read_S15Fixed16Number(bp+36);
7846
		p->u.formula.blueMin    = read_S15Fixed16Number(bp+40);
7847
		p->u.formula.blueMax    = read_S15Fixed16Number(bp+44);
7848
		break;
7849
	default:
7850
		sprintf(icp->err,"icmVideoCardGammaTable_read: Unknown gamma format for icmVideoCardGamma");
7851
		icp->al->free(icp->al, buf);
7852
		return icp->errc = 1;
7853
	}
7854
 
7855
	icp->al->free(icp->al, buf);
7856
	return 0;
7857
}
7858
 
7859
/* Write the contents of the object. Return 0 on sucess, error code on failure */
7860
static int icmVideoCardGamma_write(
7861
	icmBase *pp,
7862
	unsigned long of			/* File offset to write from */
7863
) {
7864
	icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
7865
	icc *icp = p->icp;
7866
	unsigned int len;
7867
	char *bp, *buf;		/* Buffer to write from */
7868
	int rv = 0, c;
7869
	unsigned char *pchar;
7870
	unsigned short *pshort;
7871
 
7872
	/* Allocate a file write buffer */
7873
	len = p->get_size((icmBase *)p);
7874
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
7875
		sprintf(icp->err,"icmViewingConditions_write malloc() failed");
7876
		return icp->errc = 2;
7877
	}
7878
	bp = buf;
7879
 
7880
	/* Write type descriptor to the buffer */
7881
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
7882
		sprintf(icp->err,"icmVideoCardGamma_write: write_SInt32Number() failed");
7883
		icp->al->free(icp->al, buf);
7884
		return icp->errc = rv;
7885
	}
7886
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
7887
 
7888
	/* Write gamma format (eg. table of formula) */
7889
	if ((rv = write_UInt32Number(p->tagType,bp+8)) != 0) {
7890
		sprintf(icp->err,"icmVideoCardGamma_write: write_UInt32Number() failed");
7891
		icp->al->free(icp->al, buf);
7892
		return icp->errc = rv;
7893
	}
7894
 
7895
	/* Write remaining gamma data based on format */
7896
	switch ((int)p->tagType) {
7897
	case icmVideoCardGammaTableType:
7898
		if ((rv = write_UInt16Number(p->u.table.channels,bp+12)) != 0) {
7899
			sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
7900
			icp->al->free(icp->al, buf);
7901
			return icp->errc = rv;
7902
		}
7903
		if ((rv = write_UInt16Number(p->u.table.entryCount,bp+14)) != 0) {
7904
			sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
7905
			icp->al->free(icp->al, buf);
7906
			return icp->errc = rv;
7907
		}
7908
		if ((rv = write_UInt16Number(p->u.table.entrySize,bp+16)) != 0) {
7909
			sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
7910
			icp->al->free(icp->al, buf);
7911
			return icp->errc = rv;
7912
		}
7913
		pchar = (unsigned char*)p->u.table.data;
7914
		pshort = (unsigned short*)p->u.table.data;
7915
		for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
7916
			switch (p->u.table.entrySize) {
7917
			case 1:
7918
				write_UInt8Number(*pchar++,bp);
7919
				bp++;
7920
				break;
7921
			case 2:
7922
				write_UInt16Number(*pshort++,bp);
7923
				bp+=2;
7924
				break;
7925
			default:
7926
				sprintf(icp->err,"icmVideoCardGamma_write: unsupported table entry size");
7927
				icp->al->free(icp->al, buf);
7928
				return icp->errc = 1;
7929
			}
7930
		}
7931
		break;
7932
	case icmVideoCardGammaFormulaType:
7933
		if ((rv = write_S15Fixed16Number(p->u.formula.redGamma,bp+12)) != 0) {
7934
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7935
			icp->al->free(icp->al, buf);
7936
			return icp->errc = rv;
7937
		}
7938
		if ((rv = write_S15Fixed16Number(p->u.formula.redMin,bp+16)) != 0) {
7939
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7940
			icp->al->free(icp->al, buf);
7941
			return icp->errc = rv;
7942
		}
7943
		if ((rv = write_S15Fixed16Number(p->u.formula.redMax,bp+20)) != 0) {
7944
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7945
			icp->al->free(icp->al, buf);
7946
			return icp->errc = rv;
7947
		}
7948
		if ((rv = write_S15Fixed16Number(p->u.formula.greenGamma,bp+24)) != 0) {
7949
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7950
			icp->al->free(icp->al, buf);
7951
			return icp->errc = rv;
7952
		}
7953
		if ((rv = write_S15Fixed16Number(p->u.formula.greenMin,bp+28)) != 0) {
7954
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7955
			icp->al->free(icp->al, buf);
7956
			return icp->errc = rv;
7957
		}
7958
		if ((rv = write_S15Fixed16Number(p->u.formula.greenMax,bp+32)) != 0) {
7959
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7960
			icp->al->free(icp->al, buf);
7961
			return icp->errc = rv;
7962
		}
7963
		if ((rv = write_S15Fixed16Number(p->u.formula.blueGamma,bp+36)) != 0) {
7964
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7965
			icp->al->free(icp->al, buf);
7966
			return icp->errc = rv;
7967
		}
7968
		if ((rv = write_S15Fixed16Number(p->u.formula.blueMin,bp+40)) != 0) {
7969
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7970
			icp->al->free(icp->al, buf);
7971
			return icp->errc = rv;
7972
		}
7973
		if ((rv = write_S15Fixed16Number(p->u.formula.blueMax,bp+44)) != 0) {
7974
			sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
7975
			icp->al->free(icp->al, buf);
7976
			return icp->errc = rv;
7977
		}
7978
		break;
7979
	default:
7980
		sprintf(icp->err,"icmVideoCardGammaTable_write: Unknown gamma format for icmVideoCardGamma");
7981
		icp->al->free(icp->al, buf);
7982
		return icp->errc = 1;
7983
	}
7984
 
7985
	/* Write to the file */
7986
	if (   icp->fp->seek(icp->fp, of) != 0
7987
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
7988
		sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
7989
		icp->al->free(icp->al, buf);
7990
		return icp->errc = 2;
7991
	}
7992
	icp->al->free(icp->al, buf);
7993
	return 0;
7994
}
7995
 
7996
/* Dump a text description of the object */
7997
static void icmVideoCardGamma_dump(
7998
	icmBase *pp,
7999
	FILE *op,		/* Output to dump to */
8000
	int   verb		/* Verbosity level */
8001
) {
8002
	icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
8003
	int c,i;
8004
 
8005
	if (verb <= 0)
8006
		return;
8007
 
8008
	switch ((int)p->tagType) {
8009
	case icmVideoCardGammaTableType:
8010
		fprintf(op,"VideoCardGammaTable:\n");
8011
		fprintf(op,"  channels  = %d\n", p->u.table.channels);
8012
		fprintf(op,"  entries   = %d\n", p->u.table.entryCount);
8013
		fprintf(op,"  entrysize = %d\n", p->u.table.entrySize);
8014
		if (verb >= 2) {
8015
			/* dump array contents also */
8016
			for (c=0; c<p->u.table.channels; c++) {
8017
				fprintf(op,"  channel #%d\n",c);
8018
				for (i=0; i<p->u.table.entryCount; i++) {
8019
					if (p->u.table.entrySize == 1) {
8020
						fprintf(op,"    %d: %d\n",i,((unsigned char*)p->u.table.data)[c*p->u.table.entryCount+i]);
8021
					}
8022
					else if (p->u.table.entrySize == 2) {
8023
						fprintf(op,"    %d: %d\n",i,((unsigned short*)p->u.table.data)[c*p->u.table.entryCount+i]);
8024
					}
8025
				}
8026
			}
8027
		}
8028
		break;
8029
	case icmVideoCardGammaFormulaType:
8030
		fprintf(op,"VideoCardGammaFormula:\n");
8031
		fprintf(op,"  red gamma   = %f\n", p->u.formula.redGamma);
8032
		fprintf(op,"  red min     = %f\n", p->u.formula.redMin);
8033
		fprintf(op,"  red max     = %f\n", p->u.formula.redMax);
8034
		fprintf(op,"  green gamma = %f\n", p->u.formula.greenGamma);
8035
		fprintf(op,"  green min   = %f\n", p->u.formula.greenMin);
8036
		fprintf(op,"  green max   = %f\n", p->u.formula.greenMax);
8037
		fprintf(op,"  blue gamma  = %f\n", p->u.formula.blueGamma);
8038
		fprintf(op,"  blue min    = %f\n", p->u.formula.blueMin);
8039
		fprintf(op,"  blue max    = %f\n", p->u.formula.blueMax);
8040
		break;
8041
	default:
8042
		fprintf(op,"  Unknown tag format\n");
8043
	}
8044
}
8045
 
8046
/* Allocate variable sized data elements */
8047
static int icmVideoCardGamma_allocate(
8048
	icmBase *pp
8049
) {
8050
	icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
8051
	icc *icp = p->icp;
8052
	int size;
8053
 
8054
	/* note: allocation is only relevant for table type
8055
	 * and in that case the channels, entryCount, and entrySize
8056
	 * fields must all be set prior to getting here
8057
	 */
8058
 
8059
	if (p->tagType == icmVideoCardGammaTableType) {
8060
		if (p->u.table.data != NULL)
8061
			icp->al->free(icp->al, p->u.table.data);
8062
		size = (p->u.table.channels *
8063
				p->u.table.entryCount);
8064
		switch (p->u.table.entrySize) {
8065
		case 1:
8066
			size *= sizeof(unsigned char);
8067
			break;
8068
		case 2:
8069
			size *= sizeof(unsigned short);
8070
			break;
8071
		default:
8072
			sprintf(icp->err,"icmVideoCardGamma_alloc: unsupported table entry size");
8073
			return icp->errc = 1;
8074
		}
8075
		if ((p->u.table.data = (void*) icp->al->malloc(icp->al, size)) == NULL) {
8076
			sprintf(icp->err,"icmVideoCardGamma_alloc: malloc() of table data failed");
8077
			return icp->errc = 2;
8078
		}
8079
	}
8080
 
8081
	return 0;
8082
}
8083
 
8084
/* Free all storage in the object */
8085
static void icmVideoCardGamma_delete(
8086
	icmBase *pp
8087
) {
8088
	icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
8089
	icc *icp = p->icp;
8090
 
8091
	if (p->tagType == icmVideoCardGammaTableType && p->u.table.data != NULL)
8092
		icp->al->free(icp->al, p->u.table.data);
8093
 
8094
	icp->al->free(icp->al, p);
8095
}
8096
 
8097
/* Create an empty object. Return null on error */
8098
static icmBase *new_icmVideoCardGamma(
8099
	icc *icp
8100
) {
8101
	icmVideoCardGamma *p;
8102
	if ((p = (icmVideoCardGamma *) icp->al->calloc(icp->al,1,sizeof(icmVideoCardGamma))) == NULL)
8103
		return NULL;
8104
	p->ttype    = icSigVideoCardGammaType;
8105
	p->refcount = 1;
8106
	p->get_size = icmVideoCardGamma_get_size;
8107
	p->read     = icmVideoCardGamma_read;
8108
	p->write    = icmVideoCardGamma_write;
8109
	p->dump     = icmVideoCardGamma_dump;
8110
	p->allocate = icmVideoCardGamma_allocate;
8111
	p->del      = icmVideoCardGamma_delete;
8112
	p->icp      = icp;
8113
 
8114
	return (icmBase *)p;
8115
}
8116
 
8117
/* ---------------------------------------------------------- */
8118
/* ViewingConditions */
8119
 
8120
/* Return the number of bytes needed to write this tag */
8121
static unsigned int icmViewingConditions_get_size(
8122
	icmBase *pp
8123
) {
8124
	unsigned int len = 0;
8125
	len += 8;			/* 8 bytes for tag and padding */
8126
	len += 12;			/* 12 for XYZ of illuminant */
8127
	len += 12;			/* 12 for XYZ of surround */
8128
	len += 4;			/* 4 for illuminant type */
8129
	return len;
8130
}
8131
 
8132
/* read the object, return 0 on success, error code on fail */
8133
static int icmViewingConditions_read(
8134
	icmBase *pp,
8135
	unsigned long len,		/* tag length */
8136
	unsigned long of		/* start offset within file */
8137
) {
8138
	icmViewingConditions *p = (icmViewingConditions *)pp;
8139
	icc *icp = p->icp;
8140
	int rv;
8141
	char *bp, *buf;
8142
 
8143
	if (len < 36) {
8144
		sprintf(icp->err,"icmViewingConditions_read: Tag too small to be legal");
8145
		return icp->errc = 1;
8146
	}
8147
 
8148
	/* Allocate a file read buffer */
8149
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8150
		sprintf(icp->err,"icmViewingConditions_read: malloc() failed");
8151
		return icp->errc = 2;
8152
	}
8153
	bp = buf;
8154
 
8155
	/* Read portion of file into buffer */
8156
	if (   icp->fp->seek(icp->fp, of) != 0
8157
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
8158
		sprintf(icp->err,"icmViewingConditions_read: fseek() or fread() failed");
8159
		icp->al->free(icp->al, buf);
8160
		return icp->errc = 1;
8161
	}
8162
 
8163
	/* Read type descriptor from the buffer */
8164
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
8165
		sprintf(icp->err,"icmViewingConditions_read: Wrong tag type for icmViewingConditions");
8166
		icp->al->free(icp->al, buf);
8167
		return icp->errc = 1;
8168
	}
8169
 
8170
	/* Read the XYZ values for the illuminant */
8171
	if ((rv = read_XYZNumber(&p->illuminant, bp+8)) != 0) {
8172
		sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
8173
		icp->al->free(icp->al, buf);
8174
		return icp->errc = rv;
8175
	}
8176
 
8177
	/* Read the XYZ values for the surround */
8178
	if ((rv = read_XYZNumber(&p->surround, bp+20)) != 0) {
8179
		sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
8180
		icp->al->free(icp->al, buf);
8181
		return icp->errc = rv;
8182
	}
8183
 
8184
	/* Read the encoded standard illuminant */
8185
	p->stdIlluminant = (icIlluminant)read_SInt32Number(bp + 32);
8186
 
8187
	icp->al->free(icp->al, buf);
8188
	return 0;
8189
}
8190
 
8191
/* Write the contents of the object. Return 0 on sucess, error code on failure */
8192
static int icmViewingConditions_write(
8193
	icmBase *pp,
8194
	unsigned long of			/* File offset to write from */
8195
) {
8196
	icmViewingConditions *p = (icmViewingConditions *)pp;
8197
	icc *icp = p->icp;
8198
	unsigned int len;
8199
	char *bp, *buf;		/* Buffer to write from */
8200
	int rv = 0;
8201
 
8202
	/* Allocate a file write buffer */
8203
	len = p->get_size((icmBase *)p);
8204
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8205
		sprintf(icp->err,"icmViewingConditions_write malloc() failed");
8206
		return icp->errc = 2;
8207
	}
8208
	bp = buf;
8209
 
8210
	/* Write type descriptor to the buffer */
8211
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
8212
		sprintf(icp->err,"icmViewingConditions_write: write_SInt32Number() failed");
8213
		icp->al->free(icp->al, buf);
8214
		return icp->errc = rv;
8215
	}
8216
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
8217
 
8218
	/* Write the XYZ values for the illuminant */
8219
	if ((rv = write_XYZNumber(&p->illuminant, bp+8)) != 0) {
8220
		sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
8221
		icp->al->free(icp->al, buf);
8222
		return icp->errc = rv;
8223
	}
8224
 
8225
	/* Write the XYZ values for the surround */
8226
	if ((rv = write_XYZNumber(&p->surround, bp+20)) != 0) {
8227
		sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
8228
		icp->al->free(icp->al, buf);
8229
		return icp->errc = rv;
8230
	}
8231
 
8232
	/* Write the encoded standard illuminant */
8233
	if ((rv = write_SInt32Number((int)p->stdIlluminant, bp + 32)) != 0) {
8234
		sprintf(icp->err,"icmViewingConditionsa_write: write_SInt32Number() failed");
8235
		icp->al->free(icp->al, buf);
8236
		return icp->errc = rv;
8237
	}
8238
 
8239
	/* Write to the file */
8240
	if (   icp->fp->seek(icp->fp, of) != 0
8241
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
8242
		sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
8243
		icp->al->free(icp->al, buf);
8244
		return icp->errc = 2;
8245
	}
8246
	icp->al->free(icp->al, buf);
8247
	return 0;
8248
}
8249
 
8250
/* Dump a text description of the object */
8251
static void icmViewingConditions_dump(
8252
	icmBase *pp,
8253
	FILE *op,		/* Output to dump to */
8254
	int   verb		/* Verbosity level */
8255
) {
8256
	icmViewingConditions *p = (icmViewingConditions *)pp;
8257
	if (verb <= 0)
8258
		return;
8259
 
8260
	fprintf(op,"Viewing Conditions:\n");
8261
	fprintf(op,"  XYZ value of illuminant in cd/m^2 = %s\n", string_XYZNumber(&p->illuminant));
8262
	fprintf(op,"  XYZ value of surround in cd/m^2   = %s\n", string_XYZNumber(&p->surround));
8263
	fprintf(op,"  Illuminant type = %s\n", string_Illuminant(p->stdIlluminant));
8264
}
8265
 
8266
/* Allocate variable sized data elements */
8267
static int icmViewingConditions_allocate(
8268
	icmBase *pp
8269
) {
8270
	/* Nothing to do */
8271
	return 0;
8272
}
8273
 
8274
/* Free all storage in the object */
8275
static void icmViewingConditions_delete(
8276
	icmBase *pp
8277
) {
8278
	icmViewingConditions *p = (icmViewingConditions *)pp;
8279
	icc *icp = p->icp;
8280
 
8281
	icp->al->free(icp->al, p);
8282
}
8283
 
8284
/* Create an empty object. Return null on error */
8285
static icmBase *new_icmViewingConditions(
8286
	icc *icp
8287
) {
8288
	icmViewingConditions *p;
8289
	if ((p = (icmViewingConditions *) icp->al->calloc(icp->al,1,sizeof(icmViewingConditions))) == NULL)
8290
		return NULL;
8291
	p->ttype    = icSigViewingConditionsType;
8292
	p->refcount = 1;
8293
	p->get_size = icmViewingConditions_get_size;
8294
	p->read     = icmViewingConditions_read;
8295
	p->write    = icmViewingConditions_write;
8296
	p->dump     = icmViewingConditions_dump;
8297
	p->allocate = icmViewingConditions_allocate;
8298
	p->del      = icmViewingConditions_delete;
8299
	p->icp      = icp;
8300
 
8301
	return (icmBase *)p;
8302
}
8303
 
8304
/* ---------------------------------------------------------- */
8305
/* icmCrdInfo object */
8306
 
8307
/* Return the number of bytes needed to write this tag */
8308
static unsigned int icmCrdInfo_get_size(
8309
	icmBase *pp
8310
) {
8311
	icmCrdInfo *p = (icmCrdInfo *)pp;
8312
	unsigned int len = 0, t;
8313
	len += 8;				/* 8 bytes for tag and padding */
8314
	len += 4 + p->ppsize;	/* Postscript product name */
8315
	for (t = 0; t < 4; t++) {	/* For all 4 intents */
8316
		len += 4 + p->crdsize[t];	/* crd names */ 
8317
	}
8318
	return len;
8319
}
8320
 
8321
/* read the object, return 0 on success, error code on fail */
8322
static int icmCrdInfo_read(
8323
	icmBase *pp,
8324
	unsigned long len,		/* tag length */
8325
	unsigned long of		/* start offset within file */
8326
) {
8327
	icmCrdInfo *p = (icmCrdInfo *)pp;
8328
	icc *icp = p->icp;
8329
	unsigned long t;
8330
	int rv = 0;
8331
	char *bp, *buf, *end;
8332
 
8333
	if (len < 28) {
8334
		sprintf(icp->err,"icmCrdInfo_read: Tag too small to be legal");
8335
		return icp->errc = 1;
8336
	}
8337
 
8338
	/* Allocate a file read buffer */
8339
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8340
		sprintf(icp->err,"icmCrdInfo_read: malloc() failed");
8341
		return icp->errc = 2;
8342
	}
8343
	bp = buf;
8344
	end = buf + len;
8345
 
8346
	/* Read portion of file into buffer */
8347
	if (   icp->fp->seek(icp->fp, of) != 0
8348
	    || icp->fp->read(icp->fp, bp, 1, len) != len) {
8349
		sprintf(icp->err,"icmCrdInfo_read: fseek() or fread() failed");
8350
		icp->al->free(icp->al, buf);
8351
		return icp->errc = 1;
8352
	}
8353
 
8354
	/* Read type descriptor from the buffer */
8355
	if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
8356
		sprintf(icp->err,"icmCrdInfo_read: Wrong tag type for icmCrdInfo");
8357
		icp->al->free(icp->al, buf);
8358
		return icp->errc = 1;
8359
	}
8360
	bp = bp + 8;
8361
 
8362
	/* Postscript product name */
8363
	if ((bp + 4) > end) {
8364
		sprintf(icp->err,"icmCrdInfo_read: Data too short to read Postscript product name");
8365
		icp->al->free(icp->al, buf);
8366
		return icp->errc = 1;
8367
	}
8368
	p->ppsize = read_UInt32Number(bp);
8369
	bp += 4;
8370
	if (p->ppsize > 0) {
8371
		if ((bp + p->ppsize) > end) {
8372
			sprintf(icp->err,"icmCrdInfo_read: Data to short to read Postscript product string");
8373
			icp->al->free(icp->al, buf);
8374
			return icp->errc = 1;
8375
		}
8376
		if (check_null_string(bp,p->ppsize)) {
8377
			sprintf(icp->err,"icmCrdInfo_read: Postscript product name is not terminated");
8378
			icp->al->free(icp->al, buf);
8379
			return icp->errc = 1;
8380
		}
8381
		if ((rv = p->allocate((icmBase *)p)) != 0) {
8382
			icp->al->free(icp->al, buf);
8383
			return rv;
8384
		}
8385
		memcpy((void *)p->ppname, (void *)bp, p->ppsize);
8386
		bp += p->ppsize;
8387
	}
8388
 
8389
	/* CRD names for the four rendering intents */
8390
	for (t = 0; t < 4; t++) {	/* For all 4 intents */
8391
		if ((bp + 4) > end) {
8392
			sprintf(icp->err,"icmCrdInfo_read: Data too short to read CRD%ld name",t);
8393
			icp->al->free(icp->al, buf);
8394
			return icp->errc = 1;
8395
		}
8396
		p->crdsize[t] = read_UInt32Number(bp);
8397
		bp += 4;
8398
		if (p->crdsize[t] > 0) {
8399
			if ((bp + p->crdsize[t]) > end) {
8400
				sprintf(icp->err,"icmCrdInfo_read: Data to short to read CRD%ld string",t);
8401
				icp->al->free(icp->al, buf);
8402
				return icp->errc = 1;
8403
			}
8404
			if (check_null_string(bp,p->crdsize[t])) {
8405
				sprintf(icp->err,"icmCrdInfo_read: CRD%ld name is not terminated",t);
8406
				icp->al->free(icp->al, buf);
8407
				return icp->errc = 1;
8408
			}
8409
			if ((rv = p->allocate((icmBase *)p)) != 0) { 
8410
				icp->al->free(icp->al, buf);
8411
				return rv;
8412
			}
8413
			memcpy((void *)p->crdname[t], (void *)bp, p->crdsize[t]);
8414
			bp += p->crdsize[t];
8415
		}
8416
	}
8417
 
8418
	icp->al->free(icp->al, buf);
8419
	return 0;
8420
}
8421
 
8422
/* Write the contents of the object. Return 0 on sucess, error code on failure */
8423
static int icmCrdInfo_write(
8424
	icmBase *pp,
8425
	unsigned long of			/* File offset to write from */
8426
) {
8427
	icmCrdInfo *p = (icmCrdInfo *)pp;
8428
	icc *icp = p->icp;
8429
	unsigned long t;
8430
	unsigned int len;
8431
	char *bp, *buf;		/* Buffer to write from */
8432
	int rv = 0;
8433
 
8434
	/* Allocate a file write buffer */
8435
	len = p->get_size((icmBase *)p);
8436
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8437
		sprintf(icp->err,"icmCrdInfo_write malloc() failed");
8438
		return icp->errc = 2;
8439
	}
8440
	bp = buf;
8441
 
8442
	/* Write type descriptor to the buffer */
8443
	if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
8444
		sprintf(icp->err,"icmCrdInfo_write: write_SInt32Number() failed");
8445
		icp->al->free(icp->al, buf);
8446
		return icp->errc = rv;
8447
	}
8448
	write_SInt32Number(0,bp+4);			/* Set padding to 0 */
8449
	bp = bp + 8;
8450
 
8451
	/* Postscript product name */
8452
	if ((rv = write_UInt32Number(p->ppsize,bp)) != 0) {
8453
		sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
8454
		icp->al->free(icp->al, buf);
8455
		return icp->errc = rv;
8456
	}
8457
	bp += 4;
8458
	if (p->ppsize > 0) {
8459
		if ((rv = check_null_string(p->ppname,p->ppsize)) != 0) {
8460
			sprintf(icp->err,"icmCrdInfo_write: Postscript product name is not terminated");
8461
			icp->al->free(icp->al, buf);
8462
			return icp->errc = 1;
8463
		}
8464
		memcpy((void *)bp, (void *)p->ppname, p->ppsize);
8465
		bp += p->ppsize;
8466
	}
8467
 
8468
	/* CRD names for the four rendering intents */
8469
	for (t = 0; t < 4; t++) {	/* For all 4 intents */
8470
		if ((rv = write_UInt32Number(p->crdsize[t],bp)) != 0) {
8471
			sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
8472
			icp->al->free(icp->al, buf);
8473
			return icp->errc = rv;
8474
		}
8475
		bp += 4;
8476
		if (p->ppsize > 0) {
8477
			if ((rv = check_null_string(p->crdname[t],p->crdsize[t])) != 0) {
8478
				sprintf(icp->err,"icmCrdInfo_write: CRD%ld name is not terminated",t);
8479
				icp->al->free(icp->al, buf);
8480
				return icp->errc = 1;
8481
			}
8482
			memcpy((void *)bp, (void *)p->crdname[t], p->crdsize[t]);
8483
			bp += p->crdsize[t];
8484
		}
8485
	}
8486
 
8487
	/* Write to the file */
8488
	if (   icp->fp->seek(icp->fp, of) != 0
8489
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
8490
		sprintf(icp->err,"icmCrdInfo_write fseek() or fwrite() failed");
8491
		icp->al->free(icp->al, buf);
8492
		return icp->errc = 2;
8493
	}
8494
	icp->al->free(icp->al, buf);
8495
	return 0;
8496
}
8497
 
8498
/* Dump a text description of the object */
8499
static void icmCrdInfo_dump(
8500
	icmBase *pp,
8501
	FILE *op,		/* Output to dump to */
8502
	int   verb		/* Verbosity level */
8503
) {
8504
	icmCrdInfo *p = (icmCrdInfo *)pp;
8505
	unsigned long i, r, c, size, t;
8506
 
8507
	if (verb <= 0)
8508
		return;
8509
 
8510
	fprintf(op,"PostScript Product name and CRD names:\n");
8511
 
8512
	fprintf(op,"  Product name:\n");
8513
	fprintf(op,"    No. chars = %lu\n",p->ppsize);
8514
 
8515
	size = p->ppsize > 0 ? p->ppsize-1 : 0;
8516
	i = 0;
8517
	for (r = 1;; r++) {		/* count rows */
8518
		if (i >= size) {
8519
			fprintf(op,"\n");
8520
			break;
8521
		}
8522
		if (r > 1 && verb < 2) {
8523
			fprintf(op,"...\n");
8524
			break;			/* Print 1 row if not verbose */
8525
		}
8526
		c = 1;
8527
		fprintf(op,"      0x%04lx: ",i);
8528
		c += 10;
8529
		while (i < size && c < 73) {
8530
			if (isprint(p->ppname[i])) {
8531
				fprintf(op,"%c",p->ppname[i]);
8532
				c++;
8533
			} else {
8534
				fprintf(op,"\\%03o",p->ppname[i]);
8535
				c += 4;
8536
			}
8537
			i++;
8538
		}
8539
		if (i < size)
8540
			fprintf(op,"\n");
8541
	}
8542
 
8543
	for (t = 0; t < 4; t++) {	/* For all 4 intents */
8544
		fprintf(op,"  CRD%ld name:\n",t);
8545
		fprintf(op,"    No. chars = %lu\n",p->crdsize[t]);
8546
 
8547
		size = p->crdsize[t] > 0 ? p->crdsize[t]-1 : 0;
8548
		i = 0;
8549
		for (r = 1;; r++) {		/* count rows */
8550
			if (i >= size) {
8551
				fprintf(op,"\n");
8552
				break;
8553
			}
8554
			if (r > 1 && verb < 2) {
8555
				fprintf(op,"...\n");
8556
				break;			/* Print 1 row if not verbose */
8557
			}
8558
			c = 1;
8559
			fprintf(op,"      0x%04lx: ",i);
8560
			c += 10;
8561
			while (i < size && c < 73) {
8562
				if (isprint(p->crdname[t][i])) {
8563
					fprintf(op,"%c",p->crdname[t][i]);
8564
					c++;
8565
				} else {
8566
					fprintf(op,"\\%03o",p->crdname[t][i]);
8567
					c += 4;
8568
				}
8569
				i++;
8570
			}
8571
			if (i < size)
8572
				fprintf(op,"\n");
8573
		}
8574
	}
8575
}
8576
 
8577
/* Allocate variable sized data elements */
8578
static int icmCrdInfo_allocate(
8579
	icmBase *pp
8580
) {
8581
	icmCrdInfo *p = (icmCrdInfo *)pp;
8582
	icc *icp = p->icp;
8583
	unsigned int t;
8584
 
8585
	if (p->ppsize != p->_ppsize) {
8586
		if (p->ppname != NULL)
8587
			icp->al->free(icp->al, p->ppname);
8588
		if ((p->ppname = (char *) icp->al->malloc(icp->al, p->ppsize * sizeof(char))) == NULL) {
8589
			sprintf(icp->err,"icmCrdInfo_alloc: malloc() of string data failed");
8590
			return icp->errc = 2;
8591
		}
8592
		p->_ppsize = p->ppsize;
8593
	}
8594
	for (t = 0; t < 4; t++) {	/* For all 4 intents */
8595
		if (p->crdsize[t] != p->_crdsize[t]) {
8596
			if (p->crdname[t] != NULL)
8597
				icp->al->free(icp->al, p->crdname[t]);
8598
			if ((p->crdname[t] = (char *) icp->al->malloc(icp->al, p->crdsize[t] * sizeof(char))) == NULL) {
8599
				sprintf(icp->err,"icmCrdInfo_alloc: malloc() of CRD%d name string failed",t);
8600
				return icp->errc = 2;
8601
			}
8602
			p->_crdsize[t] = p->crdsize[t];
8603
		}
8604
	}
8605
	return 0;
8606
}
8607
 
8608
/* Free all storage in the object */
8609
static void icmCrdInfo_delete(
8610
	icmBase *pp
8611
) {
8612
	icmCrdInfo *p = (icmCrdInfo *)pp;
8613
	icc *icp = p->icp;
8614
	unsigned int t;
8615
 
8616
	if (p->ppname != NULL)
8617
		icp->al->free(icp->al, p->ppname);
8618
	for (t = 0; t < 4; t++) {	/* For all 4 intents */
8619
		if (p->crdname[t] != NULL)
8620
			icp->al->free(icp->al, p->crdname[t]);
8621
	}
8622
	icp->al->free(icp->al, p);
8623
}
8624
 
8625
/* Create an empty object. Return null on error */
8626
static icmBase *new_icmCrdInfo(
8627
	icc *icp
8628
) {
8629
	icmCrdInfo *p;
8630
	if ((p = (icmCrdInfo *) icp->al->calloc(icp->al,1,sizeof(icmCrdInfo))) == NULL)
8631
		return NULL;
8632
	p->ttype    = icSigCrdInfoType;
8633
	p->refcount = 1;
8634
	p->get_size = icmCrdInfo_get_size;
8635
	p->read     = icmCrdInfo_read;
8636
	p->write    = icmCrdInfo_write;
8637
	p->dump     = icmCrdInfo_dump;
8638
	p->allocate = icmCrdInfo_allocate;
8639
	p->del      = icmCrdInfo_delete;
8640
	p->icp      = icp;
8641
 
8642
	return (icmBase *)p;
8643
}
8644
 
8645
/* ========================================================== */
8646
/* icmHeader object */
8647
/* ========================================================== */
8648
 
8649
/* Return the number of bytes needed to write this tag */
8650
static unsigned int icmHeader_get_size(
8651
	icmHeader *p
8652
) {
8653
	return 128;		/* By definition */
8654
}
8655
 
8656
/* read the object, return 0 on success, error code on fail */
8657
static int icmHeader_read(
8658
	icmHeader *p,
8659
	unsigned long len,		/* tag length */
8660
	unsigned long of		/* start offset within file */
8661
) {
8662
	icc *icp = p->icp;
8663
	char *buf;
8664
	unsigned int tt;
8665
	int rv = 0;
8666
 
8667
	if (len != 128) {
8668
		sprintf(icp->err,"icmHeader_read: Length expected to be 128");
8669
		return icp->errc = 1;
8670
	}
8671
 
8672
	if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
8673
		sprintf(icp->err,"icmHeader_read: malloc() failed");
8674
		return icp->errc = 2;
8675
	}
8676
	if (   icp->fp->seek(icp->fp, of) != 0
8677
	    || icp->fp->read(icp->fp, buf, 1, len) != len) {
8678
		sprintf(icp->err,"icmHeader_read: fseek() or fread() failed");
8679
		icp->al->free(icp->al, buf);
8680
		return icp->errc = 1;
8681
	}
8682
 
8683
	/* Fill in the in-memory structure */
8684
	p->size  = read_UInt32Number(buf + 0);	/* Profile size in bytes */
8685
    p->cmmId = read_SInt32Number(buf + 4);	/* CMM for profile */
8686
	tt       = read_UInt8Number(buf + 8);	/* Raw major version number */
8687
    p->majv  = (tt >> 4) * 10 + (tt & 0xf);	/* Integer major version number */
8688
	tt       = read_UInt8Number(buf + 9);	/* Raw minor/bug fix version numbers */
8689
    p->minv  = (tt >> 4);					/* Integer minor version number */
8690
    p->bfv   = (tt & 0xf);					/* Integer bug fix version number */
8691
	p->deviceClass = (icProfileClassSignature)
8692
	           read_SInt32Number(buf + 12);	/* Type of profile */
8693
    p->colorSpace = (icColorSpaceSignature)
8694
	           read_SInt32Number(buf + 16);	/* Color space of data */
8695
    p->pcs = (icColorSpaceSignature)
8696
	           read_SInt32Number(buf + 20);	/* PCS: XYZ or Lab */
8697
	if ((rv = read_DateTimeNumber(&p->date, buf + 24)) != 0) {	/* Creation Date */
8698
		sprintf(icp->err,"icmHeader_read: read_DateTimeNumber corrupted");
8699
		icp->al->free(icp->al, buf);
8700
		return icp->errc = rv;
8701
	}
8702
	tt = read_SInt32Number(buf+36);
8703
	if (tt != icMagicNumber) {				/* Check magic number */
8704
		sprintf(icp->err,"icmHeader_read: wrong magic number 0x%x",tt);
8705
		icp->al->free(icp->al, buf);
8706
		return icp->errc = 1;
8707
	}
8708
    p->platform = (icPlatformSignature)
8709
	           read_SInt32Number(buf + 40);			/* Primary platform */
8710
    p->flags = read_UInt32Number(buf + 44);			/* Various bits */
8711
    p->manufacturer = read_SInt32Number(buf + 48); /* Dev manufacturer */
8712
    p->model = read_SInt32Number(buf + 52);			/* Dev model */
8713
    read_UInt64Number(&p->attributes, buf + 56);	/* Device attributes */
8714
	p->renderingIntent = (icRenderingIntent)
8715
	           read_SInt32Number(buf + 64);	/* Rendering intent */
8716
	if ((rv = read_XYZNumber(&p->illuminant, buf + 68)) != 0) {	/* Profile illuminant */
8717
		sprintf(icp->err,"icmHeader_read: read_XYZNumber error");
8718
		icp->al->free(icp->al, buf);
8719
		return icp->errc = rv;
8720
	}
8721
    p->creator = read_SInt32Number(buf + 80);	/* Profile creator */
8722
 
8723
	icp->al->free(icp->al, buf);
8724
	return 0;
8725
}
8726
 
8727
/* Write the contents of the object. Return 0 on sucess, error code on failure */
8728
static int icmHeader_write(
8729
	icmHeader *p,
8730
	unsigned long of			/* File offset to write from */
8731
) {
8732
	icc *icp = p->icp;
8733
	char *buf;		/* Buffer to write from */
8734
	unsigned int len;
8735
	unsigned int tt;
8736
	int rv = 0;
8737
 
8738
	len = p->get_size(p);
8739
	if ((buf = (char *) icp->al->calloc(icp->al,1,len)) == NULL) {			/* Zero it - some CMS are fussy */
8740
		sprintf(icp->err,"icmHeader_write calloc() failed");
8741
		return icp->errc = 2;
8742
	}
8743
 
8744
	/* Fill in the write buffer */
8745
	if ((rv = write_UInt32Number(p->size, buf + 0)) != 0) {	/* Profile size in bytes */
8746
		sprintf(icp->err,"icmHeader_write: profile size");
8747
		icp->al->free(icp->al, buf);
8748
		return icp->errc = rv;
8749
	}
8750
 
8751
    if ((rv = write_SInt32Number(p->cmmId, buf + 4)) != 0) {	/* CMM for profile */
8752
		sprintf(icp->err,"icmHeader_write: cmmId");
8753
		icp->al->free(icp->al, buf);
8754
		return icp->errc = rv;
8755
	}
8756
	if (p->majv < 0 || p->majv > 99			/* Sanity check version numbers */
8757
	 || p->minv < 0 || p->minv > 9
8758
	 || p->bfv  < 0 || p->bfv  > 9) {
8759
		sprintf(icp->err,"icmHeader_write: version number");
8760
		icp->al->free(icp->al, buf);
8761
		return icp->errc = 1;
8762
	}
8763
	tt = ((p->majv/10) << 4) + (p->majv % 10);
8764
	if ((rv = write_UInt8Number(tt, buf + 8)) != 0) {	/* Raw major version number */
8765
		sprintf(icp->err,"icmHeader_write: Uint8Number major version");
8766
		icp->al->free(icp->al, buf);
8767
		return icp->errc = rv;
8768
	}
8769
    tt = (p->minv << 4) + p->bfv;
8770
	if ((rv = write_UInt8Number(tt, buf + 9)) != 0) {	/* Raw minor/bug fix version numbers */
8771
		sprintf(icp->err,"icmHeader_write: Uint8Number minor/bug fix");
8772
		icp->al->free(icp->al, buf);
8773
		return icp->errc = rv;
8774
	}
8775
	if ((rv = write_SInt32Number((int)p->deviceClass, buf + 12)) != 0) {	/* Type of profile */
8776
		sprintf(icp->err,"icmHeader_write: SInt32Number deviceClass");
8777
		icp->al->free(icp->al, buf);
8778
		return icp->errc = rv;
8779
	}
8780
	if ((rv = write_SInt32Number((int)p->colorSpace, buf + 16)) != 0) {	/* Color space of data */
8781
		sprintf(icp->err,"icmHeader_write: SInt32Number data color space");
8782
		icp->al->free(icp->al, buf);
8783
		return icp->errc = rv;
8784
	}
8785
	if ((rv = write_SInt32Number((int)p->pcs, buf + 20)) != 0) {		/* PCS: XYZ or Lab */
8786
		sprintf(icp->err,"icmHeader_write: SInt32Number PCS");
8787
		icp->al->free(icp->al, buf);
8788
		return icp->errc = rv;
8789
	}
8790
	if ((rv = write_DateTimeNumber(&p->date, buf + 24)) != 0) {		/* Creation Date */
8791
		sprintf(icp->err,"icmHeader_write: DateTimeNumber creation");
8792
		icp->al->free(icp->al, buf);
8793
		return icp->errc = rv;
8794
	}
8795
	if ((rv = write_SInt32Number(icMagicNumber, buf+36)) != 0) {		/* Magic number */
8796
		sprintf(icp->err,"icmHeader_write: SInt32Number magic");
8797
		icp->al->free(icp->al, buf);
8798
		return icp->errc = rv;
8799
	}
8800
	if ((rv = write_SInt32Number((int)p->platform, buf + 40)) != 0) {	/* Primary platform */
8801
		sprintf(icp->err,"icmHeader_write: SInt32Number platform");
8802
		icp->al->free(icp->al, buf);
8803
		return icp->errc = rv;
8804
	}
8805
    if ((rv = write_UInt32Number(p->flags, buf + 44)) != 0) {			/* Various bits */
8806
		sprintf(icp->err,"icmHeader_write: UInt32Number flags");
8807
		icp->al->free(icp->al, buf);
8808
		return icp->errc = rv;
8809
	}
8810
    if ((rv = write_SInt32Number(p->manufacturer, buf + 48)) != 0) { /* Dev manufacturer */
8811
		sprintf(icp->err,"icmHeader_write: SInt32Number manufaturer");
8812
		icp->al->free(icp->al, buf);
8813
		return icp->errc = rv;
8814
	}
8815
    if ((write_SInt32Number(p->model, buf + 52)) != 0) {				/* Dev model */
8816
		sprintf(icp->err,"icmHeader_write: SInt32Number model");
8817
		icp->al->free(icp->al, buf);
8818
		return icp->errc = rv;
8819
	}
8820
    if ((rv = write_UInt64Number(&p->attributes, buf + 56)) != 0) {	/* Device attributes */
8821
		sprintf(icp->err,"icmHeader_write: UInt64Number attributes");
8822
		icp->al->free(icp->al, buf);
8823
		return icp->errc = rv;
8824
	}
8825
	if ((rv = write_SInt32Number((int)p->renderingIntent, buf + 64)) != 0) { /* Rendering intent */
8826
		sprintf(icp->err,"icmHeader_write: SInt32Number rendering intent");
8827
		icp->al->free(icp->al, buf);
8828
		return icp->errc = rv;
8829
	}
8830
	if ((rv = write_XYZNumber(&p->illuminant, buf + 68)) != 0) {		/* Profile illuminant */
8831
		sprintf(icp->err,"icmHeader_write: XYZNumber illuminant");
8832
		icp->al->free(icp->al, buf);
8833
		return icp->errc = rv;
8834
	}
8835
    if ((rv = write_SInt32Number(p->creator, buf + 80)) != 0) {		/* Profile creator */
8836
		sprintf(icp->err,"icmHeader_write: SInt32Number creator");
8837
		icp->al->free(icp->al, buf);
8838
		return icp->errc = rv;
8839
	}
8840
 
8841
	if (   icp->fp->seek(icp->fp, of) != 0
8842
	    || icp->fp->write(icp->fp, buf, 1, len) != len) {
8843
		sprintf(icp->err,"icmHeader_write fseek() or fwrite() failed");
8844
		icp->al->free(icp->al, buf);
8845
		return icp->errc = 2;
8846
	}
8847
 
8848
	icp->al->free(icp->al, buf);
8849
	return rv;
8850
}
8851
 
8852
static void icmHeader_dump(
8853
	icmHeader *p,
8854
	FILE *op,		/* Output to dump to */
8855
	int   verb		/* Verbosity level */
8856
) {
8857
	if (verb <= 0)
8858
		return;
8859
 
8860
	fprintf(op,"Header:\n");
8861
	fprintf(op,"  size         = %d bytes\n",p->size);
8862
	fprintf(op,"  CMM          = %s\n",tag2str(p->cmmId));
8863
	fprintf(op,"  Version      = %d.%d.%d\n",p->majv, p->minv, p->bfv);
8864
	fprintf(op,"  Device Class = %s\n", string_ProfileClassSignature(p->deviceClass));
8865
	fprintf(op,"  Color Space  = %s\n", string_ColorSpaceSignature(p->colorSpace));
8866
	fprintf(op,"  Conn. Space  = %s\n", string_ColorSpaceSignature(p->pcs));
8867
	fprintf(op,"  Date, Time   = %s\n", string_DateTimeNumber(&p->date));
8868
	fprintf(op,"  Platform     = %s\n", string_PlatformSignature(p->platform));
8869
	fprintf(op,"  Flags        = %s\n", string_ProfileHeaderFlags(p->flags));
8870
	fprintf(op,"  Dev. Mnfctr. = %s\n",tag2str(p->manufacturer));	/* ~~~ */
8871
	fprintf(op,"  Dev. Model   = %s\n",tag2str(p->model));	/* ~~~ */
8872
	fprintf(op,"  Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l));
8873
	fprintf(op,"  Rndrng Intnt = %s\n", string_RenderingIntent(p->renderingIntent));
8874
	fprintf(op,"  Illuminant   = %s\n", string_XYZNumber_and_Lab(&p->illuminant));
8875
	fprintf(op,"  Creator      = %s\n",tag2str(p->creator));	/* ~~~ */
8876
	fprintf(op,"\n");
8877
}
8878
 
8879
static void icmHeader_delete(
8880
	icmHeader *p
8881
) {
8882
	icc *icp = p->icp;
8883
 
8884
	icp->al->free(icp->al, p);
8885
}
8886
 
8887
/* Create an empty object. Return null on error */
8888
static icmHeader *new_icmHeader(
8889
	icc *icp
8890
) {
8891
	icmHeader *p;
8892
	if ((p = (icmHeader *) icp->al->calloc(icp->al,1,sizeof(icmHeader))) == NULL)
8893
		return NULL;
8894
	p->icp      = icp;
8895
	p->get_size = icmHeader_get_size;
8896
	p->read     = icmHeader_read;
8897
	p->write    = icmHeader_write;
8898
	p->dump     = icmHeader_dump;
8899
	p->del      = icmHeader_delete;
8900
 
8901
	return p;
8902
}
8903
 
8904
/* ---------------------------------------------------------- */
8905
/* Type vector table. Match the Tag type against the object creator */
8906
static struct {
8907
	icTagTypeSignature  ttype;			/* The tag type signature */
8908
	icmBase *              (*new_obj)(icc *icp);
8909
} typetable[] = {
8910
	{icSigCrdInfoType,             new_icmCrdInfo},
8911
	{icSigCurveType,               new_icmCurve},
8912
	{icSigDataType,                new_icmData},
8913
	{icSigDateTimeType,            new_icmDateTimeNumber},
8914
	{icSigLut16Type,               new_icmLut},
8915
	{icSigLut8Type,                new_icmLut},
8916
	{icSigMeasurementType,         new_icmMeasurement},
8917
	{icSigNamedColorType,          new_icmNamedColor},
8918
	{icSigNamedColor2Type,         new_icmNamedColor},
8919
	{icSigProfileSequenceDescType, new_icmProfileSequenceDesc},
8920
	{icSigS15Fixed16ArrayType,     new_icmS15Fixed16Array},
8921
	{icSigScreeningType,           new_icmScreening},
8922
	{icSigSignatureType,           new_icmSignature},
8923
	{icSigTextDescriptionType,     new_icmTextDescription},
8924
	{icSigTextType,                new_icmText},
8925
	{icSigU16Fixed16ArrayType,     new_icmU16Fixed16Array},
8926
	{icSigUcrBgType,               new_icmUcrBg},
8927
	{icSigVideoCardGammaType,      new_icmVideoCardGamma},
8928
	{icSigUInt16ArrayType,         new_icmUInt16Array},
8929
	{icSigUInt32ArrayType,         new_icmUInt32Array},
8930
	{icSigUInt64ArrayType,         new_icmUInt64Array},
8931
	{icSigUInt8ArrayType,          new_icmUInt8Array},
8932
	{icSigViewingConditionsType,   new_icmViewingConditions},
8933
	{icSigXYZArrayType,            new_icmXYZArray},
8934
	{icMaxEnumType,                NULL}
8935
}; 
8936
 
8937
/* Table that lists the legal Types for each Tag Signature */
8938
static struct {
8939
	icTagSignature      sig;
8940
	icTagTypeSignature  ttypes[4];			/* Arbitrary max of 4 */
8941
} sigtypetable[] = {
8942
	{icSigAToB0Tag,					{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8943
	{icSigAToB1Tag,					{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8944
	{icSigAToB2Tag,					{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8945
	{icSigBlueColorantTag,			{icSigXYZType,icMaxEnumType}},
8946
	{icSigBlueTRCTag,				{icSigCurveType,icMaxEnumType}},
8947
	{icSigBToA0Tag,					{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8948
	{icSigBToA1Tag,					{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8949
	{icSigBToA2Tag,					{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8950
	{icSigCalibrationDateTimeTag,	{icSigDateTimeType,icMaxEnumType}},
8951
	{icSigCharTargetTag,			{icSigTextType,icMaxEnumType}},
8952
	{icSigCopyrightTag,				{icSigTextType,icMaxEnumType}},
8953
	{icSigCrdInfoTag,				{icSigCrdInfoType,icMaxEnumType}},
8954
	{icSigDeviceMfgDescTag,			{icSigTextDescriptionType,icMaxEnumType}},
8955
	{icSigDeviceModelDescTag,		{icSigTextDescriptionType,icMaxEnumType}},
8956
	{icSigGamutTag,					{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8957
	{icSigGrayTRCTag,				{icSigCurveType,icMaxEnumType}},
8958
	{icSigGreenColorantTag,			{icSigXYZType,icMaxEnumType}},
8959
	{icSigGreenTRCTag,				{icSigCurveType,icMaxEnumType}},
8960
	{icSigLuminanceTag,				{icSigXYZType,icMaxEnumType}},
8961
	{icSigMeasurementTag,			{icSigMeasurementType,icMaxEnumType}},
8962
	{icSigMediaBlackPointTag,		{icSigXYZType,icMaxEnumType}},
8963
	{icSigMediaWhitePointTag,		{icSigXYZType,icMaxEnumType}},
8964
	{icSigNamedColorTag,			{icSigNamedColorType,icMaxEnumType}},
8965
	{icSigNamedColor2Tag,			{icSigNamedColor2Type,icMaxEnumType}},
8966
	{icSigPreview0Tag,				{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8967
	{icSigPreview1Tag,				{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8968
	{icSigPreview2Tag,				{icSigLut8Type,icSigLut16Type,icMaxEnumType}},
8969
	{icSigProfileDescriptionTag,	{icSigTextDescriptionType,icMaxEnumType}},
8970
	{icSigProfileSequenceDescTag,	{icSigProfileSequenceDescType,icMaxEnumType}},
8971
	{icSigPs2CRD0Tag,				{icSigDataType,icMaxEnumType}},
8972
	{icSigPs2CRD1Tag,				{icSigDataType,icMaxEnumType}},
8973
	{icSigPs2CRD2Tag,				{icSigDataType,icMaxEnumType}},
8974
	{icSigPs2CRD3Tag,				{icSigDataType,icMaxEnumType}},
8975
	{icSigPs2CSATag,				{icSigDataType,icMaxEnumType}},
8976
	{icSigPs2RenderingIntentTag,	{icSigDataType,icMaxEnumType}},
8977
	{icSigRedColorantTag,			{icSigXYZType,icMaxEnumType}},
8978
	{icSigRedTRCTag,				{icSigCurveType,icMaxEnumType}},
8979
	{icSigScreeningDescTag,			{icSigTextDescriptionType,icMaxEnumType}},
8980
	{icSigScreeningTag,				{icSigScreeningType,icMaxEnumType}},
8981
	{icSigTechnologyTag,			{icSigSignatureType,icMaxEnumType}},
8982
	{icSigUcrBgTag,					{icSigUcrBgType,icMaxEnumType}},
8983
	{icSigVideoCardGammaTag,		{icSigVideoCardGammaType,icMaxEnumType}},
8984
	{icSigViewingCondDescTag,		{icSigTextDescriptionType,icMaxEnumType}},
8985
	{icSigViewingConditionsTag,		{icSigViewingConditionsType,icMaxEnumType}},
8986
	{icMaxEnumType,					{icMaxEnumType}}
8987
}; 
8988
 
8989
/* Fake color tag for specifying PCS */
8990
#define icSigPCSData  ((icColorSpaceSignature) 0x50435320L)
8991
 
8992
/* Table that lists the required tags for various profiles */
8993
static struct {
8994
	icProfileClassSignature sig;		/* Profile signature */
8995
	int      			    chans;		/* Data Color channels, -ve for match but try next, */
8996
										/*          -100 for ignore, -200 for ignore and try next */
8997
	icColorSpaceSignature   colsig;		/* Data Color space signature, icMaxEnumData for ignore, */
8998
										/*                           icSigPCSData for XYZ of Lab */
8999
	icColorSpaceSignature   pcssig;		/* PCS Color space signature, icMaxEnumData for ignore, */
9000
										/*                          icSigPCSData for XYZ or Lab */
9001
	icTagSignature          tags[12];	/* Arbitrary max of 12 */
9002
} tagchecktable[] = {
9003
    {icSigInputClass,      -1, icMaxEnumData, icSigPCSData,
9004
	 	{icSigProfileDescriptionTag,
9005
		 icSigGrayTRCTag,
9006
		 icSigMediaWhitePointTag,
9007
		 icSigCopyrightTag, icMaxEnumType}},
9008
 
9009
    {icSigInputClass,      -3, icMaxEnumData, icSigXYZData,
9010
	 	{icSigProfileDescriptionTag,
9011
		 icSigRedColorantTag,
9012
		 icSigGreenColorantTag,
9013
		 icSigBlueColorantTag,
9014
		 icSigRedTRCTag,
9015
		 icSigGreenTRCTag,
9016
		 icSigBlueTRCTag,
9017
		 icSigMediaWhitePointTag,
9018
		 icSigCopyrightTag, icMaxEnumType}},
9019
 
9020
    {icSigInputClass,     -100, icMaxEnumData, icSigPCSData,
9021
	 	{icSigProfileDescriptionTag,
9022
		 icSigAToB0Tag,
9023
		 icSigMediaWhitePointTag,
9024
		 icSigCopyrightTag, icMaxEnumType}},
9025
 
9026
    {icSigDisplayClass,     -1, icMaxEnumData, icSigPCSData,
9027
	 	{icSigProfileDescriptionTag,
9028
		 icSigGrayTRCTag,
9029
		 icSigMediaWhitePointTag,
9030
		 icSigCopyrightTag, icMaxEnumType}},
9031
 
9032
    {icSigDisplayClass,     -3, icSigRgbData, icSigXYZData,	/* Rgb or any 3 component space ?? */
9033
	 	{icSigProfileDescriptionTag,
9034
		 icSigRedColorantTag,
9035
		 icSigGreenColorantTag,
9036
		 icSigBlueColorantTag,
9037
		 icSigRedTRCTag,
9038
		 icSigGreenTRCTag,
9039
		 icSigBlueTRCTag,
9040
		 icSigMediaWhitePointTag,
9041
		 icSigCopyrightTag, icMaxEnumType}},
9042
 
9043
	/* Non-3 component Display device */
9044
    {icSigDisplayClass,     -100, icMaxEnumData, icSigPCSData,
9045
	 	{icSigProfileDescriptionTag,
9046
		 icSigAToB0Tag,					/* BToA doesn't seem to be required, which is strange... */
9047
		 icSigMediaWhitePointTag,
9048
		 icSigCopyrightTag, icMaxEnumType}},
9049
 
9050
    {icSigOutputClass,     -1, icMaxEnumData, icSigPCSData,
9051
	 	{icSigProfileDescriptionTag,
9052
		 icSigGrayTRCTag,
9053
		 icSigMediaWhitePointTag,
9054
		 icSigCopyrightTag, icMaxEnumType}},
9055
 
9056
    {icSigOutputClass,     -1, icMaxEnumData, icSigPCSData,
9057
	 	{icSigProfileDescriptionTag,
9058
		 icSigAToB0Tag,
9059
		 icSigBToA0Tag,
9060
		 icSigGamutTag,
9061
		 icSigAToB1Tag,
9062
		 icSigBToA1Tag,
9063
		 icSigAToB2Tag,
9064
		 icSigBToA2Tag,
9065
		 icSigMediaWhitePointTag,
9066
		 icSigCopyrightTag, icMaxEnumType}},
9067
 
9068
    {icSigOutputClass,     -2, icMaxEnumData, icSigPCSData,
9069
	 	{icSigProfileDescriptionTag,
9070
		 icSigAToB0Tag,
9071
		 icSigBToA0Tag,
9072
		 icSigGamutTag,
9073
		 icSigAToB1Tag,
9074
		 icSigBToA1Tag,
9075
		 icSigAToB2Tag,
9076
		 icSigBToA2Tag,
9077
		 icSigMediaWhitePointTag,
9078
		 icSigCopyrightTag, icMaxEnumType}},
9079
 
9080
    {icSigOutputClass,     -3, icMaxEnumData, icSigPCSData,
9081
	 	{icSigProfileDescriptionTag,
9082
		 icSigAToB0Tag,
9083
		 icSigBToA0Tag,
9084
		 icSigGamutTag,
9085
		 icSigAToB1Tag,
9086
		 icSigBToA1Tag,
9087
		 icSigAToB2Tag,
9088
		 icSigBToA2Tag,
9089
		 icSigMediaWhitePointTag,
9090
		 icSigCopyrightTag, icMaxEnumType}},
9091
 
9092
    {icSigOutputClass,     -4, icMaxEnumData, icSigPCSData,
9093
	 	{icSigProfileDescriptionTag,
9094
		 icSigAToB0Tag,
9095
		 icSigBToA0Tag,
9096
		 icSigGamutTag,
9097
		 icSigAToB1Tag,
9098
		 icSigBToA1Tag,
9099
		 icSigAToB2Tag,
9100
		 icSigBToA2Tag,
9101
		 icSigMediaWhitePointTag,
9102
		 icSigCopyrightTag, icMaxEnumType}},
9103
 
9104
    {icSigOutputClass,     -100, icMaxEnumData, icSigPCSData,	/* Assumed from Hexachrome examples */
9105
	 	{icSigProfileDescriptionTag,
9106
		 icSigBToA0Tag,
9107
		 icSigBToA1Tag,
9108
		 icSigBToA2Tag,
9109
		 icSigMediaWhitePointTag,
9110
		 icSigCopyrightTag, icMaxEnumType}},
9111
 
9112
    {icSigLinkClass,      -100, icMaxEnumData, icMaxEnumData,
9113
	 	{icSigProfileDescriptionTag,
9114
		 icSigAToB0Tag,
9115
		 icSigProfileSequenceDescTag,
9116
		 icSigCopyrightTag, icMaxEnumType}},
9117
 
9118
    {icSigColorSpaceClass,       -100, icMaxEnumData, icSigPCSData,
9119
	 	{icSigProfileDescriptionTag,
9120
		 icSigBToA0Tag,
9121
		 icSigAToB0Tag,
9122
		 icSigMediaWhitePointTag,
9123
		 icSigCopyrightTag, icMaxEnumType}},
9124
 
9125
    {icSigAbstractClass,      -100, icSigPCSData, icSigPCSData,
9126
	 	{icSigProfileDescriptionTag,
9127
		 icSigAToB0Tag,
9128
		 icSigMediaWhitePointTag,
9129
		 icSigCopyrightTag, icMaxEnumType}},
9130
 
9131
    {icSigNamedColorClass,        -200, icMaxEnumData, icMaxEnumData,
9132
	 	{icSigProfileDescriptionTag,
9133
		 icSigNamedColor2Tag,
9134
		 icSigMediaWhitePointTag,
9135
		 icSigCopyrightTag, icMaxEnumType}},
9136
 
9137
    {icSigNamedColorClass,        -100, icMaxEnumData, icMaxEnumData,
9138
	 	{icSigProfileDescriptionTag,
9139
		 icSigNamedColorTag,				/* Not strictly V3.4 */
9140
		 icSigMediaWhitePointTag,
9141
		 icSigCopyrightTag, icMaxEnumType}},
9142
 
9143
	{icMaxEnumType,-1,icMaxEnumData, icMaxEnumData,		{icMaxEnumType}}
9144
}; 
9145
 
9146
/* ------------------------------------------------------------- */
9147
/* Check that the ICC profile looks like it will be legal. */
9148
/* Return non-zero and set error string if not */
9149
static int check_icc_legal(
9150
	icc *p
9151
) {
9152
	int i, j;
9153
	icProfileClassSignature  sig;
9154
	icColorSpaceSignature colsig;
9155
	icColorSpaceSignature pcssig;
9156
	int      	          dchans;
9157
 
9158
	if (p->header == NULL) {
9159
		sprintf(p->err,"icc_check_legal: Header is missing");
9160
		return p->errc = 1;
9161
	}
9162
 
9163
	sig = p->header->deviceClass;
9164
	colsig = p->header->colorSpace;
9165
	dchans = number_ColorSpaceSignature(colsig);
9166
	pcssig = p->header->pcs;
9167
 
9168
	/* Find a matching table entry */
9169
	for (i = 0; tagchecktable[i].sig != icMaxEnumType; i++) {
9170
		if (    tagchecktable[i].sig   == sig
9171
		 && (   tagchecktable[i].chans == dchans	/* Exactly matches */
9172
		     || tagchecktable[i].chans == -dchans	/* Exactly matches, but can try next table */
9173
		     || tagchecktable[i].chans < -99)		/* Doesn't have to match or try next table */
9174
		 && (   tagchecktable[i].colsig == colsig
9175
		     || (tagchecktable[i].colsig == icSigPCSData
9176
		         && (colsig == icSigXYZData || colsig == icSigLabData))
9177
		     || tagchecktable[i].colsig == icMaxEnumData)
9178
		 && (   tagchecktable[i].pcssig == pcssig
9179
		     || (tagchecktable[i].pcssig == icSigPCSData
9180
		         && (pcssig == icSigXYZData || pcssig == icSigLabData))
9181
		     || tagchecktable[i].pcssig == icMaxEnumData)) {
9182
 
9183
			/* Found entry, so now check that all the required tags are present. */
9184
			for (j = 0; tagchecktable[i].tags[j] != icMaxEnumType; j++) {
9185
				if (p->find_tag(p, tagchecktable[i].tags[j]) != 0) {	/* Not present! */
9186
					if (tagchecktable[i].chans == -200
9187
					 || tagchecktable[i].chans == -dchans) {	/* But can try next table */
9188
						break;
9189
					}
9190
					sprintf(p->err,"icc_check_legal: deviceClass %s is missing required tag %s",
9191
					               tag2str(sig), tag2str(tagchecktable[i].tags[j]));
9192
					return p->errc = 1;
9193
				}
9194
			}
9195
			if (tagchecktable[i].tags[j] == icMaxEnumType) {
9196
				break;		/* Fount all required tags */
9197
			}
9198
		}
9199
	}
9200
 
9201
	/* According to the spec. if the deviceClass is:
9202
		an Abstract Class: both in and out color spaces should be PCS
9203
		an Link Class: both in and out color spaces can be any, and should
9204
		    be the input space of the first profile in the link, and the
9205
		    input space of the last profile in the link respectively.
9206
		a Named Class: in and out color spaces are not defined in the spec.
9207
		Input, Display, Output and ColorSpace Classes, input color
9208
		    space can be any, and the output space must be PCS.
9209
		~~ should check this here ???
9210
	*/
9211
 
9212
	return 0;	/* Assume anything is ok */
9213
}
9214
 
9215
 
9216
/* read the object, return 0 on success, error code on fail */
9217
/* NOTE: this doesn't read the tag types, they should be read on demand. */
9218
static int icc_read(
9219
	icc *p,
9220
	icmFile *fp,			/* File to read from */
9221
	unsigned long of		/* File offset to read from */
9222
) {
9223
	char tcbuf[4];			/* Tag count read buffer */
9224
	int i;
9225
	unsigned int len;
9226
	int er = 0;				/* Error code */
9227
 
9228
	p->fp = fp;
9229
	p->of = of;
9230
	if (p->header == NULL) {
9231
		sprintf(p->err,"icc_read: No header defined");
9232
		return p->errc = 1;
9233
	}
9234
 
9235
	/* Read the header */
9236
	if (p->header->read(p->header, 128, of)) {
9237
		return 1;
9238
	}
9239
 
9240
	/* Read the tag count */
9241
	if (   p->fp->seek(p->fp, of + 128) != 0
9242
	    || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
9243
		sprintf(p->err,"icc_read: fseek() or fread() failed on tag count");
9244
		return p->errc = 1;
9245
	}
9246
 
9247
	p->count = read_UInt32Number(tcbuf);		/* Tag count */
9248
	if (p->count > 0) {
9249
		char *bp, *buf;
9250
		if ((p->data = (icmTag *) p->al->malloc(p->al, p->count * sizeof(icmTag))) == NULL) {
9251
			sprintf(p->err,"icc_read: Tag table malloc() failed");
9252
			return p->errc = 2;
9253
		}
9254
 
9255
		len = 4 + p->count * 12;
9256
		if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) {
9257
			sprintf(p->err,"icc_read: Tag table read buffer malloc() failed");
9258
			p->al->free(p->al, p->data);
9259
			p->data = NULL;
9260
			return p->errc = 2;
9261
		}
9262
		if (   p->fp->seek(p->fp, of + 128) != 0
9263
		    || p->fp->read(p->fp, buf, 1, len) != len) {
9264
			sprintf(p->err,"icc_read: fseek() or fread() failed on tag table");
9265
			p->al->free(p->al, p->data);
9266
			p->data = NULL;
9267
			p->al->free(p->al, buf);
9268
			return p->errc = 1;
9269
		}
9270
 
9271
		/* Fill in the tag table structure */
9272
		bp = buf+4;
9273
		for (i = 0; i < p->count; i++, bp += 12) {
9274
	    	p->data[i].sig = (icTagSignature)read_SInt32Number(bp + 0);	
9275
	    	p->data[i].offset = read_UInt32Number(bp + 4);
9276
	    	p->data[i].size = read_UInt32Number(bp + 8);	
9277
			if (   p->fp->seek(p->fp, of + p->data[i].offset) != 0
9278
			    || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
9279
				sprintf(p->err,"icc_read: fseek() or fread() failed on tag headers");
9280
				p->al->free(p->al, p->data);
9281
				p->data = NULL;
9282
				p->al->free(p->al, buf);
9283
				return p->errc = 1;
9284
			}
9285
	    	p->data[i].ttype = read_SInt32Number(tcbuf);		/* Tag type */
9286
	    	p->data[i].objp = NULL;							/* Read on demand */
9287
		}
9288
		p->al->free(p->al, buf);
9289
	}	/* p->count > 0 */
9290
 
9291
	return er;
9292
}
9293
 
9294
#define DO_ALIGN(val) (((val) + 3) & ~3)
9295
 
9296
/* Return the total size needed for the profile */
9297
/* Return 0 on error. */
9298
static unsigned int icc_get_size(
9299
	icc *p
9300
) {
9301
	unsigned int size = 0;
9302
	int i;
9303
 
9304
	/* Check that the right tags etc. are present for a legal ICC profile */
9305
	if (check_icc_legal(p) != 0) {
9306
		return 0;
9307
	}
9308
 
9309
	/* Compute the total size and tag element data offsets */
9310
	if (p->header == NULL) {
9311
		sprintf(p->err,"icc_get_size: No header defined");
9312
		p->errc = 1;
9313
		return 0;
9314
	}
9315
 
9316
	size += p->header->get_size(p->header);
9317
 
9318
	size = DO_ALIGN(size);
9319
	size += 4 + p->count * 12;	/* Tag table length */
9320
 
9321
	/* Reset touched flag for each tag type */
9322
	for (i = 0; i < p->count; i++) {
9323
		if (p->data[i].objp == NULL) {
9324
			sprintf(p->err,"icc_get_size: Internal error - NULL tag element");
9325
			p->errc = 1;
9326
			return 0;
9327
		}
9328
		p->data[i].objp->touched = 0;
9329
	}
9330
	/* Get size for each tag type, skipping links */
9331
	for (i = 0; i < p->count; i++) {
9332
		if (p->data[i].objp->touched == 0) { /* Not alllowed for previously */
9333
			size = DO_ALIGN(size);
9334
			size += p->data[i].objp->get_size(p->data[i].objp);
9335
			p->data[i].objp->touched = 1;	/* Don't account for this again */
9336
		}
9337
	}
9338
 
9339
	return size;	/* Total size needed */
9340
}
9341
 
9342
/* Write the contents of the object. Return 0 on sucess, error code on failure */
9343
static int icc_write(
9344
	icc *p,
9345
	icmFile *fp,		/* File to write to */
9346
	unsigned long of	/* File offset to write to */
9347
) {
9348
	char *bp, *buf;		/* Buffer to write to */
9349
	unsigned int len;
9350
	int rv = 0;
9351
	int i;
9352
	unsigned int size = 0;
9353
 
9354
	/* Check that the right tags etc. are present for a legal ICC profile */
9355
	if ((rv = check_icc_legal(p)) != 0) {
9356
		return rv;
9357
	}
9358
 
9359
	p->fp = fp;			/* Open file pointer */
9360
	p->of = of;			/* Offset of ICC profile */
9361
 
9362
	/* Compute the total size and tag element data offsets */
9363
	if (p->header == NULL) {
9364
		sprintf(p->err,"icc_write: No header defined");
9365
		return p->errc = 1;
9366
	}
9367
 
9368
	size += p->header->get_size(p->header);
9369
 
9370
	len = 4 + p->count * 12;	/* Tag table length */
9371
	size = DO_ALIGN(size);
9372
	size += len;
9373
 
9374
	/* Allocate memory buffer for tag table */
9375
	if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) {
9376
		sprintf(p->err,"icc_write malloc() failed");
9377
		return p->errc = 2;
9378
	}
9379
	bp = buf;
9380
 
9381
    if ((rv = write_UInt32Number(p->count, bp)) != 0) {		/* Tag count */
9382
		sprintf(p->err,"icc_write: write_UInt32Number() failed on tag count");
9383
		p->al->free(p->al, buf);
9384
		return p->errc = rv;
9385
	}
9386
	bp += 4;
9387
	/* Reset touched flag for each tag type */
9388
	for (i = 0; i < p->count; i++) {
9389
		if (p->data[i].objp == NULL) {
9390
			sprintf(p->err,"icc_write: Internal error - NULL tag element");
9391
			p->al->free(p->al, buf);
9392
			return p->errc = 1;
9393
		}
9394
		p->data[i].objp->touched = 0;
9395
	}
9396
	/* Set the offset and size for each tag type */
9397
	for (i = 0; i < p->count; i++) {
9398
		if (p->data[i].objp->touched == 0) {	/* Allocate space for tag type */
9399
			size = DO_ALIGN(size);
9400
			p->data[i].offset = size;			/* Profile relative target */
9401
			p->data[i].size = p->data[i].objp->get_size(p->data[i].objp);
9402
			size += p->data[i].size;
9403
			p->data[i].objp->touched = 1;	/* Allocated space for it */
9404
		} else { /* must be linked - copy allocation */
9405
			int k;
9406
			for (k = 0; k < p->count; k++) {	/* Find linked tag */
9407
				if (p->data[k].objp == p->data[i].objp)
9408
					break;
9409
			}
9410
			if (k == p->count) {
9411
				sprintf(p->err,"icc_write: corrupted link"); 
9412
				return p->errc = 2;
9413
			}
9414
		    p->data[i].offset = p->data[k].offset;
9415
		    p->data[i].size   = p->data[k].size;
9416
		}
9417
		/* Write tag table entry for this tag */
9418
		if ((rv = write_SInt32Number((int)p->data[i].sig,bp + 0)) != 0) {
9419
			sprintf(p->err,"icc_write: write_SInt32Number() failed on tag signature");
9420
			p->al->free(p->al, buf);
9421
			return p->errc = rv;
9422
		}
9423
		if ((rv = write_UInt32Number(p->data[i].offset, bp + 4)) != 0) {
9424
			sprintf(p->err,"icc_write: write_UInt32Number() failed on tag offset");
9425
			p->al->free(p->al, buf);
9426
			return p->errc = rv;
9427
		}
9428
		if ((rv = write_UInt32Number(p->data[i].size, bp + 8)) != 0) {
9429
			sprintf(p->err,"icc_write: write_UInt32Number() failed on tag size");
9430
			p->al->free(p->al, buf);
9431
			return p->errc = rv;
9432
		}
9433
		bp += 12;
9434
	}
9435
	p->header->size = size;		/* Record total icc size */
9436
 
9437
	/* Write the header */
9438
	if ((rv = p->header->write(p->header, of)) != 0) {
9439
		p->al->free(p->al, buf);
9440
		return rv;
9441
	}
9442
 
9443
	/* Write the tag table */
9444
	if (   p->fp->seek(p->fp, of + 128) != 0
9445
	    || p->fp->write(p->fp, buf, 1, len) != len) {
9446
		sprintf(p->err,"icc_write: fseek() or fwrite() failed");
9447
		p->al->free(p->al, buf);
9448
		return p->errc = 1;
9449
	}
9450
	p->al->free(p->al, buf);
9451
 
9452
	/* Write all the tag element data */
9453
	for (i = 0; i < p->count; i++) {	/* For all the tag element data */
9454
		if (p->data[i].objp->touched == 0)
9455
			continue;		/* Must be linked, and we've already written it */
9456
		if ((rv = p->data[i].objp->write(p->data[i].objp, of + p->data[i].offset)) != 0) {
9457
			return rv;
9458
		}
9459
		p->data[i].objp->touched = 0;	/* Written it */
9460
	}
9461
 
9462
	if (p->fp->flush(p->fp) != 0) {
9463
		sprintf(p->err,"icc_write flush() failed");
9464
		p->al->free(p->al, buf);
9465
		return p->errc = 2;
9466
	}
9467
	return rv;
9468
}
9469
#undef DO_ALIGN
9470
 
9471
/* Create and add a tag with the given signature. */
9472
/* Returns a pointer to the element object */
9473
/* Returns NULL if error - icc->errc will contain */
9474
/* 2 on system error, */
9475
/* 3 if unknown tag */
9476
/* NOTE: that we prevent tag duplication */
9477
static icmBase *icc_add_tag(
9478
	icc *p,
9479
    icTagSignature sig,			/* Tag signature - may be unknown */
9480
	icTagTypeSignature  ttype	/* Tag type */
9481
) {
9482
	icmBase *tp;
9483
	icmBase *nob;
9484
	int i, j, ok = 1;
9485
 
9486
	/* Check that a known signature has an acceptable type */
9487
	for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
9488
		if (sigtypetable[i].sig == sig) {	/* recognized signature */
9489
			ok = 0;
9490
			for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
9491
				if (sigtypetable[i].ttypes[j] == ttype)	/* recognized type */
9492
					ok = 1;
9493
			}
9494
			break;
9495
		}
9496
	}
9497
	if (!ok) {
9498
		sprintf(p->err,"icc_add_tag: wrong tag type for signature");
9499
		p->errc = 1;
9500
		return NULL;
9501
	}
9502
 
9503
	/* Check that we know how to handle this type */
9504
	for (i = 0; typetable[i].ttype != icMaxEnumType; i++) {
9505
		if (typetable[i].ttype == ttype)
9506
			break;
9507
	}
9508
	if (typetable[i].ttype == icMaxEnumType) {
9509
		sprintf(p->err,"icc_add_tag: unsupported tag type");
9510
		p->errc = 1;
9511
		return NULL;
9512
	}
9513
 
9514
	/* Check that this tag doesn't already exits */
9515
	/* (Perhaps we should simply replace it, rather than erroring ?) */
9516
	for (j = 0; j < p->count; j++) {
9517
		if (p->data[j].sig == sig) {
9518
			sprintf(p->err,"icc_add_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig)); 
9519
			p->errc = 1;
9520
			return NULL;
9521
		}
9522
	}
9523
 
9524
	/* Make space in tag table for new tag item */
9525
	if (p->data == NULL)
9526
		tp = p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
9527
	else
9528
		tp = p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
9529
	if (tp == NULL) {
9530
		sprintf(p->err,"icc_add_tag: Tag table realloc() failed");
9531
		p->errc = 2;
9532
		return NULL;
9533
	}
9534
	p->data = (icmTag *)tp;
9535
 
9536
	/* Allocate the empty object */
9537
	if ((nob = typetable[i].new_obj(p)) == NULL)
9538
		return NULL;
9539
 
9540
	/* Fill out our tag table entry */
9541
    p->data[p->count].sig = sig;		/* The tag signature */
9542
	p->data[p->count].ttype = nob->ttype = ttype;	/* The tag type signature */
9543
    p->data[p->count].offset = 0;		/* Unknown offset yet */
9544
    p->data[p->count].size = 0;			/* Unknown size yet */
9545
    p->data[p->count].objp = nob;		/* Empty object */
9546
	p->count++;
9547
 
9548
	return nob;
9549
}
9550
 
9551
/* Create and add a tag which is a link to an existing tag. */
9552
/* Returns a pointer to the element object */
9553
/* Returns NULL if error - icc->errc will contain */
9554
/* 3 if incompatible tag */
9555
/* NOTE: that we prevent tag duplication */
9556
static icmBase *icc_link_tag(
9557
	icc *p,
9558
    icTagSignature sig,			/* Tag signature - may be unknown */
9559
    icTagSignature ex_sig		/* Tag signature of tag to link to */
9560
) {
9561
	icmBase *tp;
9562
	int i, j, exi, ok = 1;
9563
 
9564
	/* Search for existing signature */
9565
	for (exi = 0; exi < p->count; exi++) {
9566
		if (p->data[exi].sig == ex_sig)		/* Found it */
9567
			break;
9568
	}
9569
	if (exi == p->count) {
9570
		sprintf(p->err,"icc_link_tag: Can't find existing tag '%s'",tag2str(ex_sig)); 
9571
		p->errc = 1;
9572
		return NULL;
9573
	}
9574
 
9575
    if (p->data[exi].objp == NULL) {
9576
		sprintf(p->err,"icc_link_tag: Existing tag '%s' isn't loaded",tag2str(ex_sig)); 
9577
		p->errc = 1;
9578
		return NULL;
9579
	}
9580
 
9581
	/* Check that a known signature has an acceptable type */
9582
	for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
9583
		if (sigtypetable[i].sig == sig) {	/* recognized signature */
9584
			ok = 0;
9585
			for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
9586
				if (sigtypetable[i].ttypes[j] == p->data[exi].ttype)	/* recognized type */
9587
					ok = 1;
9588
			}
9589
			break;
9590
		}
9591
	}
9592
	if (!ok) {
9593
		sprintf(p->err,"icc_link_tag: wrong tag type for signature");
9594
		p->errc = 1;
9595
		return NULL;
9596
	}
9597
 
9598
	/* Check that this tag doesn't already exits */
9599
	for (j = 0; j < p->count; j++) {
9600
		if (p->data[j].sig == sig) {
9601
			sprintf(p->err,"icc_link_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig)); 
9602
			p->errc = 1;
9603
			return NULL;
9604
		}
9605
	}
9606
 
9607
	/* Make space in tag table for new tag item */
9608
	if (p->data == NULL)
9609
		tp = p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
9610
	else
9611
		tp = p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
9612
	if (tp == NULL) {
9613
		sprintf(p->err,"icc_link_tag: Tag table realloc() failed");
9614
		p->errc = 2;
9615
		return NULL;
9616
	}
9617
	p->data = (icmTag *)tp;
9618
 
9619
	/* Fill out our tag table entry */
9620
    p->data[p->count].sig  = sig;		/* The tag signature */
9621
	p->data[p->count].ttype  = p->data[exi].ttype;	/* The tag type signature */
9622
    p->data[p->count].offset = p->data[exi].offset;	/* Same offset (may not be allocated yet) */
9623
    p->data[p->count].size = p->data[exi].size;		/* Same size (may not be allocated yet) */
9624
    p->data[p->count].objp = p->data[exi].objp;		/* Shared object */
9625
	p->data[exi].objp->refcount++;					/* Bump reference count on tag type */
9626
	p->count++;
9627
 
9628
	return p->data[exi].objp;
9629
}
9630
 
9631
/* Search for tag signature */
9632
/* return: */
9633
/* 0 if found */
9634
/* 1 if found but not handled type */
9635
/* 2 if not found */
9636
/* NOTE: doesn't set icc->errc or icc->err[] */
9637
/* NOTE: we don't handle tag duplication - you'll always get the first in the file. */
9638
static int icc_find_tag(
9639
	icc *p,
9640
    icTagSignature sig			/* Tag signature - may be unknown */
9641
) {
9642
	int i,j;
9643
 
9644
	/* Search for signature */
9645
	for (i = 0; i < p->count; i++) {
9646
		if (p->data[i].sig == sig)		/* Found it */
9647
			break;
9648
	}
9649
	if (i == p->count)
9650
		return 2;
9651
 
9652
	/* See if we can handle this type */
9653
	for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
9654
		if (typetable[j].ttype == p->data[i].ttype)
9655
			break;
9656
	}
9657
	if (typetable[j].ttype == icMaxEnumType)
9658
		return 1;
9659
 
9660
	return 0;
9661
}
9662
 
9663
/* Read the tag element data, and return a pointer to the object */
9664
/**
9665
 * Returns NULL if error - icc->errc will contain:
9666
 * 1 if found but not handled type
9667
 * 2 if not found
9668
 **/
9669
/* NOTE: we don't handle tag duplication - you'll always get the first in the file */
9670
static icmBase *icc_read_tag(
9671
	icc *p,
9672
    icTagSignature sig			/* Tag signature - may be unknown */
9673
) {
9674
	icmBase *nob;
9675
	int i,j,k;
9676
 
9677
	/* Search for signature */
9678
	for (i = 0; i < p->count; i++) {
9679
		if (p->data[i].sig == sig)		/* Found it */
9680
			break;
9681
	}
9682
	if (i >= p->count) {
9683
		sprintf(p->err,"icc_read_tag: Tag '%s' not found",string_TagSignature(sig));
9684
		p->errc = 2;
9685
		return NULL;
9686
	}
9687
 
9688
	/* See if it's already been read */
9689
    if (p->data[i].objp != NULL) {
9690
		return p->data[i].objp;		/* Just return it */
9691
	}
9692
 
9693
	/* See if this should be a link */
9694
	for (k = 0; k < p->count; k++) {
9695
		if (i == k)
9696
			continue;
9697
	    if (p->data[i].ttype  == p->data[k].ttype	/* Exact match and already read */
9698
	     && p->data[i].offset == p->data[k].offset
9699
	     && p->data[i].size   == p->data[k].size
9700
	     && p->data[k].objp != NULL)
9701
			break;
9702
	}
9703
	if (k < p->count) {		/* Make this a link */
9704
		p->data[i].objp = p->data[k].objp;
9705
		p->data[k].objp->refcount++;	/* Bump reference count */
9706
		return p->data[k].objp;			/* Done */
9707
	}
9708
 
9709
	/* See if we can handle this type */
9710
	for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
9711
		if (typetable[j].ttype == p->data[i].ttype)
9712
			break;
9713
	}
9714
	if (typetable[j].ttype == icMaxEnumType) {
9715
		sprintf(p->err,"icc_read_tag: Unhandled tag type '%s'",string_TypeSignature(p->data[i].ttype));
9716
		p->errc = 1;
9717
		return NULL;
9718
	}
9719
 
9720
	/* Creat and read in the object */
9721
	if ((nob = typetable[j].new_obj(p)) == NULL)
9722
		return NULL;
9723
	if ((nob->read(nob, p->data[i].size, p->of + p->data[i].offset)) != 0) {
9724
		nob->del(nob);		/* Failed, so destroy it */
9725
		return NULL;
9726
	}
9727
    p->data[i].objp = nob;
9728
	return nob;
9729
}
9730
 
9731
/* Rename a tag signature */
9732
static int icc_rename_tag(
9733
	icc *p,
9734
    icTagSignature sig,			/* Existing Tag signature - may be unknown */
9735
    icTagSignature sigNew		/* New Tag signature - may be unknown */
9736
) {
9737
	int i, j, k, ok = 1;
9738
 
9739
	/* Search for signature */
9740
	for (k = 0; k < p->count; k++) {
9741
		if (p->data[k].sig == sig)		/* Found it */
9742
			break;
9743
	}
9744
	if (k >= p->count) {
9745
		sprintf(p->err,"icc_rename_tag: Tag '%s' not found",string_TagSignature(sig));
9746
		return p->errc = 2;
9747
	}
9748
 
9749
	/* Check that a known new signature has an acceptable type */
9750
	for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
9751
		if (sigtypetable[i].sig == sigNew) {	/* recognized signature */
9752
			ok = 0;
9753
			for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
9754
				if (sigtypetable[i].ttypes[j] == p->data[k].ttype)	/* recognized type */
9755
					ok = 1;
9756
			}
9757
			break;
9758
		}
9759
	}
9760
 
9761
	if (!ok) {
9762
		sprintf(p->err,"icc_rename_tag: wrong signature for tag type");
9763
		p->errc = 1;
9764
		return p->errc;
9765
	}
9766
 
9767
	/* change its signature */
9768
	p->data[k].sig = sigNew;
9769
 
9770
	return 0;
9771
}
9772
 
9773
/* Unread the tag, and free the underlying tag type */
9774
/* if this was the last reference to it. */
9775
/* Returns non-zero on error: */
9776
/* tag not found - icc->errc will contain 2 */
9777
/* tag not read - icc->errc will contain 2 */
9778
static int icc_unread_tag(
9779
	icc *p,
9780
    icTagSignature sig		/* Tag signature - may be unknown */
9781
) {
9782
	int i;
9783
 
9784
	/* Search for signature */
9785
	for (i = 0; i < p->count; i++) {
9786
		if (p->data[i].sig == sig)		/* Found it */
9787
			break;
9788
	}
9789
	if (i >= p->count) {
9790
		sprintf(p->err,"icc_unread_tag: Tag '%s' not found",string_TagSignature(sig));
9791
		return p->errc = 2;
9792
	}
9793
 
9794
	/* See if it's been read */
9795
    if (p->data[i].objp == NULL) {
9796
		sprintf(p->err,"icc_unread_tag: Tag '%s' not currently loaded",string_TagSignature(sig));
9797
		return p->errc = 2;
9798
	}
9799
 
9800
	if (--(p->data[i].objp->refcount) == 0)			/* decrement reference count */
9801
			(p->data[i].objp->del)(p->data[i].objp);	/* Last reference */
9802
  	p->data[i].objp = NULL;
9803
 
9804
	return 0;
9805
}
9806
 
9807
/* Delete the tag, and free the underlying tag type */
9808
/* if this was the last reference to it. */
9809
/* Returns non-zero on error: */
9810
/* tag not found - icc->errc will contain 2 */
9811
static int icc_delete_tag(
9812
	icc *p,
9813
    icTagSignature sig		/* Tag signature - may be unknown */
9814
) {
9815
	int i;
9816
 
9817
	/* Search for signature */
9818
	for (i = 0; i < p->count; i++) {
9819
		if (p->data[i].sig == sig)		/* Found it */
9820
			break;
9821
	}
9822
	if (i >= p->count) {
9823
		sprintf(p->err,"icc_delete_tag: Tag '%s' not found",string_TagSignature(sig));
9824
		return p->errc = 2;
9825
	}
9826
 
9827
	/* If it's been read into memory, decrement the reference count */
9828
    if (p->data[i].objp != NULL) {
9829
		if (--(p->data[i].objp->refcount) == 0)			/* decrement reference count */
9830
			(p->data[i].objp->del)(p->data[i].objp);	/* Last reference */
9831
  		p->data[i].objp = NULL;
9832
	}
9833
 
9834
	/* Now remove it from the tag list */
9835
	for (; i < (p->count-1); i++)
9836
		p->data[i] = p->data[i+1];	/* Copy the structure down */
9837
 
9838
	p->count--;		/* One less tag in list */
9839
 
9840
	return 0;
9841
}
9842
 
9843
 
9844
/* Read all the tags into memory. */
9845
/* Returns non-zero on error. */
9846
static int icc_read_all_tags(
9847
	icc *p
9848
) {
9849
	int i;
9850
 
9851
	for (i = 0; i < p->count; i++) {	/* For all the tag element data */
9852
		icmBase *ob;
9853
		if ((ob = p->read_tag(p, p->data[i].sig)) == NULL) {
9854
			return p->errc;
9855
		}
9856
	}
9857
	return 0;
9858
}
9859
 
9860
 
9861
static void icc_dump(
9862
	icc *p,
9863
	FILE *op,		/* Output to dump to */
9864
	int   verb		/* Verbosity level */
9865
) {
9866
	int i;
9867
	if (verb <= 0)
9868
		return;
9869
 
9870
	fprintf(op,"icc:\n");
9871
 
9872
	/* Dump the header */
9873
	if (p->header != NULL)
9874
		p->header->dump(p->header,op,verb);
9875
 
9876
	/* Dump all the tag elements */
9877
	for (i = 0; i < p->count; i++) {	/* For all the tag element data */
9878
		icmBase *ob;
9879
		int tr;
9880
		fprintf(op,"tag %d:\n",i);
9881
		fprintf(op,"  sig      %s\n",tag2str(p->data[i].sig)); 
9882
		fprintf(op,"  type     %s\n",tag2str(p->data[i].ttype)); 
9883
		fprintf(op,"  offset   %d\n", p->data[i].offset);
9884
		fprintf(op,"  size     %d\n", p->data[i].size);
9885
		tr = 0;
9886
		if ((ob = p->data[i].objp) == NULL) {
9887
			/* The object is not loaded, so load it then free it */
9888
			if ((ob = p->read_tag(p, p->data[i].sig)) == NULL) {
9889
				fprintf(op,"Unable to read: %d, %s\n",p->errc,p->err);
9890
			}
9891
			tr = 1;
9892
		}
9893
		if (ob != NULL) {
9894
			/* fprintf(op,"  refcount %d\n", ob->refcount); */
9895
			ob->dump(ob,op,verb-1);
9896
 
9897
			if (tr != 0) {		/* Cleanup if temporary */
9898
				ob->refcount--;
9899
				(ob->del)(ob);
9900
				p->data[i].objp = NULL;
9901
			}
9902
		}
9903
		fprintf(op,"\n");
9904
	}
9905
}
9906
 
9907
static void icc_delete(
9908
	icc *p
9909
) {
9910
	int i;
9911
	icmAlloc *al = p->al;
9912
	int del_al   = p->del_al;
9913
 
9914
	/* Free up the header */
9915
	if (p->header != NULL)
9916
		(p->header->del)(p->header);
9917
 
9918
	/* Free up the tag data objects */
9919
	for (i = 0; i < p->count; i++) {
9920
		if (p->data[i].objp != NULL) {
9921
			if (--(p->data[i].objp->refcount) == 0)	/* decrement reference count */
9922
				(p->data[i].objp->del)(p->data[i].objp);	/* Last reference */
9923
	  	  	p->data[i].objp = NULL;
9924
		}
9925
	}
9926
 
9927
	/* Free tag table */
9928
	al->free(al, p->data);
9929
 
9930
	/* This object */
9931
	al->free(al, p);
9932
 
9933
	if (del_al)			/* We are responsible for deleting allocator */
9934
		al->del(al);
9935
}
9936
 
9937
/* ================================================== */
9938
/* Lut Color normalizing and de-normalizing functions */
9939
 
9940
/* As a rule, I am representing Lut in memory as values in machine form as real */
9941
/* numbers in the range 0.0 - 1.0. For many color spaces (ie. RGB, Gray, */
9942
/* hsv, hls, cmyk and other device coords), this is entirely appropriate. */
9943
/* For the PCS though, this is not correct, since (I assume!) the binary */
9944
/* representation will be consistent with the encoding in Annex A, page 74 */
9945
/* of the standard. Note that the standard doesn't specify the encoding of */
9946
/* many color spaces (ie. Yuv, Yxy etc.), and is unclear about PCS. */
9947
 
9948
/* The following functions convert to and from the PCS spaces (XYZ or Lab) */
9949
/* and the real Lut input/output values. These are used to convert real color */
9950
/* space values into/out of the raw lut 0.0-1.0 representation. */
9951
 
9952
/* This is used internally to support the Lut->lookup() function, */
9953
/* and can also be used by someone writing a Lut based profile to determine */
9954
/* the colorspace range that the input lut indexes cover, as well */
9955
/* as processing the output luts values into normalized form ready */
9956
/* for writing. */
9957
 
9958
/* These functions should be accessed by calling icc.getNormFuncs() */ 
9959
 
9960
/* - - - - - - - - - - - - - - - - */
9961
/* According to 6.5.5 and 6.5.6 of the spec., */
9962
/* XYZ index values are represented the same as their table */
9963
/* values, ie. as a u1.15 representation, with a value */
9964
/* range from 0.0 ->  1.999969482422 */
9965
 
9966
/* Convert Lut index/value to XYZ coord. */ 
9967
static void Lut_Lut2XYZ(double *out, double *in) {
9968
	out[0] = in[0] * (1.0 + 32767.0/32768); /* X */
9969
	out[1] = in[1] * (1.0 + 32767.0/32768); /* Y */
9970
	out[2] = in[2] * (1.0 + 32767.0/32768); /* Z */
9971
}
9972
 
9973
/* Convert XYZ coord to Lut index/value. */ 
9974
static void Lut_XYZ2Lut(double *out, double *in) {
9975
	out[0] = in[0] * (1.0/(1.0 + 32767.0/32768));
9976
	out[1] = in[1] * (1.0/(1.0 + 32767.0/32768));
9977
	out[2] = in[2] * (1.0/(1.0 + 32767.0/32768));
9978
}
9979
 
9980
/* - - - - - - - - - - - - - - - - */
9981
/* Convert Lab to Lut numbers */
9982
/* Annex A specifies 8 and 16 bit encoding, but is */
9983
/* silent on the Lut index normalization. */
9984
/* Following Michael Bourgoin's 1998 SIGGRAPH course comment on this, */
9985
/* we assume here that the index encoding is the same as the */
9986
/* value encoding. */
9987
 
9988
/* Convert Lut16 table index/value to Lab */
9989
static void Lut_Lut2Lab16(double *out, double *in) {
9990
	out[0] = in[0] * (100.0 * 65535.0)/65280.0;			/* L */
9991
	out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0;	/* a */
9992
	out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0;	/* b */
9993
}
9994
 
9995
/* Convert Lab to Lut16 table index/value */
9996
static void Lut_Lab2Lut16(double *out, double *in) {
9997
	out[0] = in[0] * 65280.0/(100.0 * 65535.0);				/* L */
9998
	out[1] = (in[1] + 128.0) * 65280.0/(255.0 * 65535.0);	/* a */
9999
	out[2] = (in[2] + 128.0) * 65280.0/(255.0 * 65535.0);	/* b */
10000
}
10001
 
10002
/* Convert Lut8 table index/value to Lab */
10003
static void Lut_Lut2Lab8(double *out, double *in) {
10004
	out[0] = in[0] * 100.0;				/* L */
10005
	out[1] = (in[1] * 255.0) - 128.0;	/* a */
10006
	out[2] = (in[2] * 255.0) - 128.0;	/* b */
10007
}
10008
 
10009
/* Convert Lab to Lut8 table index/value */
10010
static void Lut_Lab2Lut8(double *out, double *in) {
10011
	out[0] = in[0] * 1.0/100.0;				/* L */
10012
	out[1] = (in[1] + 128.0) * 1.0/255.0;	/* a */
10013
	out[2] = (in[2] + 128.0) * 1.0/255.0;	/* b */
10014
}
10015
 
10016
/* - - - - - - - - - - - - - - - - */
10017
/* Convert Luv to Lut number */
10018
/* This data normalization is taken from Apples */
10019
/* Colorsync specification. */
10020
/* As per other color spaces, we assume that the index */
10021
/* normalization is the same as the data normalization. */
10022
 
10023
/* Convert Lut table index/value to Luv */
10024
static void Lut_Lut2Luv(double *out, double *in) {
10025
	out[0] = in[0] * 100.0;						/* L */
10026
	out[1] = (in[1] * 65535.0/256.0) - 128.0;	/* u */
10027
	out[2] = (in[2] * 65535.0/256.0) - 128.0;	/* v */
10028
}
10029
 
10030
/* Convert Luv to Lut table index/value */
10031
static void Lut_Luv2Lut(double *out, double *in) {
10032
	out[0] = in[0] * 1.0/100.0;					/* L */
10033
	out[1] = (in[1] + 128.0) * 256.0/65535.0;	/* u */
10034
	out[2] = (in[2] + 128.0) * 256.0/65535.0;	/* v */
10035
}
10036
 
10037
/* - - - - - - - - - - - - - - - - */
10038
/* Default N component conversions */
10039
static void Lut_N(double *out, double *in, int nc) {
10040
	for (--nc; nc >= 0; nc--)
10041
		out[nc] = in[nc];
10042
}
10043
 
10044
/* 1 */
10045
static void Lut_1(double *out, double *in) {
10046
	out[0] = in[0];
10047
}
10048
 
10049
/* 2 */
10050
static void Lut_2(double *out, double *in) {
10051
	out[0] = in[0];
10052
	out[1] = in[1];
10053
}
10054
 
10055
/* 3 */
10056
static void Lut_3(double *out, double *in) {
10057
	out[0] = in[0];
10058
	out[1] = in[1];
10059
	out[2] = in[2];
10060
}
10061
 
10062
/* 4 */
10063
static void Lut_4(double *out, double *in) {
10064
	out[0] = in[0];
10065
	out[1] = in[1];
10066
	out[2] = in[2];
10067
	out[3] = in[3];
10068
}
10069
 
10070
/* 5 */
10071
static void Lut_5(double *out, double *in) {
10072
	out[0] = in[0];
10073
	out[1] = in[1];
10074
	out[2] = in[2];
10075
	out[3] = in[3];
10076
	out[4] = in[4];
10077
}
10078
 
10079
/* 6 */
10080
static void Lut_6(double *out, double *in) {
10081
	out[0] = in[0];
10082
	out[1] = in[1];
10083
	out[2] = in[2];
10084
	out[3] = in[3];
10085
	out[4] = in[4];
10086
	out[5] = in[5];
10087
}
10088
 
10089
/* 7 */
10090
static void Lut_7(double *out, double *in) {
10091
	Lut_N(out, in, 7);
10092
}
10093
 
10094
/* 8 */
10095
static void Lut_8(double *out, double *in) {
10096
	Lut_N(out, in, 8);
10097
}
10098
 
10099
/* 9 */
10100
static void Lut_9(double *out, double *in) {
10101
	Lut_N(out, in, 9);
10102
}
10103
 
10104
/* 10 */
10105
static void Lut_10(double *out, double *in) {
10106
	Lut_N(out, in, 10);
10107
}
10108
 
10109
/* 11 */
10110
static void Lut_11(double *out, double *in) {
10111
	Lut_N(out, in, 11);
10112
}
10113
 
10114
/* 12 */
10115
static void Lut_12(double *out, double *in) {
10116
	Lut_N(out, in, 12);
10117
}
10118
 
10119
/* 13 */
10120
static void Lut_13(double *out, double *in) {
10121
	Lut_N(out, in, 13);
10122
}
10123
 
10124
/* 14 */
10125
static void Lut_14(double *out, double *in) {
10126
	Lut_N(out, in, 14);
10127
}
10128
 
10129
/* 15 */
10130
static void Lut_15(double *out, double *in) {
10131
	Lut_N(out, in, 15);
10132
}
10133
 
10134
/* Function table - match conversions to color spaces. */
10135
/* Anything not here, we don't know how to convert. */
10136
/* (ie. YCbCr) */
10137
static struct {
10138
	icColorSpaceSignature csig;
10139
	void (*fromLut8)(double *out, double *in);		/* 8  bit from Lut index/entry */
10140
	void (*fromLut16)(double *out, double *in);		/* 16 bit from Lut index/entry */
10141
	void (*toLut8)(double *out, double *in);		/* 8  bit to Lut index/entry */
10142
	void (*toLut16)(double *out, double *in);		/* 16 bit to Lut index/entry */
10143
} colnormtable[] = {
10144
	{icSigXYZData,     NULL,         Lut_Lut2XYZ,   NULL,         Lut_XYZ2Lut },
10145
	{icSigLabData,     Lut_Lut2Lab8, Lut_Lut2Lab16, Lut_Lab2Lut8, Lut_Lab2Lut16 },
10146
	{icSigLuvData,     Lut_Lut2Luv,  Lut_Lut2Luv,   Lut_Luv2Lut,  Lut_Luv2Lut },
10147
	{icSigYxyData,     Lut_3,        Lut_3,         Lut_3,        Lut_3 },
10148
	{icSigRgbData,     Lut_3,        Lut_3,         Lut_3,        Lut_3 },
10149
	{icSigGrayData,    Lut_1,        Lut_1,         Lut_1,        Lut_1 },
10150
	{icSigHsvData,     Lut_3,        Lut_3,         Lut_3,        Lut_3 },
10151
	{icSigHlsData,     Lut_3,        Lut_3,         Lut_3,        Lut_3 },
10152
	{icSigCmykData,    Lut_4,        Lut_4,         Lut_4,        Lut_4 },
10153
	{icSigCmyData,     Lut_3,        Lut_3,         Lut_3,        Lut_3 },
10154
	{icSigMch6Data,    Lut_6,        Lut_6,         Lut_6,        Lut_6 },
10155
	{icSig2colorData,  Lut_2,        Lut_2,         Lut_2,        Lut_2 },
10156
	{icSig3colorData,  Lut_3,        Lut_3,         Lut_3,        Lut_3 },
10157
	{icSig4colorData,  Lut_4,        Lut_4,         Lut_4,        Lut_4 },
10158
	{icSig5colorData,  Lut_5,        Lut_5,         Lut_5,        Lut_5 },
10159
	{icSig6colorData,  Lut_6,        Lut_6,         Lut_6,        Lut_6 },
10160
	{icSig7colorData,  Lut_7,        Lut_7,         Lut_7,        Lut_7 },
10161
	{icSig8colorData,  Lut_8,        Lut_8,         Lut_8,        Lut_8 },
10162
	{icSig9colorData,  Lut_9,        Lut_9,         Lut_9,        Lut_9 },
10163
	{icSig10colorData, Lut_10,       Lut_10,        Lut_10,       Lut_10 },
10164
	{icSig11colorData, Lut_11,       Lut_11,        Lut_11,       Lut_11 },
10165
	{icSig12colorData, Lut_12,       Lut_12,        Lut_12,       Lut_12 },
10166
	{icSig13colorData, Lut_13,       Lut_13,        Lut_13,       Lut_13 },
10167
	{icSig14colorData, Lut_14,       Lut_14,        Lut_14,       Lut_14 },
10168
	{icSig15colorData, Lut_15,       Lut_15,        Lut_15,       Lut_15 },
10169
	{icMaxEnumData,    NULL,         NULL,          NULL,         NULL   }
10170
};
10171
 
10172
/* Find appropriate conversion functions */
10173
/* given the color space and Lut type */
10174
/* Return 0 on success, 1 on match failure */
10175
/* NOTE: doesn't set error value, message etc.! */
10176
static int getNormFunc(
10177
	icColorSpaceSignature csig, 
10178
	icTagTypeSignature    tagSig,
10179
	icmNormFlag           flag,
10180
	void               (**nfunc)(double *out, double *in)
10181
) {
10182
	int i;
10183
	for (i = 0; colnormtable[i].csig != icMaxEnumData; i++) {
10184
		if (colnormtable[i].csig == csig)
10185
			break;	/* Found it */
10186
	}
10187
	if (colnormtable[i].csig == icMaxEnumData) {	/* Oops */
10188
		*nfunc   = NULL;
10189
		return 1;
10190
	}
10191
 
10192
	if (flag == icmFromLuti || flag == icmFromLutv) {	/* Table index/value decoding functions */
10193
		if (tagSig == icSigLut8Type) {
10194
			*nfunc = colnormtable[i].fromLut8;
10195
			return 0;
10196
		} else if (tagSig == icSigLut16Type) {
10197
			*nfunc = colnormtable[i].fromLut16;
10198
			return 0;
10199
		} else {
10200
			*nfunc   = NULL;
10201
			return 1;
10202
		}
10203
	} else if (flag == icmToLuti || flag == icmToLutv) {	/* Table index/value encoding functions */
10204
		if (tagSig == icSigLut8Type) {
10205
			*nfunc = colnormtable[i].toLut8;
10206
			return 0;
10207
		} else if (tagSig == icSigLut16Type) {
10208
			*nfunc = colnormtable[i].toLut16;
10209
			return 0;
10210
		} else {
10211
			*nfunc   = NULL;
10212
			return 1;
10213
		}
10214
	} else {
10215
		*nfunc   = NULL;
10216
		return 1;
10217
	}
10218
	return 0;
10219
}
10220
 
10221
/* - - - - - - - - - - - - - - - - - - - - - - - - */
10222
/* Colorspace ranges - used instead of norm/denorm by Mono & Matrix */
10223
 
10224
/* Function table - match ranges to color spaces. */
10225
/* Anything not here, we don't know how to convert. */
10226
/* (ie. YCbCr) */
10227
static struct {
10228
	icColorSpaceSignature csig;
10229
	int same;				/* Non zero if first entry applies to all channels */
10230
	double min[15];			/* Minimum value for this colorspace */
10231
	double max[15];			/* Maximum value for this colorspace */
10232
} colorrangetable[] = {
10233
	{icSigXYZData,     1, { 0.0 } , { 1.0 + 32767.0/32768.0 } },
10234
	{icSigLabData,     0, { 0.0, -128.0, -128.0 },
10235
	                      { 100.0 + 25500.0/65280.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } }, 
10236
	{icSigLuvData,     0, { 0.0, -128.0, -128.0 },
10237
	                      { 100.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } }, 
10238
	{icSigYxyData,     1, { 0.0 }, { 1.0 } },
10239
	{icSigRgbData,     1, { 0.0 }, { 1.0 } },
10240
	{icSigGrayData,    1, { 0.0 }, { 1.0 } },
10241
	{icSigHsvData,     1, { 0.0 }, { 1.0 } },
10242
	{icSigHlsData,     1, { 0.0 }, { 1.0 } },
10243
	{icSigCmykData,    1, { 0.0 }, { 1.0 } },
10244
	{icSigCmyData,     1, { 0.0 }, { 1.0 } },
10245
	{icSigMch6Data,    1, { 0.0 }, { 1.0 } },
10246
	{icSig2colorData,  1, { 0.0 }, { 1.0 } },
10247
	{icSig3colorData,  1, { 0.0 }, { 1.0 } },
10248
	{icSig4colorData,  1, { 0.0 }, { 1.0 } },
10249
	{icSig5colorData,  1, { 0.0 }, { 1.0 } },
10250
	{icSig6colorData,  1, { 0.0 }, { 1.0 } },
10251
	{icSig7colorData,  1, { 0.0 }, { 1.0 } },
10252
	{icSig8colorData,  1, { 0.0 }, { 1.0 } },
10253
	{icSig9colorData,  1, { 0.0 }, { 1.0 } },
10254
	{icSig10colorData, 1, { 0.0 }, { 1.0 } },
10255
	{icSig11colorData, 1, { 0.0 }, { 1.0 } },
10256
	{icSig12colorData, 1, { 0.0 }, { 1.0 } },
10257
	{icSig13colorData, 1, { 0.0 }, { 1.0 } },
10258
	{icSig14colorData, 1, { 0.0 }, { 1.0 } },
10259
	{icSig15colorData, 1, { 0.0 }, { 1.0 } },
10260
	{icMaxEnumData     }
10261
};
10262
 
10263
/* Find appropriate typical encoding ranges for a */
10264
/* colorspace given the color space. */
10265
/* Return 0 on success, 1 on match failure */
10266
static int getRange(
10267
	icColorSpaceSignature csig, 
10268
	double *min, double *max
10269
) {
10270
	int i, e, ee;
10271
	for (i = 0; colorrangetable[i].csig != icMaxEnumData; i++) {
10272
		if (colorrangetable[i].csig == csig)
10273
			break;	/* Found it */
10274
	}
10275
	if (colorrangetable[i].csig == icMaxEnumData) {	/* Oops */
10276
		return 1;
10277
	}
10278
	ee = number_ColorSpaceSignature(csig);		/* Get number of components */
10279
 
10280
	if (colorrangetable[i].same) {		/* All channels are the same */
10281
		for (e = 0; e < ee; e++) {
10282
			if (min != NULL)
10283
				min[e] = colorrangetable[i].min[0];
10284
			if (max != NULL)
10285
				max[e] = colorrangetable[i].max[0];
10286
		}
10287
	} else {
10288
		for (e = 0; e < ee; e++) {
10289
			if (min != NULL)
10290
				min[e] = colorrangetable[i].min[e];
10291
			if (max != NULL)
10292
				max[e] = colorrangetable[i].max[e];
10293
		}
10294
	}
10295
	return 0;
10296
}
10297
 
10298
/* - - - - - - - - - - - - - - - - - - - - - - - - */
10299
 
10300
/* 
10301
	Matrix Inversion
10302
	by Richard Carling
10303
	from "Graphics Gems", Academic Press, 1990
10304
*/
10305
 
10306
/* 
10307
 *   adjoint( original_matrix, inverse_matrix )
10308
 * 
10309
 *     calculate the adjoint of a 3x3 matrix
10310
 *
10311
 *      Let  a   denote the minor determinant of matrix A obtained by
10312
 *           ij
10313
 *
10314
 *      deleting the ith row and jth column from A.
10315
 *
10316
 *                    i+j
10317
 *     Let  b   = (-1)    a
10318
 *          ij            ji
10319
 *
10320
 *    The matrix B = (b  ) is the adjoint of A
10321
 *                     ij
10322
 */
10323
 
10324
#define det2x2(a, b, c, d) (a * d - b * c)
10325
 
10326
static void adjoint(
10327
double out[3][3],
10328
double in[3][3]
10329
) {
10330
    double a1, a2, a3, b1, b2, b3, c1, c2, c3;
10331
 
10332
    /* assign to individual variable names to aid  */
10333
    /* selecting correct values  */
10334
 
10335
	a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
10336
	a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
10337
	a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
10338
 
10339
    /* row column labeling reversed since we transpose rows & columns */
10340
 
10341
    out[0][0]  =   det2x2(b2, b3, c2, c3);
10342
    out[1][0]  = - det2x2(a2, a3, c2, c3);
10343
    out[2][0]  =   det2x2(a2, a3, b2, b3);
10344
 
10345
    out[0][1]  = - det2x2(b1, b3, c1, c3);
10346
    out[1][1]  =   det2x2(a1, a3, c1, c3);
10347
    out[2][1]  = - det2x2(a1, a3, b1, b3);
10348
 
10349
    out[0][2]  =   det2x2(b1, b2, c1, c2);
10350
    out[1][2]  = - det2x2(a1, a2, c1, c2);
10351
    out[2][2]  =   det2x2(a1, a2, b1, b2);
10352
}
10353
 
10354
/*
10355
 * double = det3x3(  a1, a2, a3, b1, b2, b3, c1, c2, c3 )
10356
 * 
10357
 * calculate the determinant of a 3x3 matrix
10358
 * in the form
10359
 *
10360
 *     | a1,  b1,  c1 |
10361
 *     | a2,  b2,  c2 |
10362
 *     | a3,  b3,  c3 |
10363
 */
10364
 
10365
static double det3x3(double in[3][3]) {
10366
    double a1, a2, a3, b1, b2, b3, c1, c2, c3;
10367
    double ans;
10368
 
10369
	a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
10370
	a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
10371
	a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
10372
 
10373
    ans = a1 * det2x2(b2, b3, c2, c3)
10374
        - b1 * det2x2(a2, a3, c2, c3)
10375
        + c1 * det2x2(a2, a3, b2, b3);
10376
    return ans;
10377
}
10378
 
10379
#define SMALL_NUMBER	1.e-8
10380
/* 
10381
 *   inverse( original_matrix, inverse_matrix )
10382
 * 
10383
 *    calculate the inverse of a 4x4 matrix
10384
 *
10385
 *     -1     
10386
 *     A  = ___1__ adjoint A
10387
 *         det A
10388
 */
10389
 
10390
/* Return non-zero if not invertable */
10391
static int inverse3x3(
10392
double out[3][3],
10393
double in[3][3]
10394
) {
10395
    int i, j;
10396
    double det;
10397
 
10398
    /*  calculate the 3x3 determinant
10399
     *  if the determinant is zero, 
10400
     *  then the inverse matrix is not unique.
10401
     */
10402
    det = det3x3(in);
10403
 
10404
    if ( fabs(det) < SMALL_NUMBER)
10405
        return 1;
10406
 
10407
    /* calculate the adjoint matrix */
10408
    adjoint(out, in);
10409
 
10410
    /* scale the adjoint matrix to get the inverse */
10411
    for (i = 0; i < 3; i++)
10412
        for(j = 0; j < 3; j++)
10413
		    out[i][j] /= det;
10414
	return 0;
10415
}
10416
 
10417
/* - - - - - - - - - - - - - - - - - - - - - - - - */
10418
 
10419
/* Multuply XYZ array by 3x3 transform matrix */
10420
static void icmMulBy3x3(double out[3], double mat[3][3], double in[3]) {
10421
	double tt[3];
10422
 
10423
	tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
10424
	tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
10425
	tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
10426
 
10427
	out[0] = tt[0];
10428
	out[1] = tt[1];
10429
	out[2] = tt[2];
10430
}
10431
 
10432
/* - - - - - - - - - - - - - - - - - - - - - - - - */
10433
/* CIE XYZ to perceptual Lab */
10434
void
10435
icmXYZ2Lab(icmXYZNumber *w, double *out, double *in) {
10436
	double X = in[0], Y = in[1], Z = in[2];
10437
	double x,y,z,fx,fy,fz;
10438
	double L;
10439
 
10440
	x = X/w->X;
10441
	if (x > 0.008856451586)
10442
		fx = pow(x,1.0/3.0);
10443
	else
10444
		fx = 7.787036979 * x + 16.0/116.0;
10445
 
10446
	y = Y/w->Y;
10447
	if (y > 0.008856451586) {
10448
		fy = pow(y,1.0/3.0);
10449
		L = 116.0 * fy - 16.0;
10450
	} else {
10451
		fy = 7.787036979 * y + 16.0/116.0;
10452
		L = 903.2963058 * y;
10453
	}
10454
 
10455
	z = Z/w->Z;
10456
	if (z > 0.008856451586)
10457
		fz = pow(z,1.0/3.0);
10458
	else
10459
		fz = 7.787036979 * z + 16.0/116.0;
10460
 
10461
	out[0] = L;
10462
	out[1] = 500.0 * (fx - fy);
10463
	out[2] = 200.0 * (fy - fz);
10464
}
10465
 
10466
/* Perceptual Lab to CIE XYZ */
10467
void
10468
icmLab2XYZ(icmXYZNumber *w, double *out, double *in) {
10469
	double L = in[0], a = in[1], b = in[2];
10470
	double x,y,z,fx,fy,fz;
10471
 
10472
	if (L > 8.0) {
10473
		fy = (L + 16.0)/116.0;
10474
		y = pow(fy,3.0);
10475
	} else {
10476
		y = L/903.2963058;
10477
		fy = 7.787036979 * y + 16.0/116.0;
10478
	}
10479
 
10480
	fx = a/500.0 + fy;
10481
	if (fx > 24.0/116.0)
10482
		x = pow(fx,3.0);
10483
	else
10484
		x = (fx - 16.0/116.0)/7.787036979;
10485
 
10486
	fz = fy - b/200.0;
10487
	if (fz > 24.0/116.0)
10488
		z = pow(fz,3.0);
10489
	else
10490
		z = (fz - 16.0/116.0)/7.787036979;
10491
 
10492
	out[0] = x * w->X;
10493
	out[1] = y * w->Y;
10494
	out[2] = z * w->Z;
10495
}
10496
 
10497
/* available D50 Illuminant */
10498
icmXYZNumber icmD50 = { 		/* Profile illuminant - D50 */
10499
    0.9642, 1.0000, 0.8249
10500
};
10501
 
10502
/* available D65 Illuminant */
10503
icmXYZNumber icmD65 = { 		/* Profile illuminant - D65 */
10504
	0.9505, 1.0000, 1.0890
10505
};
10506
 
10507
/* Default black point */
10508
icmXYZNumber icmBlack = {
10509
    0.0000, 0.0000, 0.0000
10510
};
10511
 
10512
/* Return the normal Delta E given two Lab values */
10513
double icmLabDE(double *Lab1, double *Lab2) {
10514
	double rv = 0.0, tt;
10515
 
10516
	tt = Lab1[0] - Lab2[0];
10517
	rv += tt * tt;
10518
	tt = Lab1[1] - Lab2[1];
10519
	rv += tt * tt;
10520
	tt = Lab1[2] - Lab2[2];
10521
	rv += tt * tt;
10522
 
10523
	return sqrt(rv);
10524
}
10525
 
10526
/* Return the normal Delta E squared, given two Lab values */
10527
double icmLabDEsq(double *Lab1, double *Lab2) {
10528
	double rv = 0.0, tt;
10529
 
10530
	tt = Lab1[0] - Lab2[0];
10531
	rv += tt * tt;
10532
	tt = Lab1[1] - Lab2[1];
10533
	rv += tt * tt;
10534
	tt = Lab1[2] - Lab2[2];
10535
	rv += tt * tt;
10536
 
10537
	return rv;
10538
}
10539
 
10540
/* Return the CIE94 Delta E color difference measure */
10541
double icmCIE94(double Lab1[3], double Lab2[3]) {
10542
	double desq, dhsq;
10543
	double dlsq, dcsq;
10544
	double c12;
10545
 
10546
	{
10547
		double dl, da, db;
10548
		dl = Lab1[0] - Lab2[0];
10549
		dlsq = dl * dl;		/* dl squared */
10550
		da = Lab1[1] - Lab2[1];
10551
		db = Lab1[2] - Lab2[2];
10552
 
10553
		/* Compute normal Lab delta E squared */
10554
		desq = dlsq + da * da + db * db;
10555
	}
10556
 
10557
	{
10558
		double c1, c2, dc;
10559
 
10560
		/* Compute chromanance for the two colors */
10561
		c1 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
10562
		c2 = sqrt(Lab2[1] * Lab2[1] + Lab2[2] * Lab2[2]);
10563
		c12 = sqrt(c1 * c2);	/* Symetric chromanance */
10564
 
10565
		/* delta chromanance squared */
10566
		dc = c2 - c1;
10567
		dcsq = dc * dc;
10568
	}
10569
 
10570
	/* Compute delta hue squared */
10571
	if ((dhsq = desq - dlsq - dcsq) < 0.0)
10572
		dhsq = 0.0;
10573
 
10574
	{
10575
		double sc, sh;
10576
 
10577
		/* Weighting factors for delta chromanance & delta hue */
10578
		sc = 1.0 + 0.048 * c12;
10579
		sh = 1.0 + 0.014 * c12;
10580
 
10581
		return sqrt(dlsq + dcsq/(sc * sc) + dhsq/(sh * sh));
10582
	}
10583
}
10584
 
10585
/* Return the CIE94 Delta E color difference measure, squared */
10586
double icmCIE94sq(double Lab1[3], double Lab2[3]) {
10587
	double desq, dhsq;
10588
	double dlsq, dcsq;
10589
	double c12;
10590
 
10591
	{
10592
		double dl, da, db;
10593
		dl = Lab1[0] - Lab2[0];
10594
		dlsq = dl * dl;		/* dl squared */
10595
		da = Lab1[1] - Lab2[1];
10596
		db = Lab1[2] - Lab2[2];
10597
 
10598
		/* Compute normal Lab delta E squared */
10599
		desq = dlsq + da * da + db * db;
10600
	}
10601
 
10602
	{
10603
		double c1, c2, dc;
10604
 
10605
		/* Compute chromanance for the two colors */
10606
		c1 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
10607
		c2 = sqrt(Lab2[1] * Lab2[1] + Lab2[2] * Lab2[2]);
10608
		c12 = sqrt(c1 * c2);	/* Symetric chromanance */
10609
 
10610
		/* delta chromanance squared */
10611
		dc = c2 - c1;
10612
		dcsq = dc * dc;
10613
	}
10614
 
10615
	/* Compute delta hue squared */
10616
	if ((dhsq = desq - dlsq - dcsq) < 0.0)
10617
		dhsq = 0.0;
10618
 
10619
	{
10620
		double sc, sh;
10621
 
10622
		/* Weighting factors for delta chromanance & delta hue */
10623
		sc = 1.0 + 0.048 * c12;
10624
		sh = 1.0 + 0.014 * c12;
10625
 
10626
		return dlsq + dcsq/(sc * sc) + dhsq/(sh * sh);
10627
	}
10628
}
10629
 
10630
/* - - - - - - - - - - - - - - - - - - - - - - - - */
10631
 
10632
/* Multiply one 3x3 with another */
10633
static void mul3x3(double dst[3][3], double src[3][3]) {
10634
	int i, j, k;
10635
	double td[3][3];		/* Temporary dest */
10636
 
10637
	for (j = 0; j < 3; j++) {
10638
		for (i = 0; i < 3; i++) {
10639
			double tt = 0.0;
10640
			for (k = 0; k < 3; k++)
10641
				tt += src[j][k] * dst[k][i];
10642
			td[j][i] = tt;
10643
		}
10644
	}
10645
 
10646
	/* Copy result out */
10647
	for (j = 0; j < 3; j++)
10648
		for (i = 0; i < 3; i++)
10649
			dst[j][i] = td[j][i];
10650
}
10651
 
10652
/* Chrmatic Adaption transform utility */
10653
/* Return a 3x3 chromatic adaption matrix */
10654
void icmChromAdaptMatrix(
10655
	int flags,
10656
	icmXYZNumber d_wp,		/* Destination white point */
10657
	icmXYZNumber s_wp,		/* Source white point */
10658
	double mat[3][3]		/* Destination matrix */
10659
) {
10660
	double dst[3], src[3];			/* Source & destination white points */
10661
	double vkmat[3][3];				/* Von Kries matrix */
10662
	double bradford[3][3] = {		/* Bradford cone space matrix */
10663
		{  0.8951,  0.2664, -0.1614 },
10664
		{ -0.7502,  1.7135,  0.0367 },
10665
		{  0.0389, -0.0685,  1.0296 }
10666
	};
10667
	double ibradford[3][3];			/* Inverse Bradford */
10668
 
10669
	/* Set initial matrix to unity */
10670
	if (!(flags & ICM_CAM_MULMATRIX)) {
10671
		mat[0][0] = mat[1][1] = mat[2][2] = 1.0;
10672
		mat[0][1] = mat[0][2] = 0.0;
10673
		mat[1][0] = mat[1][2] = 0.0;
10674
		mat[2][0] = mat[2][1] = 0.0;
10675
	}
10676
 
10677
	icmXYZ2Ary(src, s_wp);
10678
	icmXYZ2Ary(dst, d_wp);
10679
 
10680
	if (flags & ICM_CAM_BRADFORD) {
10681
		icmMulBy3x3(src, bradford, src);
10682
		icmMulBy3x3(dst, bradford, dst);
10683
	}
10684
 
10685
	/* Setup the Von Kries white point adaption matrix */
10686
	vkmat[0][0] = dst[0]/src[0];
10687
	vkmat[1][1] = dst[1]/src[1];
10688
	vkmat[2][2] = dst[2]/src[2];
10689
	vkmat[0][1] = vkmat[0][2] = 0.0;
10690
	vkmat[1][0] = vkmat[1][2] = 0.0;
10691
	vkmat[2][0] = vkmat[2][1] = 0.0;
10692
 
10693
	/* Transform to Bradford space if requested */
10694
	if (flags & ICM_CAM_BRADFORD) {
10695
		mul3x3(mat, bradford);
10696
	}
10697
 
10698
	/* Apply chromatic adaption */
10699
	mul3x3(mat, vkmat);
10700
 
10701
	/* Transform from Bradford space */
10702
	if (flags & ICM_CAM_BRADFORD) {
10703
		inverse3x3(ibradford, bradford);
10704
		mul3x3(mat, ibradford);
10705
	}
10706
 
10707
	/* We're done */
10708
}
10709
 
10710
/* - - - - - - - - - - - - - - - - - - - - - - - - */
10711
 
10712
/* Return information about the native lut in/out colorspaces. */
10713
/* Any pointer may be NULL if value is not to be returned */
10714
static void
10715
icmLutSpaces(
10716
	struct _icmLuBase *p,			/* This */
10717
	icColorSpaceSignature *ins,		/* Return Native input color space */
10718
	int *inn,						/* Return number of input components */
10719
	icColorSpaceSignature *outs,	/* Return Native output color space */
10720
	int *outn						/* Return number of output components */
10721
) {
10722
	if (ins != NULL)
10723
		*ins = p->inSpace;
10724
	if (inn != NULL)
10725
		*inn = (int)number_ColorSpaceSignature(p->inSpace);
10726
 
10727
	if (outs != NULL)
10728
		*outs = p->outSpace;
10729
	if (outn != NULL)
10730
		*outn = (int)number_ColorSpaceSignature(p->outSpace);
10731
}
10732
 
10733
/* Return information about the effective lookup in/out colorspaces, */
10734
/* including allowance for PCS overide. */
10735
/* Any pointer may be NULL if value is not to be returned */
10736
static void
10737
icmLuSpaces(
10738
	struct _icmLuBase *p,			/* This */
10739
	icColorSpaceSignature *ins,		/* Return effective input color space */
10740
	int *inn,						/* Return number of input components */
10741
	icColorSpaceSignature *outs,	/* Return effective output color space */
10742
	int *outn,						/* Return number of output components */
10743
	icmLuAlgType *alg,				/* Return type of lookup algorithm used */
10744
    icRenderingIntent *intt,		/* Return the intent being implented */
10745
    icmLookupFunc *fnc,				/* Return the profile function being implemented */
10746
	icColorSpaceSignature *pcs		/* Return the profile effective PCS */
10747
) {
10748
	if (ins != NULL)
10749
		*ins = p->e_inSpace;
10750
	if (inn != NULL)
10751
		*inn = (int)number_ColorSpaceSignature(p->e_inSpace);
10752
 
10753
	if (outs != NULL)
10754
		*outs = p->e_outSpace;
10755
	if (outn != NULL)
10756
		*outn = (int)number_ColorSpaceSignature(p->e_outSpace);
10757
 
10758
	if (alg != NULL)
10759
		*alg = p->ttype;
10760
 
10761
    if (intt != NULL)
10762
		*intt = p->intent;
10763
 
10764
	if (fnc != NULL)
10765
		*fnc = p->function;
10766
 
10767
	if (pcs != NULL)
10768
		*pcs = p->e_pcs;
10769
}
10770
 
10771
/* Return the media white and black points in XYZ space. */
10772
/* Note that if not in the icc, the black point will be returned as 0, 0, 0 */
10773
/* Any pointer may be NULL if value is not to be returned */
10774
static void icmLuWh_bk_points(
10775
struct _icmLuBase *p,
10776
icmXYZNumber *wht,
10777
icmXYZNumber *blk
10778
) {
10779
	if (wht != NULL)
10780
		*wht = p->whitePoint;	/* Structure copy */
10781
 
10782
	if (blk != NULL)
10783
		*blk = p->blackPoint;	/* Structure copy */
10784
}
10785
 
10786
/* Get the effective (externally visible) ranges for the Monochrome or Matrix profile */
10787
/* Arguments may be NULL */
10788
static void
10789
icmLu_get_ranges (
10790
	struct _icmLuBase *p,
10791
	double *inmin, double *inmax,		/* Return maximum range of inspace values */
10792
	double *outmin, double *outmax		/* Return maximum range of outspace values */
10793
) {
10794
	/* Hmm. we have no way of handlin an error from getRange. */
10795
	/* It shouldn't ever return one unless there is a mismatch between */
10796
	/* getRange and Lu creation... */
10797
	getRange(p->e_inSpace, inmin, inmax);
10798
	getRange(p->e_outSpace, outmin, outmax);
10799
}
10800
 
10801
/* - - - - - - - - - - - - - - - - - - - - - - - - */
10802
/* Forward and Backward Monochrome type conversion */
10803
/* Return 0 on success, 1 if clipping occured, 2 on other error */
10804
 
10805
/* Individual components of Fwd conversion: */
10806
 
10807
/* Actual device to linearised device */
10808
static int
10809
icmLuMonoFwd_curve (
10810
icmLuMono *p,		/* This */
10811
double *out,		/* Vector of output values */
10812
double *in			/* Vector of input values */
10813
) {
10814
	icc *icp = p->icp;
10815
	int rv = 0;
10816
 
10817
	/* Translate from device to PCS scale */
10818
	if ((rv |= p->grayCurve->lookup_fwd(p->grayCurve,&out[0],&in[0])) > 1) {
10819
		sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
10820
		icp->errc = rv;
10821
		return 2;
10822
	}
10823
 
10824
	return rv;
10825
}
10826
 
10827
/* Linearised device to relative PCS */
10828
static int
10829
icmLuMonoFwd_map (
10830
icmLuMono *p,		/* This */
10831
double *out,		/* Vector of output values (native space) */
10832
double *in			/* Vector of input values (native space) */
10833
) {
10834
	int rv = 0;
10835
	double Y = in[0];		/* In case out == in */
10836
 
10837
	out[0] = p->pcswht.X;
10838
	out[1] = p->pcswht.Y;
10839
	out[2] = p->pcswht.Z;
10840
	if (p->pcs == icSigLabData)
10841
		icmXYZ2Lab(&p->pcswht, out, out);	/* in Lab */
10842
 
10843
	/* Scale linearized device level to PCS white */
10844
	out[0] *= Y;
10845
	out[1] *= Y;
10846
	out[2] *= Y;
10847
 
10848
	return rv;
10849
}
10850
 
10851
/* relative PCS to absolute PCS (if required) */
10852
static int
10853
icmLuMonoFwd_abs (	/* Abs comes last in Fwd conversion */
10854
icmLuMono *p,		/* This */
10855
double *out,		/* Vector of output values in Effective PCS */
10856
double *in			/* Vector of input values in Native PCS */
10857
) {
10858
	int rv = 0;
10859
 
10860
	if (out != in) {
10861
		int i;
10862
		for (i = 0; i < 3; i++)		/* Don't alter input values */
10863
			out[i] = in[i];
10864
	}
10865
 
10866
	/* Do absolute conversion */
10867
	if (p->intent == icAbsoluteColorimetric) {
10868
 
10869
		if (p->pcs == icSigLabData) 	/* Convert L to Y */
10870
			icmLab2XYZ(&p->pcswht, out, out);
10871
 
10872
		/* Convert from Relative to Absolute colorometric */
10873
		icmMulBy3x3(out, p->toAbs, out);
10874
 
10875
		if (p->e_pcs == icSigLabData)
10876
			icmXYZ2Lab(&p->pcswht, out, out);
10877
 
10878
	} else {
10879
 
10880
		/* Convert from Native to Effective output space */
10881
		if (p->pcs == icSigLabData && p->e_pcs == icSigXYZData)
10882
			icmLab2XYZ(&p->pcswht, out, out);
10883
		else if (p->pcs == icSigXYZData && p->e_pcs == icSigLabData)
10884
			icmXYZ2Lab(&p->pcswht, out, out);
10885
	}
10886
 
10887
	return rv;
10888
}
10889
 
10890
 
10891
/* Overall Fwd conversion routine */
10892
static int
10893
icmLuMonoFwd_lookup (
10894
icmLuBase *pp,		/* This */
10895
double *out,		/* Vector of output values */
10896
double *in			/* Input value */
10897
) {
10898
	int rv = 0;
10899
	icmLuMono *p = (icmLuMono *)pp;
10900
	rv |= icmLuMonoFwd_curve(p, out, in);
10901
	rv |= icmLuMonoFwd_map(p, out, out);
10902
	rv |= icmLuMonoFwd_abs(p, out, out);
10903
	return rv;
10904
}
10905
 
10906
 
10907
/* Individual components of Bwd conversion: */
10908
 
10909
/* Convert from relative PCS to absolute PCS (if required) */
10910
static int
10911
icmLuMonoBwd_abs (	/* Abs comes first in Bwd conversion */
10912
icmLuMono *p,		/* This */
10913
double *out,		/* Vector of output values in Native PCS */
10914
double *in			/* Vector of input values in Effective PCS */
10915
) {
10916
	int rv = 0;
10917
 
10918
	if (out != in) {
10919
		int i;
10920
		for (i = 0; i < 3; i++)		/* Don't alter input values */
10921
			out[i] = in[i];
10922
	}
10923
 
10924
	/* Force to monochrome locus in correct space */
10925
	if (p->e_pcs == icSigLabData) {
10926
		double wp[3];
10927
 
10928
		if (p->intent == icAbsoluteColorimetric) {
10929
			wp[0] = p->whitePoint.X;
10930
			wp[1] = p->whitePoint.Y;
10931
			wp[2] = p->whitePoint.Z;
10932
		} else {
10933
			wp[0] = p->pcswht.X;
10934
			wp[1] = p->pcswht.Y;
10935
			wp[2] = p->pcswht.Z;
10936
		}
10937
		icmXYZ2Lab(&p->pcswht, wp, wp);	/* Convert to Lab white point */
10938
		out[1] = out[0]/wp[0] * wp[1];
10939
		out[2] = out[0]/wp[0] * wp[2];
10940
 
10941
	} else {
10942
		if (p->intent == icAbsoluteColorimetric) {
10943
			out[0] = out[1]/p->whitePoint.Y * p->whitePoint.X;
10944
			out[2] = out[1]/p->whitePoint.Y * p->whitePoint.Z;
10945
		} else {
10946
			out[0] = out[1]/p->pcswht.Y * p->pcswht.X;
10947
			out[2] = out[1]/p->pcswht.Y * p->pcswht.Z;
10948
		}
10949
	}
10950
 
10951
	/* Do absolute conversion to */
10952
	if (p->intent == icAbsoluteColorimetric) {
10953
 
10954
		if (p->e_pcs == icSigLabData)
10955
			icmLab2XYZ(&p->pcswht, out, out);
10956
 
10957
		icmMulBy3x3(out, p->fromAbs, out);
10958
 
10959
		/* Convert from Effective to Native input space */
10960
		if (p->pcs == icSigLabData)
10961
			icmXYZ2Lab(&p->pcswht, out, out);
10962
 
10963
	} else {
10964
 
10965
		/* Convert from Effective to Native input space */
10966
		if (p->e_pcs == icSigLabData && p->pcs == icSigXYZData)
10967
			icmLab2XYZ(&p->pcswht, out, out);
10968
		else if (p->e_pcs == icSigXYZData && p->pcs == icSigLabData)
10969
			icmXYZ2Lab(&p->pcswht, out, out);
10970
	}
10971
 
10972
	return rv;
10973
}
10974
 
10975
/* Map from relative PCS to linearised device */
10976
static int
10977
icmLuMonoBwd_map (
10978
icmLuMono *p,		/* This */
10979
double *out,		/* Output value */
10980
double *in			/* Vector of input values (native space) */
10981
) {
10982
	int rv = 0;
10983
	double pcsw[3];
10984
 
10985
	pcsw[0] = p->pcswht.X;
10986
	pcsw[1] = p->pcswht.Y;
10987
	pcsw[2] = p->pcswht.Z;
10988
	if (p->pcs == icSigLabData)
10989
		icmXYZ2Lab(&p->pcswht, pcsw, pcsw);	/* in Lab (should be 100.0!) */
10990
 
10991
	/* Divide linearized device level into PCS white luminence */
10992
	if (p->pcs == icSigLabData)
10993
		out[0] = in[0]/pcsw[0];
10994
	else
10995
		out[0] = in[1]/pcsw[1];
10996
 
10997
	return rv;
10998
}
10999
 
11000
/* Map from linearised device to actual device */
11001
static int
11002
icmLuMonoBwd_curve (
11003
icmLuMono *p,		/* This */
11004
double *out,		/* Output value */
11005
double *in			/* Input value */
11006
) {
11007
	icc *icp = p->icp;
11008
	int rv = 0;
11009
 
11010
	/* Convert to device value through curve */
11011
	if ((rv = p->grayCurve->lookup_bwd(p->grayCurve,&out[0],&in[0])) > 1) {
11012
		sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
11013
		icp->errc = rv;
11014
		return 2;
11015
	}
11016
 
11017
	return rv;
11018
}
11019
 
11020
/* Overall Bwd conversion routine */
11021
static int
11022
icmLuMonoBwd_lookup (
11023
icmLuBase *pp,		/* This */
11024
double *out,		/* Output value */
11025
double *in			/* Vector of input values */
11026
) {
11027
	double temp[3];
11028
	int rv = 0;
11029
	icmLuMono *p = (icmLuMono *)pp;
11030
	rv |= icmLuMonoBwd_abs(p, temp, in);
11031
	rv |= icmLuMonoBwd_map(p, out, temp);
11032
	rv |= icmLuMonoBwd_curve(p, out, out);
11033
	return rv;
11034
}
11035
 
11036
static void
11037
icmLuMono_delete(
11038
icmLuBase *p
11039
) {
11040
	icc *icp = p->icp;
11041
 
11042
	icp->al->free(icp->al, p);
11043
}
11044
 
11045
static icmLuBase *
11046
new_icmLuMono(
11047
	struct _icc          *icp,
11048
    icColorSpaceSignature inSpace,		/* Native Input color space */
11049
    icColorSpaceSignature outSpace,		/* Native Output color space */
11050
    icColorSpaceSignature pcs,			/* Native PCS */
11051
    icColorSpaceSignature e_inSpace,	/* Effective Input color space */
11052
    icColorSpaceSignature e_outSpace,	/* Effective Output color space */
11053
    icColorSpaceSignature e_pcs,		/* Effective PCS */
11054
	icmXYZNumber          whitePoint,	/* Profile absolute white point */
11055
	icmXYZNumber          blackPoint,	/* Profile absolute black point */
11056
	icRenderingIntent     intent,		/* Rendering intent */
11057
	icmLookupFunc         func,			/* Functionality requested */
11058
	int dir								/* 0 = fwd, 1 = bwd */
11059
) {
11060
	icmLuMono *p;
11061
 
11062
	if ((p = (icmLuMono *) icp->al->calloc(icp->al,1,sizeof(icmLuMono))) == NULL)
11063
		return NULL;
11064
	p->icp      = icp;
11065
	p->del      = icmLuMono_delete;
11066
	p->lutspaces= icmLutSpaces;
11067
	p->spaces   = icmLuSpaces;
11068
	p->get_ranges = icmLu_get_ranges;
11069
	p->wh_bk_points = icmLuWh_bk_points;
11070
	p->fwd_lookup = icmLuMonoFwd_lookup;
11071
	p->fwd_curve  = icmLuMonoFwd_curve;
11072
	p->fwd_map    = icmLuMonoFwd_map;
11073
	p->fwd_abs    = icmLuMonoFwd_abs;
11074
	p->bwd_lookup = icmLuMonoBwd_lookup;
11075
	p->bwd_abs    = icmLuMonoFwd_abs;
11076
	p->bwd_map    = icmLuMonoFwd_map;
11077
	p->bwd_curve  = icmLuMonoFwd_curve;
11078
	if (dir) {
11079
		p->ttype      = icmMonoBwdType;
11080
		p->lookup     = icmLuMonoBwd_lookup;
11081
	} else {
11082
		p->ttype      = icmMonoFwdType;
11083
		p->lookup     = icmLuMonoFwd_lookup;
11084
	}
11085
 
11086
	/* See if the color spaces are appropriate for the mono type */
11087
	if (number_ColorSpaceSignature(icp->header->colorSpace) != 1
11088
	  || ( icp->header->pcs != icSigXYZData && icp->header->pcs != icSigLabData)) {
11089
		p->del((icmLuBase *)p);
11090
		return NULL;
11091
	}
11092
 
11093
	/* Find the appropriate tags */
11094
	if ((p->grayCurve = (icmCurve *)icp->read_tag(icp, icSigGrayTRCTag)) == NULL
11095
         || p->grayCurve->ttype != icSigCurveType) {
11096
		p->del((icmLuBase *)p);
11097
		return NULL;
11098
	}
11099
 
11100
	p->pcswht = icp->header->illuminant;
11101
	p->whitePoint = whitePoint;
11102
	p->blackPoint = blackPoint;
11103
	p->intent   = intent;
11104
	p->function = func;
11105
	p->inSpace  = inSpace;
11106
	p->outSpace = outSpace;
11107
	p->pcs      = pcs;
11108
	p->e_inSpace  = e_inSpace;
11109
	p->e_outSpace = e_outSpace;
11110
	p->e_pcs      = e_pcs;
11111
 
11112
	/* Create absolute <-> relative conversion matricies */
11113
	icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs);
11114
	icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint,  p->fromAbs);
11115
 
11116
	return (icmLuBase *)p;
11117
}
11118
 
11119
static icmLuBase *
11120
new_icmLuMonoFwd(
11121
	struct _icc          *icp,
11122
    icColorSpaceSignature inSpace,		/* Native Input color space */
11123
    icColorSpaceSignature outSpace,		/* Native Output color space */
11124
    icColorSpaceSignature pcs,			/* Native PCS */
11125
    icColorSpaceSignature e_inSpace,	/* Effective Input color space */
11126
    icColorSpaceSignature e_outSpace,	/* Effective Output color space */
11127
    icColorSpaceSignature e_pcs,		/* Effective PCS */
11128
	icmXYZNumber          whitePoint,	/* Profile absolute white point */
11129
	icmXYZNumber          blackPoint,	/* Profile absolute black point */
11130
	icRenderingIntent     intent,		/* Rendering intent */
11131
	icmLookupFunc         func			/* Functionality requested */
11132
) {
11133
	return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11134
	                     whitePoint, blackPoint, intent, func, 0);
11135
}
11136
 
11137
 
11138
static icmLuBase *
11139
new_icmLuMonoBwd(
11140
	struct _icc          *icp,
11141
    icColorSpaceSignature inSpace,		/* Native Input color space */
11142
    icColorSpaceSignature outSpace,		/* Native Output color space */
11143
    icColorSpaceSignature pcs,			/* Native PCS */
11144
    icColorSpaceSignature e_inSpace,	/* Effective Input color space */
11145
    icColorSpaceSignature e_outSpace,	/* Effective Output color space */
11146
    icColorSpaceSignature e_pcs,		/* Effective PCS */
11147
	icmXYZNumber          whitePoint,	/* Profile absolute white point */
11148
	icmXYZNumber          blackPoint,	/* Profile absolute black point */
11149
	icRenderingIntent     intent,		/* Rendering intent */
11150
	icmLookupFunc         func			/* Functionality requested */
11151
) {
11152
	return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11153
	                     whitePoint, blackPoint, intent, func, 1);
11154
}
11155
 
11156
/* - - - - - - - - - - - - - - - - - - - - - - - */
11157
/* Forward and Backward Matrix type conversion */
11158
/* Return 0 on success, 1 if clipping occured, 2 on other error */
11159
 
11160
/* Individual components of Fwd conversion: */
11161
static int
11162
icmLuMatrixFwd_curve (
11163
icmLuMatrix *p,		/* This */
11164
double *out,		/* Vector of output values */
11165
double *in			/* Vector of input values */
11166
) {
11167
	icc *icp = p->icp;
11168
	int rv = 0;
11169
 
11170
	/* Curve lookups */
11171
	if ((rv |= p->redCurve->lookup_fwd(  p->redCurve,  &out[0],&in[0])) > 1
11172
	 || (rv |= p->greenCurve->lookup_fwd(p->greenCurve,&out[1],&in[1])) > 1
11173
	 || (rv |= p->blueCurve->lookup_fwd( p->blueCurve, &out[2],&in[2])) > 1) {
11174
		sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
11175
		icp->errc = rv;
11176
		return 2;
11177
	}
11178
 
11179
	return rv;
11180
}
11181
 
11182
static int
11183
icmLuMatrixFwd_matrix (
11184
icmLuMatrix *p,		/* This */
11185
double *out,		/* Vector of output values */
11186
double *in			/* Vector of input values */
11187
) {
11188
	int rv = 0;
11189
	double tt[3];
11190
 
11191
	/* Matrix */
11192
	tt[0] = p->mx[0][0] * in[0] + p->mx[0][1] * in[1] + p->mx[0][2] * in[2];
11193
	tt[1] = p->mx[1][0] * in[0] + p->mx[1][1] * in[1] + p->mx[1][2] * in[2];
11194
	tt[2] = p->mx[2][0] * in[0] + p->mx[2][1] * in[1] + p->mx[2][2] * in[2];
11195
 
11196
	out[0] = tt[0];
11197
	out[1] = tt[1];
11198
	out[2] = tt[2];
11199
 
11200
	return rv;
11201
}
11202
 
11203
static int
11204
icmLuMatrixFwd_abs (/* Abs comes last in Fwd conversion */
11205
icmLuMatrix *p,		/* This */
11206
double *out,		/* Vector of output values */
11207
double *in			/* Vector of input values */
11208
) {
11209
	int rv = 0;
11210
 
11211
	if (out != in) {
11212
		int i;
11213
		for (i = 0; i < 3; i++)		/* Don't alter input values */
11214
			out[i] = in[i];
11215
	}
11216
 
11217
	/* If required, convert from Relative to Absolute colorometric */
11218
	if (p->intent == icAbsoluteColorimetric) {
11219
		icmMulBy3x3(out, p->toAbs, out);
11220
	}
11221
 
11222
	/* If e_pcs is Lab, then convert XYZ to Lab */
11223
	if (p->e_pcs == icSigLabData)
11224
		icmXYZ2Lab(&p->pcswht, out, out);
11225
 
11226
	return rv;
11227
}
11228
 
11229
 
11230
/* Overall Fwd conversion */
11231
static int
11232
icmLuMatrixFwd_lookup (
11233
icmLuBase *pp,		/* This */
11234
double *out,		/* Vector of output values */
11235
double *in			/* Vector of input values */
11236
) {
11237
	int rv = 0;
11238
	icmLuMatrix *p = (icmLuMatrix *)pp;
11239
	rv |= icmLuMatrixFwd_curve(p, out, in);
11240
	rv |= icmLuMatrixFwd_matrix(p, out, out);
11241
	rv |= icmLuMatrixFwd_abs(p, out, out);
11242
	return rv;
11243
}
11244
 
11245
/* Individual components of Bwd conversion: */
11246
 
11247
static int
11248
icmLuMatrixBwd_abs (/* Abs comes first in Bwd conversion */
11249
icmLuMatrix *p,		/* This */
11250
double *out,		/* Vector of output values */
11251
double *in			/* Vector of input values */
11252
) {
11253
	int rv = 0;
11254
 
11255
	if (out != in) {
11256
		int i;
11257
		for (i = 0; i < 3; i++)		/* Don't alter input values */
11258
			out[i] = in[i];
11259
	}
11260
 
11261
	/* If e_pcs is Lab, then convert Lab to XYZ */
11262
	if (p->e_pcs == icSigLabData)
11263
		icmLab2XYZ(&p->pcswht, out, out);
11264
 
11265
	/* If required, convert from Absolute to Relative colorometric */
11266
	if (p->intent == icAbsoluteColorimetric) {
11267
		icmMulBy3x3(out, p->fromAbs, out);
11268
	}
11269
 
11270
	return rv;
11271
}
11272
 
11273
static int
11274
icmLuMatrixBwd_matrix (
11275
icmLuMatrix *p,		/* This */
11276
double *out,		/* Vector of output values */
11277
double *in			/* Vector of input values */
11278
) {
11279
	int rv = 0;
11280
	double tt[3];
11281
 
11282
	/* Matrix */
11283
	tt[0] = p->bmx[0][0] * in[0] + p->bmx[0][1] * in[1] + p->bmx[0][2] * in[2];
11284
	tt[1] = p->bmx[1][0] * in[0] + p->bmx[1][1] * in[1] + p->bmx[1][2] * in[2];
11285
	tt[2] = p->bmx[2][0] * in[0] + p->bmx[2][1] * in[1] + p->bmx[2][2] * in[2];
11286
 
11287
	out[0] = tt[0];
11288
	out[1] = tt[1];
11289
	out[2] = tt[2];
11290
 
11291
	return rv;
11292
}
11293
 
11294
static int
11295
icmLuMatrixBwd_curve (
11296
icmLuMatrix *p,		/* This */
11297
double *out,		/* Vector of output values */
11298
double *in			/* Vector of input values */
11299
) {
11300
	icc *icp = p->icp;
11301
	int rv = 0;
11302
 
11303
	/* Curves */
11304
	if ((rv |= p->redCurve->lookup_bwd(p->redCurve,&out[0],&out[0])) > 1
11305
	 ||	(rv |= p->greenCurve->lookup_bwd(p->greenCurve,&out[1],&out[1])) > 1
11306
	 || (rv |= p->blueCurve->lookup_bwd(p->blueCurve,&out[2],&out[2])) > 1) {
11307
		sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
11308
		icp->errc = rv;
11309
		return 2;
11310
	}
11311
	return rv;
11312
}
11313
 
11314
/* Overall Bwd conversion */
11315
static int
11316
icmLuMatrixBwd_lookup (
11317
icmLuBase *pp,		/* This */
11318
double *out,		/* Vector of output values */
11319
double *in			/* Vector of input values */
11320
) {
11321
	int rv = 0;
11322
	icmLuMatrix *p = (icmLuMatrix *)pp;
11323
	rv |= icmLuMatrixBwd_abs(p, out, in);
11324
	rv |= icmLuMatrixBwd_matrix(p, out, out);
11325
	rv |= icmLuMatrixBwd_curve(p, out, out);
11326
	return rv;
11327
}
11328
 
11329
static void
11330
icmLuMatrix_delete(
11331
icmLuBase *p
11332
) {
11333
	icc *icp = p->icp;
11334
 
11335
	icp->al->free(icp->al, p);
11336
}
11337
 
11338
/* We setup valid fwd and bwd component conversions, */
11339
/* but setup only the asked for overal conversion. */
11340
static icmLuBase *
11341
new_icmLuMatrix(
11342
	struct _icc          *icp,
11343
    icColorSpaceSignature inSpace,		/* Native Input color space */
11344
    icColorSpaceSignature outSpace,		/* Native Output color space */
11345
    icColorSpaceSignature pcs,			/* Native PCS */
11346
    icColorSpaceSignature e_inSpace,	/* Effective Input color space */
11347
    icColorSpaceSignature e_outSpace,	/* Effective Output color space */
11348
    icColorSpaceSignature e_pcs,		/* Effective PCS */
11349
	icmXYZNumber          whitePoint,	/* Profile absolute white point */
11350
	icmXYZNumber          blackPoint,	/* Profile absolute black point */
11351
	icRenderingIntent     intent,		/* Rendering intent */
11352
	icmLookupFunc         func,			/* Functionality requested */
11353
	int dir								/* 0 = fwd, 1 = bwd */
11354
) {
11355
	icmLuMatrix *p;
11356
 
11357
	if ((p = (icmLuMatrix *) icp->al->calloc(icp->al,1,sizeof(icmLuMatrix))) == NULL)
11358
		return NULL;
11359
	p->icp      = icp;
11360
	p->del      = icmLuMatrix_delete;
11361
	p->lutspaces= icmLutSpaces;
11362
	p->spaces   = icmLuSpaces;
11363
	p->get_ranges = icmLu_get_ranges;
11364
	p->wh_bk_points = icmLuWh_bk_points;
11365
	p->fwd_lookup = icmLuMatrixFwd_lookup;
11366
	p->fwd_curve  = icmLuMatrixFwd_curve;
11367
	p->fwd_matrix = icmLuMatrixFwd_matrix;
11368
	p->fwd_abs    = icmLuMatrixFwd_abs;
11369
	p->bwd_lookup = icmLuMatrixBwd_lookup;
11370
	p->bwd_abs    = icmLuMatrixBwd_abs;
11371
	p->bwd_matrix = icmLuMatrixBwd_matrix;
11372
	p->bwd_curve  = icmLuMatrixBwd_curve;
11373
	if (dir) {
11374
		p->ttype      = icmMatrixBwdType;
11375
		p->lookup     = icmLuMatrixBwd_lookup;
11376
	} else {
11377
		p->ttype      = icmMatrixFwdType;
11378
		p->lookup     = icmLuMatrixFwd_lookup;
11379
	}
11380
 
11381
	/* Note that we can use matrix type even if PCS is Lab, */
11382
	/* by simply converting it. */
11383
 
11384
	/* Find the appropriate tags */
11385
	if ((p->redCurve = (icmCurve *)icp->read_tag(icp, icSigRedTRCTag)) == NULL
11386
     || p->redCurve->ttype != icSigCurveType
11387
	 || (p->greenCurve = (icmCurve *)icp->read_tag(icp, icSigGreenTRCTag)) == NULL
11388
     || p->greenCurve->ttype != icSigCurveType
11389
	 || (p->blueCurve = (icmCurve *)icp->read_tag(icp, icSigBlueTRCTag)) == NULL
11390
     || p->blueCurve->ttype != icSigCurveType
11391
	 || (p->redColrnt = (icmXYZArray *)icp->read_tag(icp, icSigRedColorantTag)) == NULL
11392
     || p->redColrnt->ttype != icSigXYZType || p->redColrnt->size < 1
11393
	 || (p->greenColrnt = (icmXYZArray *)icp->read_tag(icp, icSigGreenColorantTag)) == NULL
11394
     || p->greenColrnt->ttype != icSigXYZType || p->greenColrnt->size < 1
11395
	 || (p->blueColrnt = (icmXYZArray *)icp->read_tag(icp, icSigBlueColorantTag)) == NULL
11396
     || p->blueColrnt->ttype != icSigXYZType || p->blueColrnt->size < 1) {
11397
		p->del((icmLuBase *)p);
11398
		return NULL;
11399
	}
11400
 
11401
	/* Setup the matrix */
11402
	p->mx[0][0] = p->redColrnt->data[0].X;
11403
	p->mx[0][1] = p->greenColrnt->data[0].X;
11404
	p->mx[0][2] = p->blueColrnt->data[0].X;
11405
	p->mx[1][1] = p->greenColrnt->data[0].Y;
11406
	p->mx[1][0] = p->redColrnt->data[0].Y;
11407
	p->mx[1][2] = p->blueColrnt->data[0].Y;
11408
	p->mx[2][1] = p->greenColrnt->data[0].Z;
11409
	p->mx[2][0] = p->redColrnt->data[0].Z;
11410
	p->mx[2][2] = p->blueColrnt->data[0].Z;
11411
 
11412
	if (inverse3x3(p->bmx, p->mx) != 0) {	/* Compute inverse */
11413
		sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
11414
		icp->errc = 2;
11415
		p->del((icmLuBase *)p);
11416
		return NULL;
11417
	}
11418
 
11419
	p->pcswht = icp->header->illuminant;
11420
	p->whitePoint = whitePoint;
11421
	p->blackPoint = blackPoint;
11422
	p->intent   = intent;
11423
	p->function = func;
11424
	p->inSpace  = inSpace;
11425
	p->outSpace = outSpace;
11426
	p->pcs      = pcs;
11427
	p->e_inSpace  = e_inSpace;
11428
	p->e_outSpace = e_outSpace;
11429
	p->e_pcs      = e_pcs;
11430
 
11431
	/* Create absolute <-> relative conversion matricies */
11432
	icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs);
11433
	icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint,  p->fromAbs);
11434
 
11435
	return (icmLuBase *)p;
11436
}
11437
 
11438
static icmLuBase *
11439
new_icmLuMatrixFwd(
11440
	struct _icc          *icp,
11441
    icColorSpaceSignature inSpace,		/* Native Input color space */
11442
    icColorSpaceSignature outSpace,		/* Native Output color space */
11443
    icColorSpaceSignature pcs,			/* Native PCS */
11444
    icColorSpaceSignature e_inSpace,	/* Effective Input color space */
11445
    icColorSpaceSignature e_outSpace,	/* Effective Output color space */
11446
    icColorSpaceSignature e_pcs,		/* Effective PCS */
11447
	icmXYZNumber          whitePoint,	/* Profile absolute white point */
11448
	icmXYZNumber          blackPoint,	/* Profile absolute black point */
11449
	icRenderingIntent     intent,		/* Rendering intent */
11450
	icmLookupFunc         func			/* Functionality requested */
11451
) {
11452
	return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11453
	                       whitePoint, blackPoint, intent, func, 0);
11454
}
11455
 
11456
 
11457
static icmLuBase *
11458
new_icmLuMatrixBwd(
11459
	struct _icc          *icp,
11460
    icColorSpaceSignature inSpace,		/* Native Input color space */
11461
    icColorSpaceSignature outSpace,		/* Native Output color space */
11462
    icColorSpaceSignature pcs,			/* Native PCS */
11463
    icColorSpaceSignature e_inSpace,	/* Effective Input color space */
11464
    icColorSpaceSignature e_outSpace,	/* Effective Output color space */
11465
    icColorSpaceSignature e_pcs,		/* Effective PCS */
11466
	icmXYZNumber          whitePoint,	/* Profile absolute white point */
11467
	icmXYZNumber          blackPoint,	/* Profile absolute black point */
11468
	icRenderingIntent     intent,		/* Rendering intent */
11469
	icmLookupFunc         func			/* Functionality requested */
11470
) {
11471
	return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
11472
	                       whitePoint, blackPoint, intent, func, 1);
11473
}
11474
 
11475
/* - - - - - - - - - - - - - - - - - - - - - - - */
11476
/* Forward and Backward Multi-Dimensional Interpolation type conversion */
11477
/* Return 0 on success, 1 if clipping occured, 2 on other error */
11478
 
11479
/* Components of overall lookup, in order */
11480
static int icmLuLut_in_abs(icmLuLut *p, double *out, double *in) {
11481
	icmLut *lut = p->lut;
11482
	int rv = 0;
11483
 
11484
	if (out != in) {
11485
		int i;
11486
		for (i = 0; i < lut->inputChan; i++)		/* Don't alter input values */
11487
			out[i] = in[i];
11488
	}
11489
 
11490
	/* If Bwd Lut, take care of Absolute color space and effective input space */
11491
	if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
11492
		&& p->intent == icAbsoluteColorimetric) {
11493
 
11494
		if (p->e_inSpace == icSigLabData)
11495
			icmLab2XYZ(&p->pcswht, out, out);
11496
 
11497
		/* Convert from Absolute to Relative colorometric */
11498
		icmMulBy3x3(out, p->fromAbs, out);
11499
 
11500
		if (p->inSpace == icSigLabData)
11501
			icmXYZ2Lab(&p->pcswht, out, out);
11502
 
11503
	} else {
11504
 
11505
		/* Convert from Effective to Native input space */
11506
		if (p->e_inSpace == icSigLabData && p->inSpace == icSigXYZData)
11507
			icmLab2XYZ(&p->pcswht, out, out);
11508
		else if (p->e_inSpace == icSigXYZData && p->inSpace == icSigLabData)
11509
			icmXYZ2Lab(&p->pcswht, out, out);
11510
	}
11511
 
11512
	return rv;
11513
}
11514
 
11515
/* Possible matrix lookup */
11516
static int icmLuLut_matrix(icmLuLut *p, double *out, double *in) {
11517
	icmLut *lut = p->lut;
11518
	int rv = 0;
11519
 
11520
	if (p->usematrix)		
11521
		rv |= lut->lookup_matrix(lut,out,in);
11522
	else if (out != in) {
11523
		int i;
11524
		for (i = 0; i < lut->inputChan; i++)
11525
			out[i] = in[i];
11526
	}
11527
	return rv;
11528
}
11529
 
11530
/* Do input -> input' lookup */
11531
static int icmLuLut_input(icmLuLut *p, double *out, double *in) {
11532
	icmLut *lut = p->lut;
11533
	int rv = 0;
11534
 
11535
	p->in_normf(out, in); 						/* Normalize from input color space */
11536
	rv |= lut->lookup_input(lut,out,out);		/* Lookup though input tables */
11537
	p->in_denormf(out,out);						/* De-normalize to input color space */
11538
	return rv;
11539
}
11540
 
11541
/* Do input'->output' lookup */
11542
static int icmLuLut_clut(icmLuLut *p, double *out, double *in) {
11543
	icmLut *lut = p->lut;
11544
	double temp[MAX_CHAN];
11545
	int rv = 0;
11546
 
11547
	p->in_normf(temp, in); 						/* Normalize from input color space */
11548
	rv |= p->lookup_clut(lut,out,temp);			/* Lookup though clut tables */
11549
	p->out_denormf(out,out);					/* De-normalize to output color space */
11550
	return rv;
11551
}
11552
 
11553
/* Do output'->output lookup */
11554
static int icmLuLut_output(icmLuLut *p, double *out, double *in) {
11555
	icmLut *lut = p->lut;
11556
	int rv = 0;
11557
 
11558
	p->out_normf(out,in);						/* Normalize from output color space */
11559
	rv |= lut->lookup_output(lut,out,out);		/* Lookup though output tables */
11560
	p->out_denormf(out, out);					/* De-normalize to output color space */
11561
	return rv;
11562
}
11563
 
11564
static int icmLuLut_out_abs(icmLuLut *p, double *out, double *in) {
11565
	icmLut *lut = p->lut;
11566
	int rv = 0;
11567
 
11568
	if (out != in) {
11569
		int i;
11570
		for (i = 0; i < lut->inputChan; i++)		/* Don't alter input values */
11571
			out[i] = in[i];
11572
	}
11573
 
11574
	/* If Fwd Lut, take care of Absolute color space */
11575
	/* and convert from native to effective out PCS */
11576
	if ((p->function == icmFwd || p->function == icmPreview)
11577
		&& p->intent == icAbsoluteColorimetric) {
11578
 
11579
		if (p->outSpace == icSigLabData)
11580
			icmLab2XYZ(&p->pcswht, out, out);
11581
 
11582
		/* Convert from Relative to Absolute colorometric XYZ */
11583
		icmMulBy3x3(out, p->toAbs, out);
11584
 
11585
		if (p->e_outSpace == icSigLabData)
11586
			icmXYZ2Lab(&p->pcswht, out, out);
11587
	} else {
11588
 
11589
		/* Convert from Native to Effective output space */
11590
		if (p->outSpace == icSigLabData && p->e_outSpace == icSigXYZData)
11591
			icmLab2XYZ(&p->pcswht, out, out);
11592
		else if (p->outSpace == icSigXYZData && p->e_outSpace == icSigLabData)
11593
			icmXYZ2Lab(&p->pcswht, out, out);
11594
	}
11595
	return rv;
11596
}
11597
 
11598
 
11599
/* Overall lookup */
11600
static int
11601
icmLuLut_lookup (
11602
icmLuBase *pp,		/* This */
11603
double *out,		/* Vector of output values */
11604
double *in			/* Vector of input values */
11605
) {
11606
	int rv = 0;
11607
	icmLuLut *p = (icmLuLut *)pp;
11608
	icmLut *lut = p->lut;
11609
	double temp[MAX_CHAN];
11610
 
11611
	rv |= p->in_abs(p,temp,in);						/* Possible absolute conversion */
11612
	if (p->usematrix)		
11613
		rv |= lut->lookup_matrix(lut,temp,temp);/* If XYZ, multiply by non-unity matrix */
11614
	p->in_normf(temp, temp);					/* Normalize for input color space */
11615
	rv |= lut->lookup_input(lut,temp,temp);		/* Lookup though input tables */
11616
	rv |= p->lookup_clut(lut,out,temp);			/* Lookup though clut tables */
11617
	rv |= lut->lookup_output(lut,out,out);		/* Lookup though output tables */
11618
	p->out_denormf(out,out);					/* Normalize for output color space */
11619
	rv |= p->out_abs(p,out,out);				/* Possible absolute conversion */
11620
 
11621
	return rv;
11622
}
11623
 
11624
#ifdef NEVER	/* The following should be identical in effect to the above. */
11625
 
11626
/* Overall lookup */
11627
static int
11628
icmLuLut_lookup (
11629
icmLuBase *pp,		/* This */
11630
double *out,		/* Vector of output values */
11631
double *in			/* Vector of input values */
11632
) {
11633
	int i, rv = 0;
11634
	icmLuLut *p = (icmLuLut *)pp;
11635
	icmLut *lut = p->lut;
11636
	double temp[MAX_CHAN];
11637
 
11638
	rv |= p->in_abs(p,temp,in);
11639
	rv |= p->matrix(p,temp,temp);
11640
	rv |= p->input(p,temp,temp);
11641
	rv |= p->clut(p,out,temp);
11642
	rv |= p->output(p,out,out);
11643
	rv |= p->out_abs(p,out,out);
11644
 
11645
	return rv;
11646
}
11647
#endif	/* NEVER */
11648
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
11649
/* Some components of inverse lookup, in order */
11650
/* ~~ should these be in icmLut (like all the fwd transforms)? */
11651
 
11652
static int icmLuLut_inv_out_abs(icmLuLut *p, double *out, double *in) {
11653
	icmLut *lut = p->lut;
11654
	int rv = 0;
11655
 
11656
	if (out != in) {
11657
		int i;
11658
		for (i = 0; i < lut->inputChan; i++)		/* Don't alter input values */
11659
			out[i] = in[i];
11660
	}
11661
 
11662
	/* If Fwd Lut, take care of Absolute color space */
11663
	/* and convert from effective to native inverse output PCS */
11664
	/* OutSpace must be PCS: XYZ or Lab */
11665
	if ((p->function == icmFwd || p->function == icmPreview)
11666
		&& p->intent == icAbsoluteColorimetric) {
11667
 
11668
		if (p->e_outSpace == icSigLabData)
11669
			icmLab2XYZ(&p->pcswht, out, out);
11670
 
11671
		/* Convert from Absolute to Relative colorometric */
11672
		icmMulBy3x3(out, p->fromAbs, out);
11673
 
11674
		if (p->outSpace == icSigLabData)
11675
			icmXYZ2Lab(&p->pcswht, out, out);
11676
 
11677
	} else {
11678
 
11679
		/* Convert from Effective to Native output space */
11680
		if (p->e_outSpace == icSigLabData && p->outSpace == icSigXYZData)
11681
			icmLab2XYZ(&p->pcswht, out, out);
11682
		else if (p->e_outSpace == icSigXYZData && p->outSpace == icSigLabData)
11683
			icmXYZ2Lab(&p->pcswht, out, out);
11684
	}
11685
	return rv;
11686
}
11687
 
11688
/* Do output->output' inverse lookup */
11689
static int icmLuLut_inv_output(icmLuLut *p, double *out, double *in) {
11690
	icc *icp = p->icp;
11691
	icmLut *lut = p->lut;
11692
	int rv = 0;
11693
 
11694
	if (lut->rot.inited == 0) {	
11695
		rv = icmTable_setup_bwd(icp, &lut->rot, lut->outputEnt, lut->outputTable);
11696
		if (rv != 0) {
11697
			sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
11698
			return icp->errc = rv;
11699
		}
11700
	}
11701
 
11702
	p->out_normf(out,in);						/* Normalize from output color space */
11703
	rv |= icmTable_lookup_bwd(&lut->rot, out, out); /* Reverse lookup though output tables */
11704
	p->out_denormf(out, out);					/* De-normalize to output color space */
11705
	return rv;
11706
}
11707
 
11708
/* No output' -> input inverse lookup. */
11709
/* This is non-trivial ! */
11710
 
11711
/* Do input' -> input inverse lookup */
11712
static int icmLuLut_inv_input(icmLuLut *p, double *out, double *in) {
11713
	icc *icp = p->icp;
11714
	icmLut *lut = p->lut;
11715
	int rv = 0;
11716
 
11717
	if (lut->rit.inited == 0) {	
11718
		rv = icmTable_setup_bwd(icp, &lut->rit, lut->inputEnt, lut->inputTable);
11719
		if (rv != 0) {
11720
			sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
11721
			return icp->errc = rv;
11722
		}
11723
	}
11724
 
11725
	p->in_normf(out, in); 						/* Normalize from input color space */
11726
	rv |= icmTable_lookup_bwd(&lut->rit, out, out); /* Reverse lookup though input tables */
11727
	p->in_denormf(out,out);						/* De-normalize to input color space */
11728
	return rv;
11729
}
11730
 
11731
/* Possible inverse matrix lookup */
11732
static int icmLuLut_inv_matrix(icmLuLut *p, double *out, double *in) {
11733
	icc *icp = p->icp;
11734
	icmLut *lut = p->lut;
11735
	int rv = 0;
11736
 
11737
	if (p->usematrix) {
11738
		double tt[3];
11739
		if (p->imx_valid == 0) {
11740
			if (inverse3x3(p->imx, lut->e) != 0) {	/* Compute inverse */
11741
				sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
11742
				icp->errc = 2;
11743
				return 2;
11744
			}
11745
			p->imx_valid = 1;
11746
		}
11747
		/* Matrix multiply */
11748
		tt[0] = p->imx[0][0] * in[0] + p->imx[0][1] * in[1] + p->imx[0][2] * in[2];
11749
		tt[1] = p->imx[1][0] * in[0] + p->imx[1][1] * in[1] + p->imx[1][2] * in[2];
11750
		tt[2] = p->imx[2][0] * in[0] + p->imx[2][1] * in[1] + p->imx[2][2] * in[2];
11751
		out[0] = tt[0], out[1] = tt[1], out[2] = tt[2];
11752
	} else if (out != in) {
11753
		int i;
11754
		for (i = 0; i < lut->inputChan; i++)
11755
			out[i] = in[i];
11756
	}
11757
	return rv;
11758
}
11759
 
11760
static int icmLuLut_inv_in_abs(icmLuLut *p, double *out, double *in) {
11761
	icmLut *lut = p->lut;
11762
	int rv = 0;
11763
 
11764
	if (out != in) {
11765
		int i;
11766
		for (i = 0; i < lut->inputChan; i++)		/* Don't alter input values */
11767
			out[i] = in[i];
11768
	}
11769
 
11770
	/* If Bwd Lut, take care of Absolute color space, and */
11771
	/* convert from native to effective input space */
11772
	if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
11773
		&& p->intent == icAbsoluteColorimetric) {
11774
 
11775
		if (p->inSpace == icSigLabData)
11776
			icmLab2XYZ(&p->pcswht, out, out);
11777
 
11778
		/* Convert from Relative to Absolute colorometric XYZ */
11779
		icmMulBy3x3(out, p->toAbs, out);
11780
 
11781
		if (p->e_inSpace == icSigLabData)
11782
			icmXYZ2Lab(&p->pcswht, out, out);
11783
	} else {
11784
 
11785
		/* Convert from Native to Effective input space */
11786
		if (p->inSpace == icSigLabData && p->e_inSpace == icSigXYZData)
11787
			icmLab2XYZ(&p->pcswht, out, out);
11788
		else if (p->inSpace == icSigXYZData && p->e_inSpace == icSigLabData)
11789
			icmXYZ2Lab(&p->pcswht, out, out);
11790
	}
11791
	return rv;
11792
}
11793
 
11794
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
11795
 
11796
/* Return LuLut information */
11797
static void icmLuLut_get_info(
11798
	icmLuLut     *p,		/* this */
11799
	icmLut       **lutp,	/* Pointer to icc lut type */
11800
	icmXYZNumber *pcswhtp,	/* Pointer to profile PCS white point */
11801
	icmXYZNumber *whitep,	/* Pointer to profile absolute white point */
11802
	icmXYZNumber *blackp	/* Pointer to profile absolute black point */
11803
) {
11804
	if (lutp != NULL)
11805
		*lutp = p->lut;
11806
	if (pcswhtp != NULL)
11807
		*pcswhtp = p->pcswht;
11808
	if (whitep != NULL)
11809
		*whitep = p->whitePoint;
11810
	if (blackp != NULL)
11811
		*blackp = p->blackPoint;
11812
}
11813
 
11814
/* Get the native ranges for the LuLut */
11815
static void
11816
icmLuLut_get_lutranges (
11817
	struct _icmLuLut *p,
11818
	double *inmin, double *inmax,		/* Return maximum range of inspace values */
11819
	double *outmin, double *outmax		/* Return maximum range of outspace values */
11820
) {
11821
	int i;
11822
 
11823
	for (i = 0; i < p->lut->inputChan; i++) {
11824
		inmin[i] = 0.0;	/* Normalized range of input space values */
11825
		inmax[i] = 1.0;
11826
	}
11827
	p->in_denormf(inmin,inmin);	/* Convert to real colorspace range */
11828
	p->in_denormf(inmax,inmax);
11829
 
11830
	/* Make sure min and max are so. */
11831
	for (i = 0; i < p->lut->inputChan; i++) {
11832
		if (inmin[i] > inmax[i]) {
11833
			double tt;
11834
			tt = inmin[i];
11835
			inmin[i] = inmax[i];
11836
			inmax[i] = tt;
11837
		}
11838
	}
11839
 
11840
	for (i = 0; i < p->lut->outputChan; i++) {
11841
		outmin[i] = 0.0;	/* Normalized range of output space values */
11842
		outmax[i] = 1.0;
11843
	}
11844
	p->out_denormf(outmin,outmin);	/* Convert to real colorspace range */
11845
	p->out_denormf(outmax,outmax);
11846
 
11847
	/* Make sure min and max are so. */
11848
	for (i = 0; i < p->lut->outputChan; i++) {
11849
		if (outmin[i] > outmax[i]) {
11850
			double tt;
11851
			tt = outmin[i];
11852
			outmin[i] = outmax[i];
11853
			outmax[i] = tt;
11854
		}
11855
	}
11856
}
11857
 
11858
/* Get the effective (externally visible) ranges for the LuLut */
11859
/* Arguments may be NULL */
11860
static void
11861
icmLuLut_get_ranges (
11862
	struct _icmLuBase *pp,
11863
	double *inmin, double *inmax,		/* Return maximum range of inspace values */
11864
	double *outmin, double *outmax		/* Return maximum range of outspace values */
11865
) {
11866
	icmLuLut *p = (icmLuLut *)pp;
11867
	double tinmin[MAX_CHAN], tinmax[MAX_CHAN], toutmin[MAX_CHAN], toutmax[MAX_CHAN];
11868
	int i;
11869
 
11870
	/* fudge NULL arguments so that they don't bomb */
11871
	if (inmin == NULL)
11872
		inmin = tinmin;
11873
	if (inmax == NULL)
11874
		inmax = tinmax;
11875
	if (outmin == NULL)
11876
		outmin = toutmin;
11877
	if (outmax == NULL)
11878
		outmax = toutmax;
11879
 
11880
	for (i = 0; i < p->lut->inputChan; i++) {
11881
		inmin[i] = 0.0;	/* Normalized range of input space values */
11882
		inmax[i] = 1.0;
11883
	}
11884
	p->e_in_denormf(inmin,inmin);	/* Convert to real colorspace range */
11885
	p->e_in_denormf(inmax,inmax);
11886
 
11887
	/* Make sure min and max are so. */
11888
	for (i = 0; i < p->lut->inputChan; i++) {
11889
		if (inmin[i] > inmax[i]) {
11890
			double tt;
11891
			tt = inmin[i];
11892
			inmin[i] = inmax[i];
11893
			inmax[i] = tt;
11894
		}
11895
	}
11896
 
11897
	for (i = 0; i < p->lut->outputChan; i++) {
11898
		outmin[i] = 0.0;	/* Normalized range of output space values */
11899
		outmax[i] = 1.0;
11900
	}
11901
	p->e_out_denormf(outmin,outmin);	/* Convert to real colorspace range */
11902
	p->e_out_denormf(outmax,outmax);
11903
 
11904
	/* Make sure min and max are so. */
11905
	for (i = 0; i < p->lut->outputChan; i++) {
11906
		if (outmin[i] > outmax[i]) {
11907
			double tt;
11908
			tt = outmin[i];
11909
			outmin[i] = outmax[i];
11910
			outmax[i] = tt;
11911
		}
11912
	}
11913
}
11914
 
11915
/* Return the underlying Lut matrix */
11916
static void
11917
icmLuLut_get_matrix (
11918
	struct _icmLuLut *p,
11919
	double m[3][3]
11920
) {
11921
	int i, j;
11922
	icmLut *lut = p->lut;
11923
 
11924
	if (p->usematrix) {
11925
		for (i = 0; i < 3; i++)
11926
			for (j = 0; j < 3; j++)
11927
				m[i][j] = lut->e[i][j];	/* Copy from Lut */
11928
 
11929
	} else {							/* return unity matrix */
11930
		for (i = 0; i < 3; i++) {
11931
			for (j = 0; j < 3; j++) {
11932
				if (i == j)
11933
					m[i][j] = 1.0;
11934
				else
11935
					m[i][j] = 0.0;
11936
			}
11937
		}
11938
	}
11939
}
11940
 
11941
 
11942
static void
11943
icmLuLut_delete(
11944
icmLuBase *p
11945
) {
11946
	icc *icp = p->icp;
11947
 
11948
	icp->al->free(icp->al, p);
11949
}
11950
 
11951
static icmLuBase *
11952
new_icmLuLut(
11953
	icc                   *icp,
11954
	icTagSignature        ttag,			/* Target Lut tag */
11955
    icColorSpaceSignature inSpace,		/* Native Input color space */
11956
    icColorSpaceSignature outSpace,		/* Native Output color space */
11957
    icColorSpaceSignature pcs,			/* Native PCS */
11958
    icColorSpaceSignature e_inSpace,	/* Effective Input color space */
11959
    icColorSpaceSignature e_outSpace,	/* Effective Output color space */
11960
    icColorSpaceSignature e_pcs,		/* Effective PCS */
11961
	icmXYZNumber          whitePoint,	/* Profile absolute white point */
11962
	icmXYZNumber          blackPoint,	/* Profile absolute black point */
11963
	icRenderingIntent     intent,		/* Rendering intent */
11964
	icmLookupFunc         func			/* Functionality requested */
11965
) {
11966
	icmLuLut *p;
11967
 
11968
	if ((p = (icmLuLut *) icp->al->calloc(icp->al,1,sizeof(icmLuLut))) == NULL)
11969
		return NULL;
11970
	p->ttype    = icmLutType;
11971
	p->icp      = icp;
11972
	p->del      = icmLuLut_delete;
11973
	p->lutspaces= icmLutSpaces;
11974
	p->spaces   = icmLuSpaces;
11975
	p->wh_bk_points = icmLuWh_bk_points;
11976
 
11977
	p->lookup   = icmLuLut_lookup;
11978
	p->in_abs   = icmLuLut_in_abs;
11979
	p->matrix   = icmLuLut_matrix;
11980
	p->input    = icmLuLut_input;
11981
	p->clut     = icmLuLut_clut;
11982
	p->output   = icmLuLut_output;
11983
	p->out_abs  = icmLuLut_out_abs;
11984
 
11985
	p->inv_in_abs   = icmLuLut_inv_in_abs;
11986
	p->inv_matrix   = icmLuLut_inv_matrix;
11987
	p->inv_input    = icmLuLut_inv_input;
11988
	p->inv_output   = icmLuLut_inv_output;
11989
	p->inv_out_abs  = icmLuLut_inv_out_abs;
11990
 
11991
	p->pcswht   = icp->header->illuminant;
11992
	p->whitePoint = whitePoint;
11993
	p->blackPoint = blackPoint;
11994
	p->intent   = intent;
11995
	p->function = func;
11996
	p->inSpace  = inSpace;
11997
	p->outSpace = outSpace;
11998
	p->pcs      = pcs;
11999
	p->e_inSpace  = e_inSpace;
12000
	p->e_outSpace = e_outSpace;
12001
	p->e_pcs      = e_pcs;
12002
	p->get_info = icmLuLut_get_info;
12003
	p->get_lutranges = icmLuLut_get_lutranges;
12004
	p->get_ranges = icmLuLut_get_ranges;
12005
	p->get_matrix = icmLuLut_get_matrix;
12006
 
12007
	/* Create absolute <-> relative conversion matricies */
12008
	icmChromAdaptMatrix(ICM_CAM_BRADFORD, whitePoint, icmD50, p->toAbs);
12009
	icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, whitePoint,  p->fromAbs);
12010
 
12011
	/* Get the Lut tag, & check that it is expected type */
12012
	if ((p->lut = (icmLut *)icp->read_tag(icp, ttag)) == NULL
12013
	 || (p->lut->ttype != icSigLut8Type && p->lut->ttype != icSigLut16Type)) {
12014
		p->del((icmLuBase *)p);
12015
		return NULL;
12016
	}
12017
 
12018
	/* Check if matrix should be used */
12019
	if (inSpace == icSigXYZData && p->lut->nu_matrix(p->lut))
12020
		p->usematrix = 1;
12021
	else
12022
		p->usematrix = 0;
12023
 
12024
	/* Lookup input color space to normalized index function */
12025
	if (getNormFunc(inSpace, p->lut->ttype, icmToLuti, &p->in_normf)) {
12026
		sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12027
		icp->errc = 1;
12028
		p->del((icmLuBase *)p);
12029
		return NULL;
12030
	}
12031
 
12032
	/* Lookup normalized index to input color space function */
12033
	if (getNormFunc(inSpace, p->lut->ttype, icmFromLuti, &p->in_denormf)) {
12034
		sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12035
		icp->errc = 1;
12036
		p->del((icmLuBase *)p);
12037
		return NULL;
12038
	}
12039
 
12040
	/* Lookup output color space to normalized Lut entry value function */
12041
	if (getNormFunc(outSpace, p->lut->ttype, icmToLutv, &p->out_normf)) {
12042
		sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12043
		icp->errc = 1;
12044
		p->del((icmLuBase *)p);
12045
		return NULL;
12046
	}
12047
 
12048
	/* Lookup normalized Lut entry value to output color space function */
12049
	if (getNormFunc(outSpace, p->lut->ttype, icmFromLutv, &p->out_denormf)) {
12050
		sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
12051
		icp->errc = 1;
12052
		p->del((icmLuBase *)p);
12053
		return NULL;
12054
	}
12055
 
12056
	/* Lookup normalized index to effective input color space function */
12057
	if (getNormFunc(e_inSpace, p->lut->ttype, icmFromLuti, &p->e_in_denormf)) {
12058
		sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
12059
		icp->errc = 1;
12060
		p->del((icmLuBase *)p);
12061
		return NULL;
12062
	}
12063
 
12064
	/* Lookup normalized Lut entry value to effective output color space function */
12065
	if (getNormFunc(e_outSpace, p->lut->ttype, icmFromLutv, &p->e_out_denormf)) {
12066
		sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
12067
		icp->errc = 1;
12068
		p->del((icmLuBase *)p);
12069
		return NULL;
12070
	}
12071
 
12072
	/* Determine appropriate clut lookup algorithm */
12073
	{
12074
		int use_sx;				/* -1 = undecided, 0 = N-linear, 1 = Simplex lookup */
12075
		icColorSpaceSignature ins, outs;	/* In and out Lut color spaces */
12076
		int inn, outn;		/* in and out number of Lut components */
12077
 
12078
		p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn);
12079
 
12080
		/* Determine if the input space is "Device" like, */
12081
		/* ie. luminance will be expected to vary most strongly */
12082
		/* with the diagonal change in input coordinates. */
12083
		switch(ins) {
12084
 
12085
			/* Luminence is carried by the sum of all the output channels, */
12086
			/* so output luminence will dominantly be in diagonal direction. */
12087
			case icSigRgbData:
12088
			case icSigGrayData:
12089
			case icSigCmykData:
12090
			case icSigCmyData:
12091
			case icSigMch6Data:
12092
				use_sx = 1;		/* Simplex interpolation is appropriate */
12093
				break;
12094
 
12095
			/* A single channel carries the luminence information */
12096
			case icSigLabData:
12097
			case icSigLuvData:
12098
			case icSigYCbCrData:
12099
			case icSigYxyData:
12100
			case icSigXYZData:
12101
			case icSigHlsData:
12102
			case icSigHsvData:
12103
				use_sx = 0;		/* N-linear interpolation is appropriate */
12104
				break;
12105
			default:
12106
				use_sx = -1;		/* undecided */
12107
			    	break;
12108
		}
12109
 
12110
		/* If we couldn't figure it out from the input space, */
12111
		/* check output luminance variation with a diagonal input */
12112
		/* change. */
12113
		if (use_sx == -1) {
12114
			int lc;		/* Luminance channel */
12115
 
12116
			/* Determine where the luminence is carried in the output */
12117
			switch(outs) {
12118
 
12119
				/* Luminence is carried by the sum of all the output channels */
12120
				case icSigRgbData:
12121
				case icSigGrayData:
12122
				case icSigCmykData:
12123
				case icSigCmyData:
12124
				case icSigMch6Data:
12125
					lc = -1;		/* Average all channels */
12126
					break;
12127
 
12128
				/* A single channel carries the luminence information */
12129
				case icSigLabData:
12130
				case icSigLuvData:
12131
				case icSigYCbCrData:
12132
				case icSigYxyData:
12133
					lc = 0;
12134
					break;
12135
 
12136
				case icSigXYZData:
12137
				case icSigHlsData:
12138
					lc = 1;
12139
					break;
12140
 
12141
				case icSigHsvData:
12142
					lc = 2;
12143
					break;
12144
 
12145
				/* default means give up and use N-linear type lookup */
12146
				default:
12147
					lc = -2;
12148
					break;
12149
			}
12150
 
12151
			/* If we know how luminance is represented in output space */
12152
			if (lc != -2) {
12153
				double tout1[MAX_CHAN];		/* Test output values */
12154
				double tout2[MAX_CHAN];
12155
				double tt, diag;
12156
				int n;
12157
 
12158
				/* Determine input space location of min and max of */
12159
				/* given output channel (chan = -1 means average of all) */
12160
				p->lut->min_max(p->lut, tout1, tout2, lc);
12161
 
12162
				/* Convert to vector and then calculate normalized */
12163
				/* dot product with diagonal vector (1,1,1...) */
12164
				for (tt = 0.0, n = 0; n < inn; n++) {
12165
					tout1[n] = tout2[n] - tout1[n];
12166
					tt += tout1[n] * tout1[n];
12167
				}
12168
				if (tt > 0.0)
12169
					tt = sqrt(tt);			/* normalizing factor for maximum delta */
12170
				else
12171
					tt = 1.0;				/* Hmm. */
12172
				tt *= sqrt((double)inn);	/* Normalizing factor for diagonal vector */
12173
				for (diag = 0.0, n = 0; n < outn; n++)
12174
					diag += tout1[n] / tt;
12175
				diag = fabs(diag);
12176
 
12177
				/* I'm not really convinced that this is a reliable */
12178
				/* indicator of whether simplex interpolation should be used ... */
12179
				/* It does seem to do the right thing with YCC space though. */
12180
				if (diag > 0.8)	/* Diagonal is dominant ? */
12181
					use_sx = 1;
12182
 
12183
				/* If we couldn't figure it out, use N-linear interpolation */
12184
				if (use_sx == -1)
12185
					use_sx = 0;
12186
			}
12187
		}
12188
 
12189
		if (use_sx) {
12190
			p->lookup_clut = p->lut->lookup_clut_sx;
12191
		} else
12192
			p->lookup_clut = p->lut->lookup_clut_nl;
12193
	}
12194
	return (icmLuBase *)p;
12195
}
12196
 
12197
/* - - - - - - - - - - - - - - - - - - - - - - - */
12198
 
12199
/* Return an appropriate lookup object */
12200
/* Return NULL on error, and detailed error in icc */
12201
static icmLuBase* icc_get_luobj (
12202
	icc *p,						/* ICC */
12203
	icmLookupFunc func,			/* Conversion functionality */
12204
	icRenderingIntent intent,	/* Rendering intent, including icmAbsoluteColorimetricXYZ */
12205
	icColorSpaceSignature pcsor,/* PCS overide (0 = def) */
12206
	icmLookupOrder order		/* Conversion representation search Order */
12207
) {
12208
	int rv;
12209
	icmLuBase *luobj = NULL;	/* Lookup object to return */
12210
	icmXYZNumber whitePoint, blackPoint;
12211
	icColorSpaceSignature pcs, e_pcs;	/* PCS and effective PCS */
12212
 
12213
	/* Check that the profile is legal, since we depend on it */
12214
	if ((rv = check_icc_legal(p)) != 0)
12215
		return NULL;
12216
 
12217
	/* Figure out the native and effective PCS */
12218
	e_pcs = pcs = p->header->pcs;
12219
	if (pcsor != icmSigDefaultData)
12220
		e_pcs = pcsor;			/* Overide */
12221
 
12222
	/* Get White and Black points from the profile */
12223
	{
12224
		icmXYZArray *whitePointTag, *blackPointTag;
12225
 
12226
		if ((whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) == NULL
12227
         || whitePointTag->ttype != icSigXYZType || whitePointTag->size < 1) {
12228
			if (intent == icAbsoluteColorimetric) {
12229
				sprintf(p->err,"icc_lookup: Profile is missing Media White Point Tag");
12230
				p->errc = 1;
12231
				return NULL;
12232
			}
12233
			whitePoint = icmD50;						/* safe value */
12234
		} else
12235
			whitePoint = whitePointTag->data[0];	/* Copy structure */
12236
 
12237
		if ((blackPointTag = (icmXYZArray *)p->read_tag(p, icSigMediaBlackPointTag)) == NULL
12238
         || blackPointTag->ttype != icSigXYZType || blackPointTag->size < 1) {
12239
			blackPoint = icmBlack;						/* default */
12240
		} else 
12241
			blackPoint = blackPointTag->data[0];	/* Copy structure */
12242
	}
12243
 
12244
	/* How we expect to execute the request depends firstly on the type of profile */
12245
	switch (p->header->deviceClass) {
12246
    	case icSigInputClass:
12247
    	case icSigDisplayClass:
12248
			/* Look for AToB0 based profile + optional BToA0 reverse */
12249
			/* or three component matrix profile (reversable) */
12250
			/* or momochrome table profile (reversable) */ 
12251
			/* No intent */
12252
			/* Device <-> PCS */
12253
			/* Determine the algorithm and set its parameters */
12254
 
12255
			if (intent != icmDefaultIntent
12256
			 && intent != icAbsoluteColorimetric) {
12257
				sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Input/Display profile");
12258
				p->errc = 1;
12259
				return NULL;
12260
			}
12261
 
12262
			switch (func) {
12263
		    	case icmFwd:	/* Device to PCS */
12264
					if (order != icmLuOrdRev) {
12265
						/* Try Lut type lookup first */
12266
						if ((luobj = new_icmLuLut(p, icSigAToB0Tag,
12267
						     p->header->colorSpace, pcs, pcs,
12268
						     p->header->colorSpace, e_pcs, e_pcs,
12269
						     whitePoint, blackPoint, intent, func)) != NULL)
12270
							break;
12271
 
12272
						/* See if it could be a matrix lookup */
12273
						if ((luobj = new_icmLuMatrixFwd(p,
12274
						     p->header->colorSpace, pcs, pcs,
12275
						     p->header->colorSpace, e_pcs, e_pcs,
12276
						     whitePoint, blackPoint, intent, func)) != NULL)
12277
							break;
12278
 
12279
						/* See if it could be a monochrome lookup */
12280
						if ((luobj = new_icmLuMonoFwd(p,
12281
						     p->header->colorSpace, pcs, pcs,
12282
						     p->header->colorSpace, e_pcs, e_pcs,
12283
						     whitePoint, blackPoint, intent, func)) != NULL)
12284
							break;
12285
 
12286
					} else {
12287
						/* See if it could be a monochrome lookup */
12288
						if ((luobj = new_icmLuMonoFwd(p,
12289
						     p->header->colorSpace, pcs, pcs,
12290
						     p->header->colorSpace, e_pcs, e_pcs,
12291
						     whitePoint, blackPoint, intent, func)) != NULL)
12292
							break;
12293
 
12294
						/* See if it could be a matrix lookup */
12295
						if ((luobj = new_icmLuMatrixFwd(p,
12296
						     p->header->colorSpace, pcs, pcs,
12297
						     p->header->colorSpace, e_pcs, e_pcs,
12298
						     whitePoint, blackPoint, intent, func)) != NULL)
12299
							break;
12300
 
12301
						/* Try Lut type lookup last */
12302
						if ((luobj = new_icmLuLut(p, icSigAToB0Tag,
12303
						     p->header->colorSpace, pcs, pcs,
12304
						     p->header->colorSpace, e_pcs, e_pcs,
12305
						     whitePoint, blackPoint, intent, func)) != NULL)
12306
							break;
12307
					}
12308
					break;
12309
 
12310
		    	case icmBwd:	/* PCS to Device */
12311
					if (order != icmLuOrdRev) {
12312
						/* Try Lut type lookup first */
12313
						if ((luobj = new_icmLuLut(p, icSigBToA0Tag,
12314
						     pcs, p->header->colorSpace, pcs,
12315
						     e_pcs, p->header->colorSpace, e_pcs,
12316
						     whitePoint, blackPoint, intent, func)) != NULL)
12317
							break;
12318
 
12319
						/* See if it could be a matrix lookup */
12320
						if ((luobj = new_icmLuMatrixBwd(p,
12321
						     pcs, p->header->colorSpace, pcs,
12322
						     e_pcs, p->header->colorSpace, e_pcs,
12323
						     whitePoint, blackPoint, intent, func)) != NULL)
12324
							break;
12325
 
12326
						/* See if it could be a monochrome lookup */
12327
						if ((luobj = new_icmLuMonoBwd(p,
12328
						     pcs, p->header->colorSpace, pcs,
12329
						     e_pcs, p->header->colorSpace, e_pcs,
12330
						     whitePoint, blackPoint, intent, func)) != NULL)
12331
							break;
12332
					} else {
12333
						/* See if it could be a monochrome lookup */
12334
						if ((luobj = new_icmLuMonoBwd(p,
12335
						     pcs, p->header->colorSpace, pcs,
12336
						     e_pcs, p->header->colorSpace, e_pcs,
12337
						     whitePoint, blackPoint, intent, func)) != NULL)
12338
							break;
12339
 
12340
						/* See if it could be a matrix lookup */
12341
						if ((luobj = new_icmLuMatrixBwd(p,
12342
						     pcs, p->header->colorSpace, pcs,
12343
						     e_pcs, p->header->colorSpace, e_pcs,
12344
						     whitePoint, blackPoint, intent, func)) != NULL)
12345
							break;
12346
 
12347
						/* Try Lut type lookup last */
12348
						if ((luobj = new_icmLuLut(p, icSigBToA0Tag,
12349
						     pcs, p->header->colorSpace, pcs,
12350
						     e_pcs, p->header->colorSpace, e_pcs,
12351
						     whitePoint, blackPoint, intent, func)) != NULL)
12352
							break;
12353
					}
12354
					break;
12355
 
12356
				default:
12357
					sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12358
					p->errc = 1;
12359
					return NULL;
12360
				}
12361
			break;
12362
 
12363
    	case icSigOutputClass:
12364
			/* Expect BToA Lut and optional AToB Lut, All intents, expect gamut */
12365
			/* or momochrome table profile (reversable) */ 
12366
			/* Device <-> PCS */
12367
			/* Gamut Lut - no intent */
12368
			/* Optional preview links PCS <-> PCS */
12369
 
12370
			/* Determine the algorithm and set its parameters */
12371
			switch (func) {
12372
				icTagSignature ttag;
12373
 
12374
		    	case icmFwd:	/* Device to PCS */
12375
 
12376
					if (intent == icmDefaultIntent)
12377
						intent = icRelativeColorimetric;	/* Make this the default */
12378
 
12379
					switch (intent) {
12380
		    			case icRelativeColorimetric:
12381
		    			case icAbsoluteColorimetric:
12382
								ttag = icSigAToB1Tag;
12383
							break;
12384
		    			case icPerceptual:
12385
								ttag = icSigAToB0Tag;
12386
							break;
12387
		    			case icSaturation:
12388
								ttag = icSigAToB2Tag;
12389
							break;
12390
						default:
12391
							sprintf(p->err,"icc_get_luobj: Unknown intent");
12392
							p->errc = 1;
12393
							return NULL;
12394
					}
12395
 
12396
					if (order != icmLuOrdRev) {
12397
						/* Try Lut type lookup first */
12398
						if ((luobj = new_icmLuLut(p, ttag,
12399
						     p->header->colorSpace, pcs, pcs,
12400
						     p->header->colorSpace, e_pcs, e_pcs,
12401
						     whitePoint, blackPoint, intent, func)) != NULL)
12402
							break;
12403
 
12404
						/* See if it could be a matrix lookup */
12405
						if ((luobj = new_icmLuMatrixFwd(p,
12406
						     p->header->colorSpace, pcs, pcs,
12407
						     p->header->colorSpace, e_pcs, e_pcs,
12408
						     whitePoint, blackPoint, intent, func)) != NULL)
12409
							break;
12410
 
12411
						/* See if it could be a monochrome lookup */
12412
						if ((luobj = new_icmLuMonoFwd(p,
12413
						     p->header->colorSpace, pcs, pcs,
12414
						     p->header->colorSpace, e_pcs, e_pcs,
12415
						     whitePoint, blackPoint, intent, func)) != NULL)
12416
							break;
12417
					} else {
12418
						/* See if it could be a monochrome lookup */
12419
						if ((luobj = new_icmLuMonoFwd(p,
12420
						     p->header->colorSpace, pcs, pcs,
12421
						     p->header->colorSpace, e_pcs, e_pcs,
12422
						     whitePoint, blackPoint, intent, func)) != NULL)
12423
							break;
12424
 
12425
						/* See if it could be a matrix lookup */
12426
						if ((luobj = new_icmLuMatrixFwd(p,
12427
						     p->header->colorSpace, pcs, pcs,
12428
						     p->header->colorSpace, e_pcs, e_pcs,
12429
						     whitePoint, blackPoint, intent, func)) != NULL)
12430
							break;
12431
 
12432
						/* Try Lut type lookup last */
12433
						if ((luobj = new_icmLuLut(p, ttag,
12434
						     p->header->colorSpace, pcs, pcs,
12435
						     p->header->colorSpace, e_pcs, e_pcs,
12436
						     whitePoint, blackPoint, intent, func)) != NULL)
12437
							break;
12438
					}
12439
					break;
12440
 
12441
		    	case icmBwd:	/* PCS to Device */
12442
 
12443
					if (intent == icmDefaultIntent)
12444
						intent = icRelativeColorimetric;	/* Make this the default */
12445
 
12446
					switch (intent) {
12447
		    			case icRelativeColorimetric:
12448
		    			case icAbsoluteColorimetric:
12449
								ttag = icSigBToA1Tag;
12450
							break;
12451
		    			case icPerceptual:
12452
								ttag = icSigBToA0Tag;
12453
							break;
12454
		    			case icSaturation:
12455
								ttag = icSigBToA2Tag;
12456
							break;
12457
						default:
12458
							sprintf(p->err,"icc_get_luobj: Unknown intent");
12459
							p->errc = 1;
12460
							return NULL;
12461
					}
12462
 
12463
					if (order != icmLuOrdRev) {
12464
						/* Try Lut type lookup first */
12465
						if ((luobj = new_icmLuLut(p, ttag,
12466
						     pcs, p->header->colorSpace, pcs,
12467
						     e_pcs, p->header->colorSpace, e_pcs,
12468
						     whitePoint, blackPoint, intent, func)) != NULL)
12469
							break;
12470
 
12471
						/* See if it could be a matrix lookup */
12472
						if ((luobj = new_icmLuMatrixBwd(p,
12473
						     pcs, p->header->colorSpace, pcs,
12474
						     e_pcs, p->header->colorSpace, e_pcs,
12475
						     whitePoint, blackPoint, intent, func)) != NULL)
12476
							break;
12477
 
12478
						/* See if it could be a monochrome lookup */
12479
						if ((luobj = new_icmLuMonoBwd(p,
12480
						     pcs, p->header->colorSpace, pcs,
12481
						     e_pcs, p->header->colorSpace, e_pcs,
12482
						     whitePoint, blackPoint, intent, func)) != NULL)
12483
							break;
12484
					} else {
12485
						/* See if it could be a monochrome lookup */
12486
						if ((luobj = new_icmLuMonoBwd(p,
12487
						     pcs, p->header->colorSpace, pcs,
12488
						     e_pcs, p->header->colorSpace, e_pcs,
12489
						     whitePoint, blackPoint, intent, func)) != NULL)
12490
							break;
12491
 
12492
						/* See if it could be a matrix lookup */
12493
						if ((luobj = new_icmLuMatrixBwd(p,
12494
						     pcs, p->header->colorSpace, pcs,
12495
						     e_pcs, p->header->colorSpace, e_pcs,
12496
						     whitePoint, blackPoint, intent, func)) != NULL)
12497
							break;
12498
 
12499
						/* Try Lut type lookup last */
12500
						if ((luobj = new_icmLuLut(p, ttag,
12501
						     pcs, p->header->colorSpace, pcs,
12502
						     e_pcs, p->header->colorSpace, e_pcs,
12503
						     whitePoint, blackPoint, intent, func)) != NULL)
12504
							break;
12505
					}
12506
					break;
12507
 
12508
		    	case icmGamut:	/* PCS to 1D */
12509
 
12510
					if (intent != icmDefaultIntent) {
12511
						sprintf(p->err,"icc_get_luobj: Intent is inappropriate for type of function");
12512
						p->errc = 1;
12513
						return NULL;
12514
					}
12515
 
12516
					/* If the target tag exists, and it is a Lut */
12517
					luobj = new_icmLuLut(p, icSigGamutTag,
12518
					     pcs, icSigGrayData, pcs,
12519
					     e_pcs, icSigGrayData, e_pcs,
12520
					     whitePoint, blackPoint, intent, func);
12521
					break;
12522
 
12523
		    	case icmPreview:	/* PCS to PCS */
12524
 
12525
					switch (intent)  {
12526
		    			case icRelativeColorimetric:
12527
								ttag = icSigPreview1Tag;
12528
							break;
12529
		    			case icPerceptual:
12530
								ttag = icSigPreview0Tag;
12531
							break;
12532
		    			case icSaturation:
12533
								ttag = icSigPreview2Tag;
12534
							break;
12535
		    			case icAbsoluteColorimetric:
12536
							sprintf(p->err,"icc_get_luobj: Intent is inappropriate for type of function");
12537
							p->errc = 1;
12538
							return NULL;
12539
						default:
12540
							sprintf(p->err,"icc_get_luobj: Unknown intent");
12541
							p->errc = 1;
12542
							return NULL;
12543
					}
12544
 
12545
					/* If the target tag exists, and it is a Lut */
12546
					luobj = new_icmLuLut(p, ttag,
12547
					     pcs, pcs, pcs,
12548
					     e_pcs, e_pcs, e_pcs,
12549
					     whitePoint, blackPoint, intent, func);
12550
					break;
12551
 
12552
				default:
12553
					sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12554
					p->errc = 1;
12555
					return NULL;
12556
			}
12557
			break;
12558
 
12559
    	case icSigLinkClass:
12560
			/* Expect AToB0 Lut and optional BToA0 Lut, One intent in header */
12561
			/* Device <-> Device */
12562
 
12563
			if (intent != p->header->renderingIntent
12564
			 && intent != icmDefaultIntent) {
12565
				sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Link profile");
12566
				p->errc = 1;
12567
				return NULL;
12568
			}
12569
			intent = p->header->renderingIntent;
12570
 
12571
			/* Determine the algorithm and set its parameters */
12572
			switch (func) {
12573
		    	case icmFwd:	/* Device to PCS (== Device) */
12574
 
12575
					luobj = new_icmLuLut(p, icSigAToB0Tag,
12576
					     p->header->colorSpace, pcs, pcs,
12577
					     p->header->colorSpace, pcs, pcs,
12578
					     whitePoint, blackPoint, intent, func);
12579
					break;
12580
 
12581
		    	case icmBwd:	/* PCS (== Device) to Device */
12582
 
12583
					luobj = new_icmLuLut(p, icSigBToA0Tag,
12584
					     pcs, p->header->colorSpace, pcs,
12585
					     pcs, p->header->colorSpace, pcs,
12586
					     whitePoint, blackPoint, intent, func);
12587
					break;
12588
 
12589
				default:
12590
					sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12591
					p->errc = 1;
12592
					return NULL;
12593
			}
12594
			break;
12595
 
12596
    	case icSigAbstractClass:
12597
			/* Expect AToB0 Lut and BToA Lut, no intents */
12598
			/* PCS <-> PCS */
12599
			/* Determine the algorithm and set its parameters */
12600
 
12601
			if (intent != icmDefaultIntent) {
12602
				sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Abstract profile");
12603
				p->errc = 1;
12604
				return NULL;
12605
			}
12606
 
12607
			switch (func) {
12608
		    	case icmFwd:	/* PCS (== Device) to PCS */
12609
 
12610
					luobj = new_icmLuLut(p, icSigAToB0Tag,
12611
					     p->header->colorSpace, pcs, pcs,
12612
					     e_pcs, e_pcs, e_pcs,
12613
					     whitePoint, blackPoint, intent, func);
12614
					break;
12615
 
12616
		    	case icmBwd:	/* PCS to PCS (== Device) */
12617
 
12618
					luobj = new_icmLuLut(p, icSigBToA0Tag,
12619
					     pcs, p->header->colorSpace, pcs,
12620
					     e_pcs, e_pcs, e_pcs,
12621
					     whitePoint, blackPoint, intent, func);
12622
					break;
12623
 
12624
				default:
12625
					sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12626
					p->errc = 1;
12627
					return NULL;
12628
			}
12629
			break;
12630
 
12631
    	case icSigColorSpaceClass:
12632
			/* Expect AToB0 Lut and BToA0 Lut, no intents, */
12633
			/* Device <-> PCS */
12634
 
12635
			if (intent != icmDefaultIntent) {
12636
				sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Colorspace profile");
12637
				p->errc = 1;
12638
				return NULL;
12639
			}
12640
 
12641
			/* Determine the algorithm and set its parameters */
12642
			switch (func) {
12643
		    	case icmFwd:	/* Device to PCS */
12644
 
12645
					luobj = new_icmLuLut(p, icSigAToB0Tag,
12646
					     p->header->colorSpace, pcs, pcs,
12647
					     p->header->colorSpace, e_pcs, e_pcs,
12648
					     whitePoint, blackPoint, intent, func);
12649
					break;
12650
 
12651
		    	case icmBwd:	/* PCS to Device */
12652
 
12653
					luobj = new_icmLuLut(p, icSigBToA0Tag,
12654
					     pcs, p->header->colorSpace, pcs,
12655
					     e_pcs, p->header->colorSpace, e_pcs,
12656
					     whitePoint, blackPoint, intent, func);
12657
					break;
12658
 
12659
				default:
12660
					sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
12661
					p->errc = 1;
12662
					return NULL;
12663
			}
12664
			break;
12665
 
12666
    	case icSigNamedColorClass:
12667
			/* Expect Name -> Device, Optional PCS */
12668
			/* and a reverse lookup would be useful */
12669
			/* (ie. PCS or Device coords to closest named color) */
12670
			/* ~~ to be implemented ~~ */
12671
 
12672
			/* ~~ Absolute intent is valid for processing of */
12673
			/* PCS from named Colors. Also allow for e_pcs */
12674
			if (intent != icmDefaultIntent) {
12675
				sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Named Color profile");
12676
				p->errc = 1;
12677
				return NULL;
12678
			}
12679
 
12680
			sprintf(p->err,"icc_get_luobj: Named Colors not handled yet");
12681
			p->errc = 1;
12682
			return NULL;
12683
 
12684
    	default:
12685
			sprintf(p->err,"icc_get_luobj: Unknown profile class");
12686
			p->errc = 1;
12687
			return NULL;
12688
	}
12689
 
12690
	return luobj;
12691
}
12692
 
12693
/* - - - - - - - - - - - - - - - - - - - - - - - - */
12694
 
12695
/* Create an empty object. Return null on error */
12696
icc *new_icc_a(
12697
icmAlloc *al			/* Optional memory allocator. NULL for default */
12698
) {
12699
	icc *p;
12700
	int del_al = 0;
12701
 
12702
	if (al == NULL) {	/* None provided, create default */
12703
		if ((al = new_icmAllocStd()) == NULL)
12704
			return NULL;
12705
		del_al = 1;		/* We need to delete it */
12706
	}
12707
 
12708
	if ((p = (icc *) al->calloc(al, 1,sizeof(icc))) == NULL)
12709
		return NULL;
12710
	p->al = al;				/* Heap allocator */
12711
	p->del_al = del_al;		/* Flag noting whether we delete it */
12712
 
12713
	p->get_size      = icc_get_size;
12714
	p->read          = icc_read;
12715
	p->write         = icc_write;
12716
	p->dump          = icc_dump;
12717
	p->del           = icc_delete;
12718
	p->add_tag       = icc_add_tag;
12719
	p->link_tag      = icc_link_tag;
12720
	p->find_tag      = icc_find_tag;
12721
	p->read_tag      = icc_read_tag;
12722
	p->rename_tag    = icc_rename_tag;
12723
	p->unread_tag    = icc_unread_tag;
12724
	p->read_all_tags = icc_read_all_tags;
12725
	p->delete_tag    = icc_delete_tag;
12726
 
12727
	p->get_luobj  = icc_get_luobj;
12728
 
12729
#if defined(__IBMC__) && defined(_M_IX86)
12730
	_control87(EM_UNDERFLOW, EM_UNDERFLOW);
12731
#endif
12732
 
12733
	/* Allocate a header object */
12734
	if ((p->header = new_icmHeader(p)) == NULL) {
12735
		al->free(al, p);
12736
		if (del_al)
12737
			al->del(al);
12738
		return NULL;
12739
	}
12740
 
12741
	/* Values that must be set before writing */
12742
	p->header->deviceClass = icMaxEnumClass;/* Type of profile - must be set! */
12743
    p->header->colorSpace = icMaxEnumData;	/* Clr space of data - must be set! */
12744
    p->header->pcs = icMaxEnumData;			/* PCS: XYZ or Lab - must be set! */
12745
    p->header->renderingIntent = icMaxEnumIntent;	/* Rendering intent - must be set ! */
12746
 
12747
	/* Values that should be set before writing */
12748
	p->header->manufacturer = -1;			/* Dev manufacturer - should be set ! */
12749
    p->header->model = -1;					/* Dev model number - should be set ! */
12750
    p->header->attributes.l = 0;			/* ICC Device attributes - should set ! */
12751
    p->header->flags = 0;					/* Embedding flags - should be set ! */
12752
 
12753
	/* Values that may be set before writing */
12754
    p->header->attributes.h = 0;			/* Dev Device attributes - may be set ! */
12755
    p->header->creator = str2tag("argl");	/* Profile creator - Argyll - may be set ! */
12756
 
12757
	/* Init default values in header */
12758
	p->header->cmmId = str2tag("argl");		/* CMM for profile - Argyll CMM */
12759
    p->header->majv = 2;					/* Current version 2.1.0 */
12760
	p->header->minv = 1;
12761
	p->header->bfv  = 0;
12762
	setcur_DateTimeNumber(&p->header->date);/* Creation Date */
12763
    p->header->platform = icSigMicrosoft;	/* Primary Platform */
12764
    p->header->illuminant = icmD50;			/* Profile illuminant - D50 */
12765
 
12766
	return p;
12767
}
12768
 
12769
 
12770
/* For backwards compatibility - a NULL allocator version */
12771
icc *new_icc(void) {
12772
	return new_icc_a(NULL);
12773
}
12774
 
12775
 
12776
/* ---------------------------------------------------------- */