]> Creatis software - gdcm.git/blob - src/gdcmjasper/src/libjasper/base/jas_icc.c
COMP: applying another patch send to jasper group, to please bcc32 5.5.1
[gdcm.git] / src / gdcmjasper / src / libjasper / base / jas_icc.c
1 /*
2  * Copyright (c) 2002-2003 Michael David Adams.
3  * All rights reserved.
4  */
5
6 /* __START_OF_JASPER_LICENSE__
7  * 
8  * JasPer License Version 2.0
9  * 
10  * Copyright (c) 1999-2000 Image Power, Inc.
11  * Copyright (c) 1999-2000 The University of British Columbia
12  * Copyright (c) 2001-2003 Michael David Adams
13  * 
14  * All rights reserved.
15  * 
16  * Permission is hereby granted, free of charge, to any person (the
17  * "User") obtaining a copy of this software and associated documentation
18  * files (the "Software"), to deal in the Software without restriction,
19  * including without limitation the rights to use, copy, modify, merge,
20  * publish, distribute, and/or sell copies of the Software, and to permit
21  * persons to whom the Software is furnished to do so, subject to the
22  * following conditions:
23  * 
24  * 1.  The above copyright notices and this permission notice (which
25  * includes the disclaimer below) shall be included in all copies or
26  * substantial portions of the Software.
27  * 
28  * 2.  The name of a copyright holder shall not be used to endorse or
29  * promote products derived from the Software without specific prior
30  * written permission.
31  * 
32  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
33  * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
34  * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
35  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
37  * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
38  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
39  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
40  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
41  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
42  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
43  * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
44  * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
45  * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
46  * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
47  * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
48  * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
49  * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
50  * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
51  * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
52  * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
53  * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
54  * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
55  * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
56  * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
57  * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
58  * 
59  * __END_OF_JASPER_LICENSE__
60  */
61
62 #include <assert.h>
63 #include <jasper/jas_config.h>
64 #include <jasper/jas_types.h>
65 #include <jasper/jas_malloc.h>
66 #include <jasper/jas_debug.h>
67 #include <jasper/jas_icc.h>
68 #include <jasper/jas_cm.h>
69 #include <jasper/jas_stream.h>
70
71 #include <stdlib.h>
72 #include <ctype.h>
73
74 #define  jas_iccputuint8(out, val)  jas_iccputuint(out, 1, val)
75 #define  jas_iccputuint16(out, val)  jas_iccputuint(out, 2, val)
76 #define  jas_iccputsint32(out, val)  jas_iccputsint(out, 4, val)
77 #define  jas_iccputuint32(out, val)  jas_iccputuint(out, 4, val)
78 #define  jas_iccputuint64(out, val)  jas_iccputuint(out, 8, val)
79
80 static jas_iccattrval_t *jas_iccattrval_create0(void);
81
82 static int jas_iccgetuint(jas_stream_t *in, int n, ulonglong *val);
83 static int jas_iccgetuint8(jas_stream_t *in, jas_iccuint8_t *val);
84 static int jas_iccgetuint16(jas_stream_t *in, jas_iccuint16_t *val);
85 static int jas_iccgetsint32(jas_stream_t *in, jas_iccsint32_t *val);
86 static int jas_iccgetuint32(jas_stream_t *in, jas_iccuint32_t *val);
87 static int jas_iccgetuint64(jas_stream_t *in, jas_iccuint64_t *val);
88 static int jas_iccputuint(jas_stream_t *out, int n, ulonglong val);
89 static int jas_iccputsint(jas_stream_t *out, int n, longlong val);
90 static jas_iccprof_t *jas_iccprof_create(void);
91 static int jas_iccprof_readhdr(jas_stream_t *in, jas_icchdr_t *hdr);
92 static int jas_iccprof_writehdr(jas_stream_t *out, jas_icchdr_t *hdr);
93 static int jas_iccprof_gettagtab(jas_stream_t *in, jas_icctagtab_t *tagtab);
94 static void jas_iccprof_sorttagtab(jas_icctagtab_t *tagtab);
95 static int jas_iccattrtab_lookup(jas_iccattrtab_t *attrtab, jas_iccuint32_t name);
96 static jas_iccattrtab_t *jas_iccattrtab_copy(jas_iccattrtab_t *attrtab);
97 static jas_iccattrvalinfo_t *jas_iccattrvalinfo_lookup(jas_iccsig_t name);
98 static int jas_iccgettime(jas_stream_t *in, jas_icctime_t *time);
99 static int jas_iccgetxyz(jas_stream_t *in, jas_iccxyz_t *xyz);
100 static int jas_icctagtabent_cmp(const void *src, const void *dst);
101
102 static void jas_icccurv_destroy(jas_iccattrval_t *attrval);
103 static int jas_icccurv_copy(jas_iccattrval_t *attrval,
104   jas_iccattrval_t *othattrval);
105 static int jas_icccurv_input(jas_iccattrval_t *attrval, jas_stream_t *in,
106   int cnt);
107 static int jas_icccurv_getsize(jas_iccattrval_t *attrval);
108 static int jas_icccurv_output(jas_iccattrval_t *attrval, jas_stream_t *out);
109 static void jas_icccurv_dump(jas_iccattrval_t *attrval, FILE *out);
110
111 static void jas_icctxtdesc_destroy(jas_iccattrval_t *attrval);
112 static int jas_icctxtdesc_copy(jas_iccattrval_t *attrval,
113   jas_iccattrval_t *othattrval);
114 static int jas_icctxtdesc_input(jas_iccattrval_t *attrval, jas_stream_t *in,
115   int cnt);
116 static int jas_icctxtdesc_getsize(jas_iccattrval_t *attrval);
117 static int jas_icctxtdesc_output(jas_iccattrval_t *attrval, jas_stream_t *out);
118 static void jas_icctxtdesc_dump(jas_iccattrval_t *attrval, FILE *out);
119
120 static void jas_icctxt_destroy(jas_iccattrval_t *attrval);
121 static int jas_icctxt_copy(jas_iccattrval_t *attrval,
122   jas_iccattrval_t *othattrval);
123 static int jas_icctxt_input(jas_iccattrval_t *attrval, jas_stream_t *in,
124   int cnt);
125 static int jas_icctxt_getsize(jas_iccattrval_t *attrval);
126 static int jas_icctxt_output(jas_iccattrval_t *attrval, jas_stream_t *out);
127 static void jas_icctxt_dump(jas_iccattrval_t *attrval, FILE *out);
128
129 static int jas_iccxyz_input(jas_iccattrval_t *attrval, jas_stream_t *in,
130   int cnt);
131 static int jas_iccxyz_getsize(jas_iccattrval_t *attrval);
132 static int jas_iccxyz_output(jas_iccattrval_t *attrval, jas_stream_t *out);
133 static void jas_iccxyz_dump(jas_iccattrval_t *attrval, FILE *out);
134
135 static jas_iccattrtab_t *jas_iccattrtab_create(void);
136 static void jas_iccattrtab_destroy(jas_iccattrtab_t *tab);
137 static int jas_iccattrtab_resize(jas_iccattrtab_t *tab, int maxents);
138 static int jas_iccattrtab_add(jas_iccattrtab_t *attrtab, int i,
139   jas_iccuint32_t name, jas_iccattrval_t *val);
140 static int jas_iccattrtab_replace(jas_iccattrtab_t *attrtab, int i,
141   jas_iccuint32_t name, jas_iccattrval_t *val);
142 static void jas_iccattrtab_delete(jas_iccattrtab_t *attrtab, int i);
143 static long jas_iccpadtomult(long x, long y);
144 static int jas_iccattrtab_get(jas_iccattrtab_t *attrtab, int i,
145   jas_iccattrname_t *name, jas_iccattrval_t **val);
146 static int jas_iccprof_puttagtab(jas_stream_t *out, jas_icctagtab_t *tagtab);
147
148 static void jas_icclut16_destroy(jas_iccattrval_t *attrval);
149 static int jas_icclut16_copy(jas_iccattrval_t *attrval,
150   jas_iccattrval_t *othattrval);
151 static int jas_icclut16_input(jas_iccattrval_t *attrval, jas_stream_t *in,
152   int cnt);
153 static int jas_icclut16_getsize(jas_iccattrval_t *attrval);
154 static int jas_icclut16_output(jas_iccattrval_t *attrval, jas_stream_t *out);
155 static void jas_icclut16_dump(jas_iccattrval_t *attrval, FILE *out);
156
157 static void jas_icclut8_destroy(jas_iccattrval_t *attrval);
158 static int jas_icclut8_copy(jas_iccattrval_t *attrval,
159   jas_iccattrval_t *othattrval);
160 static int jas_icclut8_input(jas_iccattrval_t *attrval, jas_stream_t *in,
161   int cnt);
162 static int jas_icclut8_getsize(jas_iccattrval_t *attrval);
163 static int jas_icclut8_output(jas_iccattrval_t *attrval, jas_stream_t *out);
164 static void jas_icclut8_dump(jas_iccattrval_t *attrval, FILE *out);
165
166 static int jas_iccputtime(jas_stream_t *out, jas_icctime_t *ctime);
167 static int jas_iccputxyz(jas_stream_t *out, jas_iccxyz_t *xyz);
168
169 static long jas_iccpowi(int x, int n);
170
171 static char *jas_iccsigtostr(int sig, char *buf);
172
173
174 jas_iccattrvalinfo_t jas_iccattrvalinfos[] = {
175   {JAS_ICC_TYPE_CURV, {jas_icccurv_destroy, jas_icccurv_copy,
176     jas_icccurv_input, jas_icccurv_output, jas_icccurv_getsize,
177     jas_icccurv_dump}},
178   {JAS_ICC_TYPE_XYZ, {0, 0, jas_iccxyz_input, jas_iccxyz_output,
179     jas_iccxyz_getsize, jas_iccxyz_dump}},
180   {JAS_ICC_TYPE_TXTDESC, {jas_icctxtdesc_destroy,
181     jas_icctxtdesc_copy, jas_icctxtdesc_input, jas_icctxtdesc_output,
182     jas_icctxtdesc_getsize, jas_icctxtdesc_dump}},
183   {JAS_ICC_TYPE_TXT, {jas_icctxt_destroy, jas_icctxt_copy,
184     jas_icctxt_input, jas_icctxt_output, jas_icctxt_getsize,
185     jas_icctxt_dump}},
186   {JAS_ICC_TYPE_LUT8, {jas_icclut8_destroy, jas_icclut8_copy,
187     jas_icclut8_input, jas_icclut8_output, jas_icclut8_getsize,
188     jas_icclut8_dump}},
189   {JAS_ICC_TYPE_LUT16, {jas_icclut16_destroy, jas_icclut16_copy,
190     jas_icclut16_input, jas_icclut16_output, jas_icclut16_getsize,
191     jas_icclut16_dump}},
192   {0, {0, 0, 0, 0, 0, 0}}
193 };
194
195 typedef struct {
196   jas_iccuint32_t tag;
197   char *name;
198 } jas_icctaginfo_t;
199
200 /******************************************************************************\
201 * profile class
202 \******************************************************************************/
203
204 static jas_iccprof_t *jas_iccprof_create()
205 {
206   jas_iccprof_t *prof;
207   prof = 0;
208   if (!(prof = jas_malloc(sizeof(jas_iccprof_t)))) {
209     goto error;
210   }
211   if (!(prof->attrtab = jas_iccattrtab_create()))
212     goto error;
213   memset(&prof->hdr, 0, sizeof(jas_icchdr_t));
214   prof->tagtab.numents = 0;
215   prof->tagtab.ents = 0;
216   return prof;
217 error:
218   if (prof)
219     jas_iccprof_destroy(prof);
220   return 0;
221 }
222
223 jas_iccprof_t *jas_iccprof_copy(jas_iccprof_t *prof)
224 {
225   jas_iccprof_t *newprof;
226   newprof = 0;
227   if (!(newprof = jas_iccprof_create()))
228     goto error;
229   newprof->hdr = prof->hdr;
230   newprof->tagtab.numents = 0;
231   newprof->tagtab.ents = 0;
232   assert(newprof->attrtab);
233   jas_iccattrtab_destroy(newprof->attrtab);
234   if (!(newprof->attrtab = jas_iccattrtab_copy(prof->attrtab)))
235     goto error;
236   return newprof;
237 error:
238   if (newprof)
239     jas_iccprof_destroy(newprof);
240   return 0;
241 }
242
243 void jas_iccprof_destroy(jas_iccprof_t *prof)
244 {
245   if (prof->attrtab)
246     jas_iccattrtab_destroy(prof->attrtab);
247   if (prof->tagtab.ents)
248     jas_free(prof->tagtab.ents);
249   jas_free(prof);
250 }
251
252 void jas_iccprof_dump(jas_iccprof_t *prof, FILE *out)
253 {
254   jas_iccattrtab_dump(prof->attrtab, out);
255 }
256
257 jas_iccprof_t *jas_iccprof_load(jas_stream_t *in)
258 {
259   jas_iccprof_t *prof;
260   int numtags;
261   long curoff;
262   long reloff;
263   long prevoff;
264   jas_iccsig_t type;
265   jas_iccattrval_t *attrval;
266   jas_iccattrval_t *prevattrval;
267   jas_icctagtabent_t *tagtabent;
268   jas_iccattrvalinfo_t *attrvalinfo;
269   int i;
270   int len;
271
272   prof = 0;
273   attrval = 0;
274
275   if (!(prof = jas_iccprof_create())) {
276     goto error;
277   }
278
279   if (jas_iccprof_readhdr(in, &prof->hdr)) {
280     jas_eprintf("cannot get header\n");
281     goto error;
282   }
283   if (jas_iccprof_gettagtab(in, &prof->tagtab)) {
284     jas_eprintf("cannot get tab table\n");
285     goto error;
286   }
287   jas_iccprof_sorttagtab(&prof->tagtab);
288
289   numtags = prof->tagtab.numents;
290   curoff = JAS_ICC_HDRLEN + 4 + 12 * numtags;
291   prevoff = 0;
292   prevattrval = 0;
293   for (i = 0; i < numtags; ++i) {
294     tagtabent = &prof->tagtab.ents[i];
295     if (tagtabent->off == JAS_CAST(jas_iccuint32_t, prevoff)) {
296       if (prevattrval) {
297         if (!(attrval = jas_iccattrval_clone(prevattrval)))
298           goto error;
299         if (jas_iccprof_setattr(prof, tagtabent->tag, attrval))
300           goto error;
301         jas_iccattrval_destroy(attrval);
302       } else {
303 #if 0
304         jas_eprintf("warning: skipping unknown tag type\n");
305 #endif
306       }
307       continue;
308     }
309     reloff = tagtabent->off - curoff;
310     if (reloff > 0) {
311       if (jas_stream_gobble(in, reloff) != reloff)
312         goto error;
313       curoff += reloff;
314     } else if (reloff < 0) {
315       /* This should never happen since we read the tagged
316       element data in a single pass. */
317       abort();
318     }
319     prevoff = curoff;
320     if (jas_iccgetuint32(in, &type)) {
321       goto error;
322     }
323     if (jas_stream_gobble(in, 4) != 4) {
324       goto error;
325     }
326     curoff += 8;
327     if (!(attrvalinfo = jas_iccattrvalinfo_lookup(type))) {
328 #if 0
329       jas_eprintf("warning: skipping unknown tag type\n");
330 #endif
331       (void)attrvalinfo; /*'attrvalinfo' is assigned a value that is never used in function jas_iccprof_load*/
332       prevattrval = 0;
333       continue;
334     }
335     if (!(attrval = jas_iccattrval_create(type))) {
336       goto error;
337     }
338     len = tagtabent->len - 8;
339     if ((*attrval->ops->input)(attrval, in, len)) {
340       goto error;
341     }
342     curoff += len;
343     if (jas_iccprof_setattr(prof, tagtabent->tag, attrval)) {
344       goto error;
345     }
346     prevattrval = attrval; /* This is correct, but slimey. */
347     jas_iccattrval_destroy(attrval);
348     attrval = 0;
349   }
350
351   return prof;
352
353 error:
354   if (prof)
355     jas_iccprof_destroy(prof);
356   if (attrval)
357     jas_iccattrval_destroy(attrval);
358   return 0;
359 }
360
361 int jas_iccprof_save(jas_iccprof_t *prof, jas_stream_t *out)
362 {
363   long curoff;
364   long reloff;
365   long newoff;
366   int i;
367   int j;
368   jas_icctagtabent_t *tagtabent;
369   jas_icctagtabent_t *sharedtagtabent;
370   jas_icctagtabent_t *tmptagtabent;
371   jas_iccuint32_t attrname;
372   jas_iccattrval_t *attrval;
373   jas_icctagtab_t *tagtab;
374
375   tagtab = &prof->tagtab;
376   if (!(tagtab->ents = jas_malloc(prof->attrtab->numattrs *
377     sizeof(jas_icctagtabent_t))))
378     goto error;
379   tagtab->numents = prof->attrtab->numattrs;
380   curoff = JAS_ICC_HDRLEN + 4 + 12 * tagtab->numents;
381   for (i = 0; i < JAS_CAST(int, tagtab->numents); ++i) {
382     tagtabent = &tagtab->ents[i];
383     if (jas_iccattrtab_get(prof->attrtab, i, &attrname, &attrval))
384       goto error;
385     assert(attrval->ops->output);
386     tagtabent->tag = attrname;
387     tagtabent->data = &attrval->data;
388     sharedtagtabent = 0;
389     for (j = 0; j < i; ++j) {
390       tmptagtabent = &tagtab->ents[j];
391       if (tagtabent->data == tmptagtabent->data) {
392         sharedtagtabent = tmptagtabent;
393         break;
394       }
395     }
396     if (sharedtagtabent) {
397       tagtabent->off = sharedtagtabent->off;
398       tagtabent->len = sharedtagtabent->len;
399       tagtabent->first = sharedtagtabent;
400     } else {
401       tagtabent->off = curoff;
402       tagtabent->len = (*attrval->ops->getsize)(attrval) + 8;
403       tagtabent->first = 0;
404       if (i < JAS_CAST(int, tagtab->numents - 1)) {
405         curoff = jas_iccpadtomult(curoff + tagtabent->len, 4);
406       } else {
407         curoff += tagtabent->len;
408       }
409     }
410     jas_iccattrval_destroy(attrval);
411   }
412   prof->hdr.size = curoff;
413   if (jas_iccprof_writehdr(out, &prof->hdr))
414     goto error;
415   if (jas_iccprof_puttagtab(out, &prof->tagtab))
416     goto error;
417   curoff = JAS_ICC_HDRLEN + 4 + 12 * tagtab->numents;
418   for (i = 0; i < JAS_CAST(int, tagtab->numents);) {
419     tagtabent = &tagtab->ents[i];
420     assert(curoff == JAS_CAST(long, tagtabent->off));
421     if (jas_iccattrtab_get(prof->attrtab, i, &attrname, &attrval))
422       goto error;
423     if (jas_iccputuint32(out, attrval->type) || jas_stream_pad(out,
424       4, 0) != 4)
425       goto error;
426     if ((*attrval->ops->output)(attrval, out))
427       goto error;
428     jas_iccattrval_destroy(attrval);
429     curoff += tagtabent->len;
430     ++i;
431     while (i < JAS_CAST(int, tagtab->numents) &&
432       tagtab->ents[i].first)
433       ++i;
434     newoff = (i < JAS_CAST(int, tagtab->numents)) ?
435       tagtab->ents[i].off : prof->hdr.size;
436     reloff = newoff - curoff;
437     assert(reloff >= 0);
438     if (reloff > 0) {
439       if (jas_stream_pad(out, reloff, 0) != reloff)
440         goto error;
441       curoff += reloff;
442     }
443   }  
444   return 0;
445 error:
446   /* XXX - need to free some resources here */
447   return -1;
448 }
449
450 static int jas_iccprof_writehdr(jas_stream_t *out, jas_icchdr_t *hdr)
451 {
452   if (jas_iccputuint32(out, hdr->size) ||
453     jas_iccputuint32(out, hdr->cmmtype) ||
454     jas_iccputuint32(out, hdr->version) ||
455     jas_iccputuint32(out, hdr->clas) ||
456     jas_iccputuint32(out, hdr->colorspc) ||
457     jas_iccputuint32(out, hdr->refcolorspc) ||
458     jas_iccputtime(out, &hdr->ctime) ||
459     jas_iccputuint32(out, hdr->magic) ||
460     jas_iccputuint32(out, hdr->platform) ||
461     jas_iccputuint32(out, hdr->flags) ||
462     jas_iccputuint32(out, hdr->maker) ||
463     jas_iccputuint32(out, hdr->model) ||
464     jas_iccputuint64(out, hdr->attr) ||
465     jas_iccputuint32(out, hdr->intent) ||
466     jas_iccputxyz(out, &hdr->illum) ||
467     jas_iccputuint32(out, hdr->creator) ||
468     jas_stream_pad(out, 44, 0) != 44)
469     return -1;
470   return 0;
471 }
472
473 static int jas_iccprof_puttagtab(jas_stream_t *out, jas_icctagtab_t *tagtab)
474 {
475   int i;
476   jas_icctagtabent_t *tagtabent;
477   if (jas_iccputuint32(out, tagtab->numents))
478     goto error;
479   for (i = 0; i < JAS_CAST(int, tagtab->numents); ++i) {
480     tagtabent = &tagtab->ents[i];
481     if (jas_iccputuint32(out, tagtabent->tag) ||
482       jas_iccputuint32(out, tagtabent->off) ||
483       jas_iccputuint32(out, tagtabent->len))
484       goto error;
485   }
486   return 0;
487 error:
488   return -1;
489 }
490
491 static int jas_iccprof_readhdr(jas_stream_t *in, jas_icchdr_t *hdr)
492 {
493   if (jas_iccgetuint32(in, &hdr->size) ||
494     jas_iccgetuint32(in, &hdr->cmmtype) ||
495     jas_iccgetuint32(in, &hdr->version) ||
496     jas_iccgetuint32(in, &hdr->clas) ||
497     jas_iccgetuint32(in, &hdr->colorspc) ||
498     jas_iccgetuint32(in, &hdr->refcolorspc) ||
499     jas_iccgettime(in, &hdr->ctime) ||
500     jas_iccgetuint32(in, &hdr->magic) ||
501     jas_iccgetuint32(in, &hdr->platform) ||
502     jas_iccgetuint32(in, &hdr->flags) ||
503     jas_iccgetuint32(in, &hdr->maker) ||
504     jas_iccgetuint32(in, &hdr->model) ||
505     jas_iccgetuint64(in, &hdr->attr) ||
506     jas_iccgetuint32(in, &hdr->intent) ||
507     jas_iccgetxyz(in, &hdr->illum) ||
508     jas_iccgetuint32(in, &hdr->creator) ||
509     jas_stream_gobble(in, 44) != 44)
510     return -1;
511   return 0;
512 }
513
514 static int jas_iccprof_gettagtab(jas_stream_t *in, jas_icctagtab_t *tagtab)
515 {
516   int i;
517   jas_icctagtabent_t *tagtabent;
518
519   if (tagtab->ents) {
520     jas_free(tagtab->ents);
521     tagtab->ents = 0;
522   }
523   if (jas_iccgetuint32(in, &tagtab->numents))
524     goto error;
525   if (!(tagtab->ents = jas_malloc(tagtab->numents *
526     sizeof(jas_icctagtabent_t))))
527     goto error;
528   tagtabent = tagtab->ents;
529   for (i = 0; i < JAS_CAST(long, tagtab->numents); ++i) {
530     if (jas_iccgetuint32(in, &tagtabent->tag) ||
531     jas_iccgetuint32(in, &tagtabent->off) ||
532     jas_iccgetuint32(in, &tagtabent->len))
533       goto error;
534     ++tagtabent;
535   }
536   return 0;
537 error:
538   if (tagtab->ents) {
539     jas_free(tagtab->ents);
540     tagtab->ents = 0;
541   }
542   return -1;
543 }
544
545 jas_iccattrval_t *jas_iccprof_getattr(jas_iccprof_t *prof,
546   jas_iccattrname_t name)
547 {
548   int i;
549   jas_iccattrval_t *attrval;
550   if ((i = jas_iccattrtab_lookup(prof->attrtab, name)) < 0)
551     goto error;
552   if (!(attrval = jas_iccattrval_clone(prof->attrtab->attrs[i].val)))
553     goto error;
554   return attrval;
555 error:
556   return 0;
557 }
558
559 int jas_iccprof_setattr(jas_iccprof_t *prof, jas_iccattrname_t name,
560   jas_iccattrval_t *val)
561 {
562   int i;
563   if ((i = jas_iccattrtab_lookup(prof->attrtab, name)) >= 0) {
564     if (val) {
565       if (jas_iccattrtab_replace(prof->attrtab, i, name, val))
566         goto error;
567     } else {
568       jas_iccattrtab_delete(prof->attrtab, i);
569     }
570   } else {
571     if (val) {
572       if (jas_iccattrtab_add(prof->attrtab, -1, name, val))
573         goto error;
574     } else {
575       /* NOP */
576     }
577   }
578   return 0;
579 error:
580   return -1;
581 }
582
583 int jas_iccprof_gethdr(jas_iccprof_t *prof, jas_icchdr_t *hdr)
584 {
585   *hdr = prof->hdr;
586   return 0;
587 }
588
589 int jas_iccprof_sethdr(jas_iccprof_t *prof, jas_icchdr_t *hdr)
590 {
591   prof->hdr = *hdr;
592   return 0;
593 }
594
595 static void jas_iccprof_sorttagtab(jas_icctagtab_t *tagtab)
596 {
597   qsort(tagtab->ents, tagtab->numents, sizeof(jas_icctagtabent_t),
598     jas_icctagtabent_cmp);
599 }
600
601 static int jas_icctagtabent_cmp(const void *src, const void *dst)
602 {
603   jas_icctagtabent_t *srctagtabent = JAS_CAST(jas_icctagtabent_t *, src);
604   jas_icctagtabent_t *dsttagtabent = JAS_CAST(jas_icctagtabent_t *, dst);
605   if (srctagtabent->off > dsttagtabent->off) {
606     return 1;
607   } else if (srctagtabent->off < dsttagtabent->off) {
608     return -1;
609   }
610   return 0;
611 }
612
613 static jas_iccattrvalinfo_t *jas_iccattrvalinfo_lookup(jas_iccsig_t type)
614 {
615   jas_iccattrvalinfo_t *info;
616   info = jas_iccattrvalinfos;
617   for (info = jas_iccattrvalinfos; info->type; ++info) {
618     if (info->type == type) {
619       return info;
620     }
621   }
622   return 0;
623 }
624
625 static int jas_iccgettime(jas_stream_t *in, jas_icctime_t *time)
626 {
627   if (jas_iccgetuint16(in, &time->year) ||
628     jas_iccgetuint16(in, &time->month) ||
629     jas_iccgetuint16(in, &time->day) ||
630     jas_iccgetuint16(in, &time->hour) ||
631     jas_iccgetuint16(in, &time->min) ||
632     jas_iccgetuint16(in, &time->sec)) {
633     return -1;
634   }
635   return 0;
636 }
637
638 static int jas_iccgetxyz(jas_stream_t *in, jas_iccxyz_t *xyz)
639 {
640   if (jas_iccgetsint32(in, &xyz->x) ||
641     jas_iccgetsint32(in, &xyz->y) ||
642     jas_iccgetsint32(in, &xyz->z)) {
643     return -1;
644   }
645   return 0;
646 }
647
648 static int jas_iccputtime(jas_stream_t *out, jas_icctime_t *time)
649 {
650   jas_iccputuint16(out, time->year);
651   jas_iccputuint16(out, time->month);
652   jas_iccputuint16(out, time->day);
653   jas_iccputuint16(out, time->hour);
654   jas_iccputuint16(out, time->min);
655   jas_iccputuint16(out, time->sec);
656   return 0;
657 }
658
659 static int jas_iccputxyz(jas_stream_t *out, jas_iccxyz_t *xyz)
660 {
661   jas_iccputuint32(out, xyz->x);
662   jas_iccputuint32(out, xyz->y);
663   jas_iccputuint32(out, xyz->z);
664   return 0;
665 }
666
667 /******************************************************************************\
668 * attribute table class
669 \******************************************************************************/
670
671 static jas_iccattrtab_t *jas_iccattrtab_create()
672 {
673   jas_iccattrtab_t *tab;
674   tab = 0;
675   if (!(tab = jas_malloc(sizeof(jas_iccattrtab_t))))
676     goto error;
677   tab->maxattrs = 0;
678   tab->numattrs = 0;
679   tab->attrs = 0;
680   if (jas_iccattrtab_resize(tab, 32))
681     goto error;
682   return tab;
683 error:
684   if (tab)
685     jas_iccattrtab_destroy(tab);
686   return 0;
687 }
688
689 static jas_iccattrtab_t *jas_iccattrtab_copy(jas_iccattrtab_t *attrtab)
690 {
691   jas_iccattrtab_t *newattrtab;
692   int i;
693   if (!(newattrtab = jas_iccattrtab_create()))
694     goto error;
695   for (i = 0; i < attrtab->numattrs; ++i) {
696     if (jas_iccattrtab_add(newattrtab, i, attrtab->attrs[i].name,
697       attrtab->attrs[i].val))
698       goto error;
699   }
700   return newattrtab;
701 error:
702   return 0;
703 }
704
705 static void jas_iccattrtab_destroy(jas_iccattrtab_t *tab)
706 {
707   if (tab->attrs) {
708     while (tab->numattrs > 0) {
709       jas_iccattrtab_delete(tab, 0);
710     }
711     jas_free(tab->attrs);
712   }
713   jas_free(tab);
714 }
715
716 void jas_iccattrtab_dump(jas_iccattrtab_t *attrtab, FILE *out)
717 {
718   int i;
719   jas_iccattr_t *attr;
720   jas_iccattrval_t *attrval;
721   jas_iccattrvalinfo_t *info;
722   char buf[16];
723   fprintf(out, "numattrs=%d\n", attrtab->numattrs);
724   fprintf(out, "---\n");
725   for (i = 0; i < attrtab->numattrs; ++i) {
726     attr = &attrtab->attrs[i];
727     attrval = attr->val;
728     info = jas_iccattrvalinfo_lookup(attrval->type);
729     if (!info) abort();
730     fprintf(out, "attrno=%d; attrname=\"%s\"(0x%08x); attrtype=\"%s\"(0x%08x)\n",
731       i,
732       jas_iccsigtostr(attr->name, &buf[0]),
733       attr->name,
734       jas_iccsigtostr(attrval->type, &buf[8]),
735       attrval->type
736       );
737     jas_iccattrval_dump(attrval, out);
738     fprintf(out, "---\n");
739   }
740 }
741
742 static int jas_iccattrtab_resize(jas_iccattrtab_t *tab, int maxents)
743 {
744   jas_iccattr_t *newattrs;
745   assert(maxents >= tab->numattrs);
746   newattrs = tab->attrs ? jas_realloc(tab->attrs, maxents *
747     sizeof(jas_iccattr_t)) : jas_malloc(maxents * sizeof(jas_iccattr_t));
748   if (!newattrs)
749     return -1;
750   tab->attrs = newattrs;
751   tab->maxattrs = maxents;
752   return 0;
753 }
754
755 static int jas_iccattrtab_add(jas_iccattrtab_t *attrtab, int i,
756   jas_iccuint32_t name, jas_iccattrval_t *val)
757 {
758   int n;
759   jas_iccattr_t *attr;
760   jas_iccattrval_t *tmpattrval;
761   tmpattrval = 0;
762   if (i < 0) {
763     i = attrtab->numattrs;
764   }
765   assert(i >= 0 && i <= attrtab->numattrs);
766   if (attrtab->numattrs >= attrtab->maxattrs) {
767     if (jas_iccattrtab_resize(attrtab, attrtab->numattrs + 32)) {
768       goto error;
769     }
770   }
771   if (!(tmpattrval = jas_iccattrval_clone(val)))
772     goto error;
773   n = attrtab->numattrs - i;
774   if (n > 0)
775     memmove(&attrtab->attrs[i + 1], &attrtab->attrs[i],
776       n * sizeof(jas_iccattr_t));
777   attr = &attrtab->attrs[i];
778   attr->name = name;
779   attr->val = tmpattrval;
780   ++attrtab->numattrs;
781   return 0;
782 error:
783   if (tmpattrval)
784     jas_iccattrval_destroy(tmpattrval);
785   return -1;
786 }
787
788 static int jas_iccattrtab_replace(jas_iccattrtab_t *attrtab, int i,
789   jas_iccuint32_t name, jas_iccattrval_t *val)
790 {
791   jas_iccattrval_t *newval;
792   jas_iccattr_t *attr;
793   if (!(newval = jas_iccattrval_clone(val)))
794     goto error;
795   attr = &attrtab->attrs[i];
796   jas_iccattrval_destroy(attr->val);
797   attr->name = name;
798   attr->val = newval;
799   return 0;
800 error:
801   return -1;
802 }
803
804 static void jas_iccattrtab_delete(jas_iccattrtab_t *attrtab, int i)
805 {
806   int n;
807   jas_iccattrval_destroy(attrtab->attrs[i].val);
808   if ((n = attrtab->numattrs - i - 1) > 0)
809     memmove(&attrtab->attrs[i], &attrtab->attrs[i + 1],
810       n * sizeof(jas_iccattr_t));
811   --attrtab->numattrs;
812 }
813
814 static int jas_iccattrtab_get(jas_iccattrtab_t *attrtab, int i,
815   jas_iccattrname_t *name, jas_iccattrval_t **val)
816 {
817   jas_iccattr_t *attr;
818   if (i < 0 || i >= attrtab->numattrs)
819     goto error;
820   attr = &attrtab->attrs[i];
821   *name = attr->name;
822   if (!(*val = jas_iccattrval_clone(attr->val)))
823     goto error;
824   return 0;
825 error:
826   return -1;
827 }
828
829 static int jas_iccattrtab_lookup(jas_iccattrtab_t *attrtab,
830   jas_iccuint32_t name)
831 {
832   int i;
833   jas_iccattr_t *attr;
834   for (i = 0; i < attrtab->numattrs; ++i) {
835     attr = &attrtab->attrs[i];
836     if (attr->name == name)
837       return i;
838   }
839   return -1;
840 }
841
842 /******************************************************************************\
843 * attribute value class
844 \******************************************************************************/
845
846 jas_iccattrval_t *jas_iccattrval_create(jas_iccuint32_t type)
847 {
848   jas_iccattrval_t *attrval;
849   jas_iccattrvalinfo_t *info;
850
851   if (!(info = jas_iccattrvalinfo_lookup(type)))
852     goto error;
853   if (!(attrval = jas_iccattrval_create0()))
854     goto error;
855   attrval->ops = &info->ops;
856   attrval->type = type;
857   ++attrval->refcnt;
858   memset(&attrval->data, 0, sizeof(attrval->data));
859   return attrval;
860 error:
861   return 0;
862 }
863
864 jas_iccattrval_t *jas_iccattrval_clone(jas_iccattrval_t *attrval)
865 {
866   ++attrval->refcnt;
867   return attrval;
868 }
869
870 void jas_iccattrval_destroy(jas_iccattrval_t *attrval)
871 {
872 #if 0
873 fprintf(stderr, "refcnt=%d\n", attrval->refcnt);
874 #endif
875   if (--attrval->refcnt <= 0) {
876     if (attrval->ops->destroy)
877       (*attrval->ops->destroy)(attrval);
878     jas_free(attrval);
879   }
880 }
881
882 void jas_iccattrval_dump(jas_iccattrval_t *attrval, FILE *out)
883 {
884   char buf[8];
885   jas_iccsigtostr(attrval->type, buf);
886   fprintf(out, "refcnt = %d; type = 0x%08x %s\n", attrval->refcnt,
887     attrval->type, jas_iccsigtostr(attrval->type, &buf[0]));
888   if (attrval->ops->dump) {
889     (*attrval->ops->dump)(attrval, out);
890   }
891 }
892
893 int jas_iccattrval_allowmodify(jas_iccattrval_t **attrvalx)
894 {
895   jas_iccattrval_t *newattrval;
896   jas_iccattrval_t *attrval = *attrvalx;
897   newattrval = 0;
898   if (attrval->refcnt > 1) {
899     if (!(newattrval = jas_iccattrval_create0()))
900       goto error;
901     newattrval->ops = attrval->ops;
902     newattrval->type = attrval->type;
903     ++newattrval->refcnt;
904     if (newattrval->ops->copy) {
905       if ((*newattrval->ops->copy)(newattrval, attrval))
906         goto error;
907     } else {
908       memcpy(&newattrval->data, &attrval->data,
909         sizeof(newattrval->data));
910     }
911     *attrvalx = newattrval;
912   }
913   return 0;
914 error:
915   if (newattrval) {
916     jas_free(newattrval);
917   }
918   return -1;
919 }
920
921 static jas_iccattrval_t *jas_iccattrval_create0()
922 {
923   jas_iccattrval_t *attrval;
924   if (!(attrval = jas_malloc(sizeof(jas_iccattrval_t))))
925     return 0;
926   memset(attrval, 0, sizeof(jas_iccattrval_t));
927   attrval->refcnt = 0;
928   attrval->ops = 0;
929   attrval->type = 0;
930   return attrval;
931 }
932
933 /******************************************************************************\
934 *
935 \******************************************************************************/
936
937 static int jas_iccxyz_input(jas_iccattrval_t *attrval, jas_stream_t *in,
938   int len)
939 {
940   if (len != 4 * 3) abort();
941   return jas_iccgetxyz(in, &attrval->data.xyz);
942 }
943
944 static int jas_iccxyz_output(jas_iccattrval_t *attrval, jas_stream_t *out)
945 {
946   jas_iccxyz_t *xyz = &attrval->data.xyz;
947   if (jas_iccputuint32(out, xyz->x) ||
948     jas_iccputuint32(out, xyz->y) ||
949     jas_iccputuint32(out, xyz->z))
950     return -1;
951   return 0;
952 }
953
954 static int jas_iccxyz_getsize(jas_iccattrval_t *attrval)
955 {
956   /* Avoid compiler warnings about unused parameters. */
957   attrval = 0;
958
959   return 12;
960 }
961
962 static void jas_iccxyz_dump(jas_iccattrval_t *attrval, FILE *out)
963 {
964   jas_iccxyz_t *xyz = &attrval->data.xyz;
965   fprintf(out, "(%f, %f, %f)\n", xyz->x / 65536.0, xyz->y / 65536.0, xyz->z / 65536.0);
966 }
967
968 /******************************************************************************\
969 * attribute table class
970 \******************************************************************************/
971
972 static void jas_icccurv_destroy(jas_iccattrval_t *attrval)
973 {
974   jas_icccurv_t *curv = &attrval->data.curv;
975   if (curv->ents)
976     jas_free(curv->ents);
977 }
978
979 static int jas_icccurv_copy(jas_iccattrval_t *attrval,
980   jas_iccattrval_t *othattrval)
981 {
982   /* Avoid compiler warnings about unused parameters. */
983   attrval = 0;
984   othattrval = 0;
985
986   /* Not yet implemented. */
987   abort();
988   return -1;
989 }
990
991 static int jas_icccurv_input(jas_iccattrval_t *attrval, jas_stream_t *in,
992   int cnt)
993 {
994   jas_icccurv_t *curv = &attrval->data.curv;
995   unsigned int i;
996
997   curv->numents = 0;
998   curv->ents = 0;
999
1000   if (jas_iccgetuint32(in, &curv->numents))
1001     goto error;
1002   if (!(curv->ents = jas_malloc(curv->numents * sizeof(jas_iccuint16_t))))
1003     goto error;
1004   for (i = 0; i < curv->numents; ++i) {
1005     if (jas_iccgetuint16(in, &curv->ents[i]))
1006       goto error;
1007   }
1008
1009   if (JAS_CAST(int, 4 + 2 * curv->numents) != cnt)
1010     goto error;
1011   return 0;
1012
1013 error:
1014   jas_icccurv_destroy(attrval);
1015   return -1;
1016 }
1017
1018 static int jas_icccurv_getsize(jas_iccattrval_t *attrval)
1019 {
1020   jas_icccurv_t *curv = &attrval->data.curv;
1021   return 4 + 2 * curv->numents;
1022 }
1023
1024 static int jas_icccurv_output(jas_iccattrval_t *attrval, jas_stream_t *out)
1025 {
1026   jas_icccurv_t *curv = &attrval->data.curv;
1027   unsigned int i;
1028
1029   if (jas_iccputuint32(out, curv->numents))
1030     goto error;
1031   for (i = 0; i < curv->numents; ++i) {
1032     if (jas_iccputuint16(out, curv->ents[i]))
1033       goto error;
1034   }
1035   return 0;
1036 error:
1037   return -1;
1038 }
1039
1040 static void jas_icccurv_dump(jas_iccattrval_t *attrval, FILE *out)
1041 {
1042   int i;
1043   jas_icccurv_t *curv = &attrval->data.curv;
1044   fprintf(out, "number of entires = %d\n", curv->numents);
1045   if (curv->numents == 1) {
1046     fprintf(out, "gamma = %f\n", curv->ents[0] / 256.0);
1047   } else {
1048     for (i = 0; i < JAS_CAST(int, curv->numents); ++i) {
1049       if (i < 3 || i >= JAS_CAST(int, curv->numents) - 3) {
1050         fprintf(out, "entry[%d] = %f\n", i, curv->ents[i] / 65535.0);
1051       }
1052     }
1053   }
1054 }
1055
1056 /******************************************************************************\
1057 *
1058 \******************************************************************************/
1059
1060 static void jas_icctxtdesc_destroy(jas_iccattrval_t *attrval)
1061 {
1062   jas_icctxtdesc_t *txtdesc = &attrval->data.txtdesc;
1063   if (txtdesc->ascdata)
1064     jas_free(txtdesc->ascdata);
1065   if (txtdesc->ucdata)
1066     jas_free(txtdesc->ucdata);
1067 }
1068
1069 static int jas_icctxtdesc_copy(jas_iccattrval_t *attrval,
1070   jas_iccattrval_t *othattrval)
1071 {
1072   jas_icctxtdesc_t *txtdesc = &attrval->data.txtdesc;
1073
1074   /* Avoid compiler warnings about unused parameters. */
1075   attrval = 0;
1076   othattrval = 0;
1077   txtdesc = 0;
1078   (void)txtdesc;
1079
1080   /* Not yet implemented. */
1081   abort();
1082   return -1;
1083 }
1084
1085 static int jas_icctxtdesc_input(jas_iccattrval_t *attrval, jas_stream_t *in,
1086   int cnt)
1087 {
1088   int n;
1089   int c;
1090   jas_icctxtdesc_t *txtdesc = &attrval->data.txtdesc;
1091   txtdesc->ascdata = 0;
1092   txtdesc->ucdata = 0;
1093   if (jas_iccgetuint32(in, &txtdesc->asclen))
1094     goto error;
1095   if (!(txtdesc->ascdata = jas_malloc(txtdesc->asclen)))
1096     goto error;
1097   if (jas_stream_read(in, txtdesc->ascdata, txtdesc->asclen) !=
1098     JAS_CAST(int, txtdesc->asclen))
1099     goto error;
1100   txtdesc->ascdata[txtdesc->asclen - 1] = '\0';
1101   if (jas_iccgetuint32(in, &txtdesc->uclangcode) ||
1102     jas_iccgetuint32(in, &txtdesc->uclen))
1103     goto error;
1104   if (!(txtdesc->ucdata = jas_malloc(txtdesc->uclen * 2)))
1105     goto error;
1106   if (jas_stream_read(in, txtdesc->ucdata, txtdesc->uclen * 2) !=
1107     JAS_CAST(int, txtdesc->uclen * 2))
1108     goto error;
1109   if (jas_iccgetuint16(in, &txtdesc->sccode))
1110     goto error;
1111   if ((c = jas_stream_getc(in)) == EOF)
1112     goto error;
1113   txtdesc->maclen = c;
1114   if (jas_stream_read(in, txtdesc->macdata, 67) != 67)
1115     goto error;
1116   txtdesc->asclen = strlen(txtdesc->ascdata) + 1;
1117 #define WORKAROUND_BAD_PROFILES
1118 #ifdef WORKAROUND_BAD_PROFILES
1119   n = txtdesc->asclen + txtdesc->uclen * 2 + 15 + 67;
1120   if (n > cnt) {
1121     return -1;
1122   }
1123   if (n < cnt) {
1124     if (jas_stream_gobble(in, cnt - n) != cnt - n)
1125       goto error;
1126   }
1127 #else
1128   if (txtdesc->asclen + txtdesc->uclen * 2 + 15 + 67 != cnt)
1129     return -1;
1130 #endif
1131   return 0;
1132 error:
1133   jas_icctxtdesc_destroy(attrval);
1134   return -1;
1135 }
1136
1137 static int jas_icctxtdesc_getsize(jas_iccattrval_t *attrval)
1138 {
1139   jas_icctxtdesc_t *txtdesc = &attrval->data.txtdesc;
1140   return strlen(txtdesc->ascdata) + 1 + txtdesc->uclen * 2 + 15 + 67;
1141 }
1142
1143 static int jas_icctxtdesc_output(jas_iccattrval_t *attrval, jas_stream_t *out)
1144 {
1145   jas_icctxtdesc_t *txtdesc = &attrval->data.txtdesc;
1146   if (jas_iccputuint32(out, txtdesc->asclen) ||
1147     jas_stream_puts(out, txtdesc->ascdata) ||
1148     jas_stream_putc(out, 0) == EOF ||
1149     jas_iccputuint32(out, txtdesc->uclangcode) ||
1150     jas_iccputuint32(out, txtdesc->uclen) ||
1151     jas_stream_write(out, txtdesc->ucdata, txtdesc->uclen * 2) != JAS_CAST(int, txtdesc->uclen * 2) ||
1152     jas_iccputuint16(out, txtdesc->sccode) ||
1153     jas_stream_putc(out, txtdesc->maclen) == EOF)
1154     goto error;
1155   if (txtdesc->maclen > 0) {
1156     if (jas_stream_write(out, txtdesc->macdata, 67) != 67)
1157       goto error;
1158   } else {
1159     if (jas_stream_pad(out, 67, 0) != 67)
1160       goto error;
1161   }
1162   return 0;
1163 error:
1164   return -1;
1165 }
1166
1167 static void jas_icctxtdesc_dump(jas_iccattrval_t *attrval, FILE *out)
1168 {
1169   jas_icctxtdesc_t *txtdesc = &attrval->data.txtdesc;
1170   fprintf(out, "ascii = \"%s\"\n", txtdesc->ascdata);
1171   fprintf(out, "uclangcode = %d; uclen = %d\n", txtdesc->uclangcode,
1172     txtdesc->uclen);
1173   fprintf(out, "sccode = %d\n", txtdesc->sccode);
1174   fprintf(out, "maclen = %d\n", txtdesc->maclen);
1175 }
1176
1177 /******************************************************************************\
1178 *
1179 \******************************************************************************/
1180
1181 static void jas_icctxt_destroy(jas_iccattrval_t *attrval)
1182 {
1183   jas_icctxt_t *txt = &attrval->data.txt;
1184   if (txt->string)
1185     jas_free(txt->string);
1186 }
1187
1188 static int jas_icctxt_copy(jas_iccattrval_t *attrval,
1189   jas_iccattrval_t *othattrval)
1190 {
1191   jas_icctxt_t *txt = &attrval->data.txt;
1192   jas_icctxt_t *othtxt = &othattrval->data.txt;
1193   if (!(txt->string = strdup(othtxt->string)))
1194     return -1;
1195   return 0;
1196 }
1197
1198 static int jas_icctxt_input(jas_iccattrval_t *attrval, jas_stream_t *in,
1199   int cnt)
1200 {
1201   jas_icctxt_t *txt = &attrval->data.txt;
1202   txt->string = 0;
1203   if (!(txt->string = jas_malloc(cnt)))
1204     goto error;
1205   if (jas_stream_read(in, txt->string, cnt) != cnt)
1206     goto error;
1207   txt->string[cnt - 1] = '\0';
1208   if (JAS_CAST(int, strlen(txt->string)) + 1 != cnt)
1209     goto error;
1210   return 0;
1211 error:
1212   if (txt->string)
1213     jas_free(txt->string);
1214   return -1;
1215 }
1216
1217 static int jas_icctxt_getsize(jas_iccattrval_t *attrval)
1218 {
1219   jas_icctxt_t *txt = &attrval->data.txt;
1220   return strlen(txt->string) + 1;
1221 }
1222
1223 static int jas_icctxt_output(jas_iccattrval_t *attrval, jas_stream_t *out)
1224 {
1225   jas_icctxt_t *txt = &attrval->data.txt;
1226   if (jas_stream_puts(out, txt->string) ||
1227     jas_stream_putc(out, 0) == EOF)
1228     return -1;
1229   return 0;
1230 }
1231
1232 static void jas_icctxt_dump(jas_iccattrval_t *attrval, FILE *out)
1233 {
1234   jas_icctxt_t *txt = &attrval->data.txt;
1235   fprintf(out, "string = \"%s\"\n", txt->string);
1236 }
1237
1238 /******************************************************************************\
1239 *
1240 \******************************************************************************/
1241
1242 static void jas_icclut8_destroy(jas_iccattrval_t *attrval)
1243 {
1244   jas_icclut8_t *lut8 = &attrval->data.lut8;
1245   if (lut8->clut)
1246     jas_free(lut8->clut);
1247   if (lut8->intabs)
1248     jas_free(lut8->intabs);
1249   if (lut8->intabsbuf)
1250     jas_free(lut8->intabsbuf);
1251   if (lut8->outtabs)
1252     jas_free(lut8->outtabs);
1253   if (lut8->outtabsbuf)
1254     jas_free(lut8->outtabsbuf);
1255 }
1256
1257 static int jas_icclut8_copy(jas_iccattrval_t *attrval,
1258   jas_iccattrval_t *othattrval)
1259 {
1260   jas_icclut8_t *lut8 = &attrval->data.lut8;
1261   /* Avoid compiler warnings about unused parameters. */
1262   attrval = 0;
1263   othattrval = 0;
1264   lut8 = 0;
1265   (void)lut8;
1266   abort();
1267   return -1;
1268 }
1269
1270 static int jas_icclut8_input(jas_iccattrval_t *attrval, jas_stream_t *in,
1271   int cnt)
1272 {
1273   int i;
1274   int j;
1275   int clutsize;
1276   jas_icclut8_t *lut8 = &attrval->data.lut8;
1277   lut8->clut = 0;
1278   lut8->intabs = 0;
1279   lut8->intabsbuf = 0;
1280   lut8->outtabs = 0;
1281   lut8->outtabsbuf = 0;
1282   if (jas_iccgetuint8(in, &lut8->numinchans) ||
1283     jas_iccgetuint8(in, &lut8->numoutchans) ||
1284     jas_iccgetuint8(in, &lut8->clutlen) ||
1285     jas_stream_getc(in) == EOF)
1286     goto error;
1287   for (i = 0; i < 3; ++i) {
1288     for (j = 0; j < 3; ++j) {
1289       if (jas_iccgetsint32(in, &lut8->e[i][j]))
1290         goto error;
1291     }
1292   }
1293   if (jas_iccgetuint16(in, &lut8->numintabents) ||
1294     jas_iccgetuint16(in, &lut8->numouttabents))
1295     goto error;
1296   clutsize = jas_iccpowi(lut8->clutlen, lut8->numinchans) * lut8->numoutchans;
1297   if (!(lut8->clut = jas_malloc(clutsize * sizeof(jas_iccuint8_t))) ||
1298     !(lut8->intabsbuf = jas_malloc(lut8->numinchans *
1299     lut8->numintabents * sizeof(jas_iccuint8_t))) ||
1300     !(lut8->intabs = jas_malloc(lut8->numinchans *
1301     sizeof(jas_iccuint8_t *))))
1302     goto error;
1303   for (i = 0; i < lut8->numinchans; ++i)
1304     lut8->intabs[i] = &lut8->intabsbuf[i * lut8->numintabents];
1305   if (!(lut8->outtabsbuf = jas_malloc(lut8->numoutchans *
1306     lut8->numouttabents * sizeof(jas_iccuint8_t))) ||
1307     !(lut8->outtabs = jas_malloc(lut8->numoutchans *
1308     sizeof(jas_iccuint8_t *))))
1309     goto error;
1310   for (i = 0; i < lut8->numoutchans; ++i)
1311     lut8->outtabs[i] = &lut8->outtabsbuf[i * lut8->numouttabents];
1312   for (i = 0; i < lut8->numinchans; ++i) {
1313     for (j = 0; j < JAS_CAST(int, lut8->numintabents); ++j) {
1314       if (jas_iccgetuint8(in, &lut8->intabs[i][j]))
1315         goto error;
1316     }
1317   }
1318   for (i = 0; i < lut8->numoutchans; ++i) {
1319     for (j = 0; j < JAS_CAST(int, lut8->numouttabents); ++j) {
1320       if (jas_iccgetuint8(in, &lut8->outtabs[i][j]))
1321         goto error;
1322     }
1323   }
1324   for (i = 0; i < clutsize; ++i) {
1325     if (jas_iccgetuint8(in, &lut8->clut[i]))
1326       goto error;
1327   }
1328   if (JAS_CAST(int, 44 + lut8->numinchans * lut8->numintabents +
1329     lut8->numoutchans * lut8->numouttabents +
1330     jas_iccpowi(lut8->clutlen, lut8->numinchans) * lut8->numoutchans) !=
1331     cnt)
1332     goto error;
1333   return 0;
1334 error:
1335   jas_icclut8_destroy(attrval);
1336   return -1;
1337 }
1338
1339 static int jas_icclut8_getsize(jas_iccattrval_t *attrval)
1340 {
1341   jas_icclut8_t *lut8 = &attrval->data.lut8;
1342   return 44 + lut8->numinchans * lut8->numintabents +
1343     lut8->numoutchans * lut8->numouttabents +
1344     jas_iccpowi(lut8->clutlen, lut8->numinchans) * lut8->numoutchans;
1345 }
1346
1347 static int jas_icclut8_output(jas_iccattrval_t *attrval, jas_stream_t *out)
1348 {
1349   jas_icclut8_t *lut8 = &attrval->data.lut8;
1350   int i;
1351   int j;
1352   int n;
1353   lut8->clut = 0;
1354   lut8->intabs = 0;
1355   lut8->intabsbuf = 0;
1356   lut8->outtabs = 0;
1357   lut8->outtabsbuf = 0;
1358   if (jas_stream_putc(out, lut8->numinchans) == EOF ||
1359     jas_stream_putc(out, lut8->numoutchans) == EOF ||
1360     jas_stream_putc(out, lut8->clutlen) == EOF ||
1361     jas_stream_putc(out, 0) == EOF)
1362     goto error;
1363   for (i = 0; i < 3; ++i) {
1364     for (j = 0; j < 3; ++j) {
1365       if (jas_iccputsint32(out, lut8->e[i][j]))
1366         goto error;
1367     }
1368   }
1369   if (jas_iccputuint16(out, lut8->numintabents) ||
1370     jas_iccputuint16(out, lut8->numouttabents))
1371     goto error;
1372   n = lut8->numinchans * lut8->numintabents;
1373   for (i = 0; i < n; ++i) {
1374     if (jas_iccputuint8(out, lut8->intabsbuf[i]))
1375       goto error;
1376   }
1377   n = lut8->numoutchans * lut8->numouttabents;
1378   for (i = 0; i < n; ++i) {
1379     if (jas_iccputuint8(out, lut8->outtabsbuf[i]))
1380       goto error;
1381   }
1382   n = jas_iccpowi(lut8->clutlen, lut8->numinchans) * lut8->numoutchans;
1383   for (i = 0; i < n; ++i) {
1384     if (jas_iccputuint8(out, lut8->clut[i]))
1385       goto error;
1386   }
1387   return 0;
1388 error:
1389   return -1;
1390 }
1391
1392 static void jas_icclut8_dump(jas_iccattrval_t *attrval, FILE *out)
1393 {
1394   jas_icclut8_t *lut8 = &attrval->data.lut8;
1395   int i;
1396   int j;
1397   fprintf(out, "numinchans=%d, numoutchans=%d, clutlen=%d\n",
1398     lut8->numinchans, lut8->numoutchans, lut8->clutlen);
1399   for (i = 0; i < 3; ++i) {
1400     for (j = 0; j < 3; ++j) {
1401       fprintf(out, "e[%d][%d]=%f ", i, j, lut8->e[i][j] / 65536.0);
1402     }
1403     fprintf(out, "\n");
1404   }
1405   fprintf(out, "numintabents=%d, numouttabents=%d\n",
1406     lut8->numintabents, lut8->numouttabents);
1407 }
1408
1409 /******************************************************************************\
1410 *
1411 \******************************************************************************/
1412
1413 static void jas_icclut16_destroy(jas_iccattrval_t *attrval)
1414 {
1415   jas_icclut16_t *lut16 = &attrval->data.lut16;
1416   if (lut16->clut)
1417     jas_free(lut16->clut);
1418   if (lut16->intabs)
1419     jas_free(lut16->intabs);
1420   if (lut16->intabsbuf)
1421     jas_free(lut16->intabsbuf);
1422   if (lut16->outtabs)
1423     jas_free(lut16->outtabs);
1424   if (lut16->outtabsbuf)
1425     jas_free(lut16->outtabsbuf);
1426 }
1427
1428 static int jas_icclut16_copy(jas_iccattrval_t *attrval,
1429   jas_iccattrval_t *othattrval)
1430 {
1431   /* Avoid compiler warnings about unused parameters. */
1432   attrval = 0;
1433   othattrval = 0;
1434   /* Not yet implemented. */
1435   abort();
1436   return -1;
1437 }
1438
1439 static int jas_icclut16_input(jas_iccattrval_t *attrval, jas_stream_t *in,
1440   int cnt)
1441 {
1442   int i;
1443   int j;
1444   int clutsize;
1445   jas_icclut16_t *lut16 = &attrval->data.lut16;
1446   lut16->clut = 0;
1447   lut16->intabs = 0;
1448   lut16->intabsbuf = 0;
1449   lut16->outtabs = 0;
1450   lut16->outtabsbuf = 0;
1451   if (jas_iccgetuint8(in, &lut16->numinchans) ||
1452     jas_iccgetuint8(in, &lut16->numoutchans) ||
1453     jas_iccgetuint8(in, &lut16->clutlen) ||
1454     jas_stream_getc(in) == EOF)
1455     goto error;
1456   for (i = 0; i < 3; ++i) {
1457     for (j = 0; j < 3; ++j) {
1458       if (jas_iccgetsint32(in, &lut16->e[i][j]))
1459         goto error;
1460     }
1461   }
1462   if (jas_iccgetuint16(in, &lut16->numintabents) ||
1463     jas_iccgetuint16(in, &lut16->numouttabents))
1464     goto error;
1465   clutsize = jas_iccpowi(lut16->clutlen, lut16->numinchans) * lut16->numoutchans;
1466   if (!(lut16->clut = jas_malloc(clutsize * sizeof(jas_iccuint16_t))) ||
1467     !(lut16->intabsbuf = jas_malloc(lut16->numinchans *
1468     lut16->numintabents * sizeof(jas_iccuint16_t))) ||
1469     !(lut16->intabs = jas_malloc(lut16->numinchans *
1470     sizeof(jas_iccuint16_t *))))
1471     goto error;
1472   for (i = 0; i < lut16->numinchans; ++i)
1473     lut16->intabs[i] = &lut16->intabsbuf[i * lut16->numintabents];
1474   if (!(lut16->outtabsbuf = jas_malloc(lut16->numoutchans *
1475     lut16->numouttabents * sizeof(jas_iccuint16_t))) ||
1476     !(lut16->outtabs = jas_malloc(lut16->numoutchans *
1477     sizeof(jas_iccuint16_t *))))
1478     goto error;
1479   for (i = 0; i < lut16->numoutchans; ++i)
1480     lut16->outtabs[i] = &lut16->outtabsbuf[i * lut16->numouttabents];
1481   for (i = 0; i < lut16->numinchans; ++i) {
1482     for (j = 0; j < JAS_CAST(int, lut16->numintabents); ++j) {
1483       if (jas_iccgetuint16(in, &lut16->intabs[i][j]))
1484         goto error;
1485     }
1486   }
1487   for (i = 0; i < lut16->numoutchans; ++i) {
1488     for (j = 0; j < JAS_CAST(int, lut16->numouttabents); ++j) {
1489       if (jas_iccgetuint16(in, &lut16->outtabs[i][j]))
1490         goto error;
1491     }
1492   }
1493   for (i = 0; i < clutsize; ++i) {
1494     if (jas_iccgetuint16(in, &lut16->clut[i]))
1495       goto error;
1496   }
1497   if (JAS_CAST(int, 44 + 2 * (lut16->numinchans * lut16->numintabents +
1498           lut16->numoutchans * lut16->numouttabents +
1499           jas_iccpowi(lut16->clutlen, lut16->numinchans) *
1500     lut16->numoutchans)) != cnt)
1501     goto error;
1502   return 0;
1503 error:
1504   jas_icclut16_destroy(attrval);
1505   return -1;
1506 }
1507
1508 static int jas_icclut16_getsize(jas_iccattrval_t *attrval)
1509 {
1510   jas_icclut16_t *lut16 = &attrval->data.lut16;
1511   return 44 + 2 * (lut16->numinchans * lut16->numintabents +
1512     lut16->numoutchans * lut16->numouttabents +
1513     jas_iccpowi(lut16->clutlen, lut16->numinchans) * lut16->numoutchans);
1514 }
1515
1516 static int jas_icclut16_output(jas_iccattrval_t *attrval, jas_stream_t *out)
1517 {
1518   jas_icclut16_t *lut16 = &attrval->data.lut16;
1519   int i;
1520   int j;
1521   int n;
1522   if (jas_stream_putc(out, lut16->numinchans) == EOF ||
1523     jas_stream_putc(out, lut16->numoutchans) == EOF ||
1524     jas_stream_putc(out, lut16->clutlen) == EOF ||
1525     jas_stream_putc(out, 0) == EOF)
1526     goto error;
1527   for (i = 0; i < 3; ++i) {
1528     for (j = 0; j < 3; ++j) {
1529       if (jas_iccputsint32(out, lut16->e[i][j]))
1530         goto error;
1531     }
1532   }
1533   if (jas_iccputuint16(out, lut16->numintabents) ||
1534     jas_iccputuint16(out, lut16->numouttabents))
1535     goto error;
1536   n = lut16->numinchans * lut16->numintabents;
1537   for (i = 0; i < n; ++i) {
1538     if (jas_iccputuint16(out, lut16->intabsbuf[i]))
1539       goto error;
1540   }
1541   n = lut16->numoutchans * lut16->numouttabents;
1542   for (i = 0; i < n; ++i) {
1543     if (jas_iccputuint16(out, lut16->outtabsbuf[i]))
1544       goto error;
1545   }
1546   n = jas_iccpowi(lut16->clutlen, lut16->numinchans) * lut16->numoutchans;
1547   for (i = 0; i < n; ++i) {
1548     if (jas_iccputuint16(out, lut16->clut[i]))
1549       goto error;
1550   }
1551   return 0;
1552 error:
1553   return -1;
1554 }
1555
1556 static void jas_icclut16_dump(jas_iccattrval_t *attrval, FILE *out)
1557 {
1558   jas_icclut16_t *lut16 = &attrval->data.lut16;
1559   int i;
1560   int j;
1561   fprintf(out, "numinchans=%d, numoutchans=%d, clutlen=%d\n",
1562     lut16->numinchans, lut16->numoutchans, lut16->clutlen);
1563   for (i = 0; i < 3; ++i) {
1564     for (j = 0; j < 3; ++j) {
1565       fprintf(out, "e[%d][%d]=%f ", i, j, lut16->e[i][j] / 65536.0);
1566     }
1567     fprintf(out, "\n");
1568   }
1569   fprintf(out, "numintabents=%d, numouttabents=%d\n",
1570     lut16->numintabents, lut16->numouttabents);
1571 }
1572
1573 /******************************************************************************\
1574 *
1575 \******************************************************************************/
1576
1577 static int jas_iccgetuint(jas_stream_t *in, int n, ulonglong *val)
1578 {
1579   int i;
1580   int c;
1581   ulonglong v;
1582   v = 0;
1583   for (i = n; i > 0; --i) {
1584     if ((c = jas_stream_getc(in)) == EOF)
1585       return -1;
1586     v = (v << 8) | c;
1587   }
1588   *val = v;
1589   return 0;
1590 }
1591
1592 static int jas_iccgetuint8(jas_stream_t *in, jas_iccuint8_t *val)
1593 {
1594   int c;
1595   if ((c = jas_stream_getc(in)) == EOF)
1596     return -1;
1597   *val = c;
1598   return 0;
1599 }
1600
1601 static int jas_iccgetuint16(jas_stream_t *in, jas_iccuint16_t *val)
1602 {
1603   ulonglong tmp;
1604   if (jas_iccgetuint(in, 2, &tmp))
1605     return -1;
1606   *val = (jas_iccuint16_t)tmp; /* warning C4244: '=' : conversion from 'ulonglong' to 'jas_iccuint16_t', possible loss of data */
1607   return 0;
1608 }
1609
1610 static int jas_iccgetsint32(jas_stream_t *in, jas_iccsint32_t *val)
1611 {
1612   ulonglong tmp;
1613   if (jas_iccgetuint(in, 4, &tmp))
1614     return -1;
1615   *val = (jas_iccsint32_t)((tmp & 0x80000000) ? (-JAS_CAST(longlong, (((~tmp) &
1616     0x7fffffff) + 1))) : JAS_CAST(longlong, tmp)); /* warning C4244: '=' : conversion from 'longlong' to 'jas_iccsint32_t', possible loss of data */
1617   return 0;
1618 }
1619
1620 static int jas_iccgetuint32(jas_stream_t *in, jas_iccuint32_t *val)
1621 {
1622   ulonglong tmp;
1623   if (jas_iccgetuint(in, 4, &tmp))
1624     return -1;
1625   *val = (jas_iccuint32_t)tmp; /* warning C4244: '=' : conversion from 'ulonglong' to 'jas_iccuint32_t', possible loss of data */
1626   return 0;
1627 }
1628
1629 static int jas_iccgetuint64(jas_stream_t *in, jas_iccuint64_t *val)
1630 {
1631   ulonglong tmp;
1632   if (jas_iccgetuint(in, 8, &tmp))
1633     return -1;
1634   *val = tmp;
1635   return 0;
1636 }
1637
1638 static int jas_iccputuint(jas_stream_t *out, int n, ulonglong val)
1639 {
1640   int i;
1641   int c;
1642   for (i = n; i > 0; --i) {
1643     c = (int)((val >> (8 * (i - 1))) & 0xff); /* warning C4244: '=' : conversion from 'ulonglong' to 'int', possible loss of data */
1644     if (jas_stream_putc(out, c) == EOF)
1645       return -1;
1646   }
1647   return 0;
1648 }
1649
1650 static int jas_iccputsint(jas_stream_t *out, int n, longlong val)
1651 {
1652   ulonglong tmp;
1653   tmp = (val < 0) ? (abort(), 0) : val;
1654   return jas_iccputuint(out, n, tmp);
1655 }
1656
1657 /******************************************************************************\
1658 *
1659 \******************************************************************************/
1660
1661 static char *jas_iccsigtostr(int sig, char *buf)
1662 {
1663   int n;
1664   int c;
1665   char *bufptr;
1666   bufptr = buf;
1667   for (n = 4; n > 0; --n) {
1668     c = (sig >> 24) & 0xff;
1669     if (isalpha(c) || isdigit(c)) {
1670       *bufptr++ = c;
1671     }
1672     sig <<= 8;
1673   }
1674   *bufptr = '\0';
1675   return buf;
1676 }
1677
1678 static long jas_iccpadtomult(long x, long y)
1679 {
1680   return ((x + y - 1) / y) * y;
1681 }
1682
1683 static long jas_iccpowi(int x, int n)
1684 {
1685   long y;
1686   y = 1;
1687   while (--n >= 0)
1688     y *= x;
1689   return y;
1690 }
1691
1692
1693 jas_iccprof_t *jas_iccprof_createfrombuf(uchar *buf, int len)
1694 {
1695   jas_stream_t *in;
1696   jas_iccprof_t *prof;
1697   if (!(in = jas_stream_memopen(JAS_CAST(char *, buf), len)))
1698     goto error;
1699   if (!(prof = jas_iccprof_load(in)))
1700     goto error;
1701   jas_stream_close(in);
1702   return prof;
1703 error:
1704   return 0;
1705 }
1706
1707 jas_iccprof_t *jas_iccprof_createfromclrspc(int clrspc)
1708 {
1709   jas_iccprof_t *prof;
1710   switch (clrspc) {
1711   case JAS_CLRSPC_SRGB:
1712     prof = jas_iccprof_createfrombuf(jas_iccprofdata_srgb,
1713       jas_iccprofdata_srgblen);
1714     break;
1715   case JAS_CLRSPC_SGRAY:
1716     prof = jas_iccprof_createfrombuf(jas_iccprofdata_sgray,
1717       jas_iccprofdata_sgraylen);
1718     break;
1719   default:
1720     prof = 0;
1721     break;
1722   }
1723   return prof;
1724 }