Update lcms (#544)
[openjpeg.git] / thirdparty / liblcms2 / src / cmstypes.c
1 //---------------------------------------------------------------------------------
2 //
3 //  Little Color Management System
4 //  Copyright (c) 1998-2016 Marti Maria Saguer
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24 //---------------------------------------------------------------------------------
25 //
26
27 #include "lcms2_internal.h"
28
29 // Tag Serialization  -----------------------------------------------------------------------------
30 // This file implements every single tag and tag type as described in the ICC spec. Some types
31 // have been deprecated, like ncl and Data. There is no implementation for those types as there
32 // are no profiles holding them. The programmer can also extend this list by defining his own types
33 // by using the appropiate plug-in. There are three types of plug ins regarding that. First type
34 // allows to define new tags using any existing type. Next plug-in type allows to define new types
35 // and the third one is very specific: allows to extend the number of elements in the multiprocessing
36 // elements special type.
37 //--------------------------------------------------------------------------------------------------
38
39 // Some broken types
40 #define cmsCorbisBrokenXYZtype    ((cmsTagTypeSignature) 0x17A505B8)
41 #define cmsMonacoBrokenCurveType  ((cmsTagTypeSignature) 0x9478ee00)
42
43 // This is the linked list that keeps track of the defined types
44 typedef struct _cmsTagTypeLinkedList_st {
45
46     cmsTagTypeHandler Handler;
47     struct _cmsTagTypeLinkedList_st* Next;
48
49 } _cmsTagTypeLinkedList;
50
51 // Some macros to define callbacks.
52 #define READ_FN(x)  Type_##x##_Read
53 #define WRITE_FN(x) Type_##x##_Write
54 #define FREE_FN(x)  Type_##x##_Free
55 #define DUP_FN(x)   Type_##x##_Dup
56
57 // Helper macro to define a handler. Callbacks do have a fixed naming convention.
58 #define TYPE_HANDLER(t, x)  { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 }
59
60 // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
61 #define TYPE_MPE_HANDLER(t, x)  { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
62
63 // Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head
64 static
65 cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos)
66 {
67     cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
68     _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos);
69     _cmsTagTypeLinkedList *pt;
70
71     // Calling the function with NULL as plug-in would unregister the plug in.
72     if (Data == NULL) {
73
74         // There is no need to set free the memory, as pool is destroyed as a whole.
75         ctx ->TagTypes = NULL;
76         return TRUE;
77     }
78
79     // Registering happens in plug-in memory pool.
80     pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
81     if (pt == NULL) return FALSE;
82
83     pt ->Handler   = Plugin ->Handler;
84     pt ->Next      = ctx ->TagTypes;
85
86     ctx ->TagTypes = pt;
87      
88     return TRUE;
89 }
90
91 // Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons 
92 // made by plug-ins and then the built-in defaults.
93 static
94 cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList)
95 {
96     _cmsTagTypeLinkedList* pt;
97
98     for (pt = PluginLinkedList;
99          pt != NULL;
100          pt = pt ->Next) {
101
102             if (sig == pt -> Handler.Signature) return &pt ->Handler;
103     }
104
105     for (pt = DefaultLinkedList;
106          pt != NULL;
107          pt = pt ->Next) {
108
109             if (sig == pt -> Handler.Signature) return &pt ->Handler;
110     }
111
112     return NULL;
113 }
114
115
116 // Auxiliar to convert UTF-32 to UTF-16 in some cases
117 static
118 cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
119 {
120     cmsUInt32Number i;
121
122     _cmsAssert(io != NULL);
123     _cmsAssert(!(Array == NULL && n > 0));
124
125     for (i=0; i < n; i++) {
126         if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
127     }
128
129     return TRUE;
130 }
131
132 // Auxiliar to read an array of wchar_t
133 static
134 cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
135 {
136     cmsUInt32Number i;
137     cmsUInt16Number tmp;
138
139     _cmsAssert(io != NULL);
140
141     for (i=0; i < n; i++) {
142
143         if (Array != NULL) {
144
145             if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
146             Array[i] = (wchar_t) tmp;
147         }
148         else {
149             if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
150         }
151
152     }
153     return TRUE;
154 }
155
156 // To deal with position tables
157 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
158                                              cmsIOHANDLER* io,
159                                              void* Cargo,
160                                              cmsUInt32Number n,
161                                              cmsUInt32Number SizeOfTag);
162
163 // Helper function to deal with position tables as decribed in ICC spec 4.3
164 // A table of n elements is readed, where first comes n records containing offsets and sizes and
165 // then a block containing the data itself. This allows to reuse same data in more than one entry
166 static
167 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
168                               cmsIOHANDLER* io,
169                               cmsUInt32Number Count,
170                               cmsUInt32Number BaseOffset,
171                               void *Cargo,
172                               PositionTableEntryFn ElementFn)
173 {
174     cmsUInt32Number i;
175     cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
176
177     // Let's take the offsets to each element
178     ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
179     if (ElementOffsets == NULL) goto Error;
180
181     ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
182     if (ElementSizes == NULL) goto Error;
183
184     for (i=0; i < Count; i++) {
185
186         if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error;
187         if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error;
188
189         ElementOffsets[i] += BaseOffset;
190     }
191
192     // Seek to each element and read it
193     for (i=0; i < Count; i++) {
194
195         if (!io -> Seek(io, ElementOffsets[i])) goto Error;
196
197         // This is the reader callback
198         if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error;
199     }
200
201     // Success
202     if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
203     if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
204     return TRUE;
205
206 Error:
207     if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
208     if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
209     return FALSE;
210 }
211
212 // Same as anterior, but for write position tables
213 static
214 cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
215                                cmsIOHANDLER* io,
216                                cmsUInt32Number SizeOfTag,
217                                cmsUInt32Number Count,
218                                cmsUInt32Number BaseOffset,
219                                void *Cargo,
220                                PositionTableEntryFn ElementFn)
221 {
222     cmsUInt32Number i;
223     cmsUInt32Number DirectoryPos, CurrentPos, Before;
224     cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
225
226      // Create table
227     ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
228     if (ElementOffsets == NULL) goto Error;
229
230     ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
231     if (ElementSizes == NULL) goto Error;
232
233     // Keep starting position of curve offsets
234     DirectoryPos = io ->Tell(io);
235
236     // Write a fake directory to be filled latter on
237     for (i=0; i < Count; i++) {
238
239         if (!_cmsWriteUInt32Number(io, 0)) goto Error;  // Offset
240         if (!_cmsWriteUInt32Number(io, 0)) goto Error;  // size
241     }
242
243     // Write each element. Keep track of the size as well.
244     for (i=0; i < Count; i++) {
245
246         Before = io ->Tell(io);
247         ElementOffsets[i] = Before - BaseOffset;
248
249         // Callback to write...
250         if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error;
251
252         // Now the size
253         ElementSizes[i] = io ->Tell(io) - Before;
254     }
255
256     // Write the directory
257     CurrentPos = io ->Tell(io);
258     if (!io ->Seek(io, DirectoryPos)) goto Error;
259
260     for (i=0; i <  Count; i++) {
261         if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
262         if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
263     }
264
265     if (!io ->Seek(io, CurrentPos)) goto Error;
266
267     if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
268     if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
269     return TRUE;
270
271 Error:
272     if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
273     if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
274     return FALSE;
275 }
276
277
278 // ********************************************************************************
279 // Type XYZ. Only one value is allowed
280 // ********************************************************************************
281
282 //The XYZType contains an array of three encoded values for the XYZ tristimulus
283 //values. Tristimulus values must be non-negative. The signed encoding allows for
284 //implementation optimizations by minimizing the number of fixed formats.
285
286
287 static
288 void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
289 {
290     cmsCIEXYZ* xyz;
291
292     *nItems = 0;
293     xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
294     if (xyz == NULL) return NULL;
295
296     if (!_cmsReadXYZNumber(io, xyz)) {
297         _cmsFree(self ->ContextID, xyz);
298         return NULL;
299     }
300
301     *nItems = 1;
302     return (void*) xyz;
303
304     cmsUNUSED_PARAMETER(SizeOfTag);
305 }
306
307 static
308 cmsBool  Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
309 {
310     return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
311
312     cmsUNUSED_PARAMETER(nItems);
313     cmsUNUSED_PARAMETER(self);
314 }
315
316 static
317 void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
318 {
319     return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
320
321     cmsUNUSED_PARAMETER(n);
322 }
323
324 static
325 void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
326 {
327     _cmsFree(self ->ContextID, Ptr);
328 }
329
330
331 static
332 cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
333 {
334     return cmsSigXYZType;
335
336     cmsUNUSED_PARAMETER(ICCVersion);
337     cmsUNUSED_PARAMETER(Data);
338 }
339
340
341 // ********************************************************************************
342 // Type chromaticity. Only one value is allowed
343 // ********************************************************************************
344 // The chromaticity tag type provides basic chromaticity data and type of
345 // phosphors or colorants of a monitor to applications and utilities.
346
347 static
348 void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
349 {
350     cmsCIExyYTRIPLE* chrm;
351     cmsUInt16Number nChans, Table;
352
353     *nItems = 0;
354     chrm =  (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
355     if (chrm == NULL) return NULL;
356
357     if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
358
359     // Let's recover from a bug introduced in early versions of lcms1
360     if (nChans == 0 && SizeOfTag == 32) {
361
362         if (!_cmsReadUInt16Number(io, NULL)) goto Error;
363         if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
364     }
365
366     if (nChans != 3) goto Error;
367
368     if (!_cmsReadUInt16Number(io, &Table)) goto Error;
369
370     if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
371     if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
372
373     chrm ->Red.Y = 1.0;
374
375     if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
376     if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
377
378     chrm ->Green.Y = 1.0;
379
380     if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
381     if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
382
383     chrm ->Blue.Y = 1.0;
384
385     *nItems = 1;
386     return (void*) chrm;
387
388 Error:
389     _cmsFree(self ->ContextID, (void*) chrm);
390     return NULL;
391
392     cmsUNUSED_PARAMETER(SizeOfTag);
393 }
394
395 static
396 cmsBool  SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
397 {
398     if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
399     if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
400
401     return TRUE;
402 }
403
404 static
405 cmsBool  Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
406 {
407     cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
408
409     if (!_cmsWriteUInt16Number(io, 3)) return FALSE;        // nChannels
410     if (!_cmsWriteUInt16Number(io, 0)) return FALSE;        // Table
411
412     if (!SaveOneChromaticity(chrm -> Red.x,   chrm -> Red.y, io)) return FALSE;
413     if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
414     if (!SaveOneChromaticity(chrm -> Blue.x,  chrm -> Blue.y, io)) return FALSE;
415
416     return TRUE;
417
418     cmsUNUSED_PARAMETER(nItems);
419     cmsUNUSED_PARAMETER(self);
420 }
421
422 static
423 void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
424 {
425     return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
426
427     cmsUNUSED_PARAMETER(n);
428 }
429
430 static
431 void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
432 {
433     _cmsFree(self ->ContextID, Ptr);
434 }
435
436
437 // ********************************************************************************
438 // Type cmsSigColorantOrderType
439 // ********************************************************************************
440
441 // This is an optional tag which specifies the laydown order in which colorants will
442 // be printed on an n-colorant device. The laydown order may be the same as the
443 // channel generation order listed in the colorantTableTag or the channel order of a
444 // colour space such as CMYK, in which case this tag is not needed. When this is not
445 // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
446 // used to specify the laydown order of the colorants.
447
448
449 static
450 void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
451 {
452     cmsUInt8Number* ColorantOrder;
453     cmsUInt32Number Count;
454
455     *nItems = 0;
456     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
457     if (Count > cmsMAXCHANNELS) return NULL;
458
459     ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
460     if (ColorantOrder == NULL) return NULL;
461
462     // We use FF as end marker
463     memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
464
465     if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
466
467         _cmsFree(self ->ContextID, (void*) ColorantOrder);
468         return NULL;
469     }
470
471     *nItems = 1;
472     return (void*) ColorantOrder;
473
474     cmsUNUSED_PARAMETER(SizeOfTag);
475 }
476
477 static
478 cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
479 {
480     cmsUInt8Number*  ColorantOrder = (cmsUInt8Number*) Ptr;
481     cmsUInt32Number i, sz, Count;
482
483     // Get the length
484     for (Count=i=0; i < cmsMAXCHANNELS; i++) {
485         if (ColorantOrder[i] != 0xFF) Count++;
486     }
487
488     if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
489
490     sz = Count * sizeof(cmsUInt8Number);
491     if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
492
493     return TRUE;
494
495     cmsUNUSED_PARAMETER(nItems);
496     cmsUNUSED_PARAMETER(self);
497 }
498
499 static
500 void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
501 {
502     return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
503
504     cmsUNUSED_PARAMETER(n);
505 }
506
507
508 static
509 void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
510 {
511     _cmsFree(self ->ContextID, Ptr);
512 }
513
514 // ********************************************************************************
515 // Type cmsSigS15Fixed16ArrayType
516 // ********************************************************************************
517 // This type represents an array of generic 4-byte/32-bit fixed point quantity.
518 // The number of values is determined from the size of the tag.
519
520 static
521 void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
522 {
523     cmsFloat64Number*  array_double;
524     cmsUInt32Number i, n;
525
526     *nItems = 0;
527     n = SizeOfTag / sizeof(cmsUInt32Number);
528     array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
529     if (array_double == NULL) return NULL;
530
531     for (i=0; i < n; i++) {
532
533         if (!_cmsRead15Fixed16Number(io, &array_double[i])) {
534
535             _cmsFree(self ->ContextID, array_double);
536             return NULL;
537         }
538     }
539
540     *nItems = n;
541     return (void*) array_double;
542 }
543
544 static
545 cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
546 {
547     cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
548     cmsUInt32Number i;
549
550     for (i=0; i < nItems; i++) {
551
552         if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
553     }
554
555     return TRUE;
556
557     cmsUNUSED_PARAMETER(self);
558 }
559
560 static
561 void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
562 {
563     return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
564 }
565
566
567 static
568 void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
569 {
570     _cmsFree(self ->ContextID, Ptr);
571 }
572
573 // ********************************************************************************
574 // Type cmsSigU16Fixed16ArrayType
575 // ********************************************************************************
576 // This type represents an array of generic 4-byte/32-bit quantity.
577 // The number of values is determined from the size of the tag.
578
579
580 static
581 void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
582 {
583     cmsFloat64Number*  array_double;
584     cmsUInt32Number v;
585     cmsUInt32Number i, n;
586
587     *nItems = 0;
588     n = SizeOfTag / sizeof(cmsUInt32Number);
589     array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
590     if (array_double == NULL) return NULL;
591
592     for (i=0; i < n; i++) {
593
594         if (!_cmsReadUInt32Number(io, &v)) {
595             _cmsFree(self ->ContextID, (void*) array_double);
596             return NULL;
597         }
598
599         // Convert to cmsFloat64Number
600         array_double[i] =  (cmsFloat64Number) (v / 65536.0);
601     }
602
603     *nItems = n;
604     return (void*) array_double;
605 }
606
607 static
608 cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
609 {
610     cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
611     cmsUInt32Number i;
612
613     for (i=0; i < nItems; i++) {
614
615         cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
616
617         if (!_cmsWriteUInt32Number(io, v)) return FALSE;
618     }
619
620     return TRUE;
621
622     cmsUNUSED_PARAMETER(self);
623 }
624
625
626 static
627 void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
628 {
629     return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
630 }
631
632 static
633 void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
634 {
635     _cmsFree(self ->ContextID, Ptr);
636 }
637
638 // ********************************************************************************
639 // Type cmsSigSignatureType
640 // ********************************************************************************
641 //
642 // The signatureType contains a four-byte sequence, Sequences of less than four
643 // characters are padded at the end with spaces, 20h.
644 // Typically this type is used for registered tags that can be displayed on many
645 // development systems as a sequence of four characters.
646
647 static
648 void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
649 {
650     cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
651     if (SigPtr == NULL) return NULL;
652
653      if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
654      *nItems = 1;
655
656      return SigPtr;
657
658      cmsUNUSED_PARAMETER(SizeOfTag);
659 }
660
661 static
662 cmsBool  Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
663 {
664     cmsSignature* SigPtr = (cmsSignature*) Ptr;
665
666     return _cmsWriteUInt32Number(io, *SigPtr);
667
668     cmsUNUSED_PARAMETER(nItems);
669     cmsUNUSED_PARAMETER(self);
670 }
671
672 static
673 void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
674 {
675     return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
676 }
677
678 static
679 void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
680 {
681     _cmsFree(self ->ContextID, Ptr);
682 }
683
684
685 // ********************************************************************************
686 // Type cmsSigTextType
687 // ********************************************************************************
688 //
689 // The textType is a simple text structure that contains a 7-bit ASCII text string.
690 // The length of the string is obtained by subtracting 8 from the element size portion
691 // of the tag itself. This string must be terminated with a 00h byte.
692
693 static
694 void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
695 {
696     char* Text = NULL;
697     cmsMLU* mlu = NULL;
698
699     // Create a container
700     mlu = cmsMLUalloc(self ->ContextID, 1);
701     if (mlu == NULL) return NULL;
702
703     *nItems = 0;
704
705     // We need to store the "\0" at the end, so +1
706     if (SizeOfTag == UINT_MAX) goto Error;
707
708     Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
709     if (Text == NULL) goto Error;
710
711     if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error;
712
713     // Make sure text is properly ended
714     Text[SizeOfTag] = 0;
715     *nItems = 1;
716
717     // Keep the result
718     if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
719
720     _cmsFree(self ->ContextID, Text);
721     return (void*) mlu;
722
723 Error:
724     if (mlu != NULL)
725         cmsMLUfree(mlu);
726     if (Text != NULL)
727         _cmsFree(self ->ContextID, Text);
728
729     return NULL;
730 }
731
732 // The conversion implies to choose a language. So, we choose the actual language.
733 static
734 cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
735 {
736     cmsMLU* mlu = (cmsMLU*) Ptr;
737     cmsUInt32Number size;
738     cmsBool  rc;
739     char* Text;
740
741     // Get the size of the string. Note there is an extra "\0" at the end
742     size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
743     if (size == 0) return FALSE;       // Cannot be zero!
744
745     // Create memory
746     Text = (char*) _cmsMalloc(self ->ContextID, size);
747     if (Text == NULL) return FALSE;
748
749     cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
750
751     // Write it, including separator
752     rc = io ->Write(io, size, Text);
753
754     _cmsFree(self ->ContextID, Text);
755     return rc;
756
757     cmsUNUSED_PARAMETER(nItems);
758 }
759
760 static
761 void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
762 {
763     return (void*) cmsMLUdup((cmsMLU*) Ptr);
764
765     cmsUNUSED_PARAMETER(n);
766     cmsUNUSED_PARAMETER(self);
767 }
768
769
770 static
771 void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
772 {
773     cmsMLU* mlu = (cmsMLU*) Ptr;
774     cmsMLUfree(mlu);
775     return;
776
777     cmsUNUSED_PARAMETER(self);
778 }
779
780 static
781 cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
782 {
783     if (ICCVersion >= 4.0)
784         return cmsSigMultiLocalizedUnicodeType;
785
786     return cmsSigTextType;
787
788     cmsUNUSED_PARAMETER(Data);
789 }
790
791
792 // ********************************************************************************
793 // Type cmsSigDataType
794 // ********************************************************************************
795
796 // General purpose data type
797 static
798 void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
799 {
800     cmsICCData* BinData;
801     cmsUInt32Number LenOfData;
802
803     *nItems = 0;
804
805     if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
806
807     LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
808     if (LenOfData > INT_MAX) return NULL;
809
810     BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1);
811     if (BinData == NULL) return NULL;
812
813     BinData ->len = LenOfData;
814     if (!_cmsReadUInt32Number(io, &BinData->flag)) {
815         _cmsFree(self ->ContextID, BinData);
816         return NULL;
817     }
818
819     if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
820
821         _cmsFree(self ->ContextID, BinData);
822         return NULL;
823     }
824
825     *nItems = 1;
826
827     return (void*) BinData;
828 }
829
830
831 static
832 cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
833 {
834    cmsICCData* BinData = (cmsICCData*) Ptr;
835
836    if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
837
838    return io ->Write(io, BinData ->len, BinData ->data);
839
840    cmsUNUSED_PARAMETER(nItems);
841    cmsUNUSED_PARAMETER(self);
842 }
843
844
845 static
846 void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
847 {
848     cmsICCData* BinData = (cmsICCData*) Ptr;
849
850     return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
851
852     cmsUNUSED_PARAMETER(n);
853 }
854
855 static
856 void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
857 {
858     _cmsFree(self ->ContextID, Ptr);
859 }
860
861 // ********************************************************************************
862 // Type cmsSigTextDescriptionType
863 // ********************************************************************************
864
865 static
866 void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
867 {
868     char* Text = NULL;
869     cmsMLU* mlu = NULL;
870     cmsUInt32Number  AsciiCount;
871     cmsUInt32Number  i, UnicodeCode, UnicodeCount;
872     cmsUInt16Number  ScriptCodeCode, Dummy;
873     cmsUInt8Number   ScriptCodeCount;
874
875     *nItems = 0;
876
877     //  One dword should be there
878     if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
879
880     // Read len of ASCII
881     if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL;
882     SizeOfTag -= sizeof(cmsUInt32Number);
883
884     // Check for size
885     if (SizeOfTag < AsciiCount) return NULL;
886
887     // All seems Ok, allocate the container
888     mlu = cmsMLUalloc(self ->ContextID, 1);
889     if (mlu == NULL) return NULL;
890
891     // As many memory as size of tag
892     Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1);
893     if (Text == NULL) goto Error;
894
895     // Read it
896     if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error;
897     SizeOfTag -= AsciiCount;
898
899     // Make sure there is a terminator
900     Text[AsciiCount] = 0;
901
902     // Set the MLU entry. From here we can be tolerant to wrong types
903     if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
904     _cmsFree(self ->ContextID, (void*) Text);
905     Text = NULL;
906
907     // Skip Unicode code
908     if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done;
909     if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done;
910     if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
911     SizeOfTag -= 2* sizeof(cmsUInt32Number);
912
913     if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
914
915     for (i=0; i < UnicodeCount; i++) {
916         if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
917     }
918     SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
919
920     // Skip ScriptCode code if present. Some buggy profiles does have less
921     // data that stricttly required. We need to skip it as this type may come
922     // embedded in other types.
923
924     if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
925
926         if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done;
927         if (!_cmsReadUInt8Number(io,  &ScriptCodeCount)) goto Done;
928
929         // Skip rest of tag
930         for (i=0; i < 67; i++) {
931             if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error;
932         }
933     }
934
935 Done:
936
937     *nItems = 1;
938     return mlu;
939
940 Error:
941     if (Text) _cmsFree(self ->ContextID, (void*) Text);
942     if (mlu) cmsMLUfree(mlu);
943     return NULL;
944 }
945
946
947 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
948 static
949 cmsBool  Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
950 {
951     cmsMLU* mlu = (cmsMLU*) Ptr;
952     char *Text = NULL;
953     wchar_t *Wide = NULL;
954     cmsUInt32Number len, len_text, len_tag_requirement, len_aligned;
955     cmsBool  rc = FALSE;
956     char Filler[68];
957
958     // Used below for writting zeroes
959     memset(Filler, 0, sizeof(Filler));
960
961     // Get the len of string
962     len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
963
964     // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data
965     //(see clause 4.1 for the definition of ï¿½aligned�). Because the Unicode language
966     // code and Unicode count immediately follow the ASCII description, their
967     // alignment is not correct if the ASCII count is not a multiple of four. The
968     // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
969     // writing software must be written carefully in order to handle these alignment
970     // problems.
971     //
972     // The above last sentence suggest to handle alignment issues in the
973     // parser. The provided example (Table 69 on Page 60) makes this clear. 
974     // The padding only in the ASCII count is not sufficient for a aligned tag
975     // size, with the same text size in ASCII and Unicode.
976
977     // Null strings
978     if (len <= 0) {
979
980         Text = (char*)    _cmsDupMem(self ->ContextID, "", sizeof(char));
981         Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
982     }
983     else {
984         // Create independent buffers
985         Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
986         if (Text == NULL) goto Error;
987
988         Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t));
989         if (Wide == NULL) goto Error;
990
991         // Get both representations.
992         cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry,  Text, len * sizeof(char));
993         cmsMLUgetWide(mlu,  cmsNoLanguage, cmsNoCountry,  Wide, len * sizeof(wchar_t));
994     }
995
996     // Tell the real text len including the null terminator and padding
997     len_text = strlen(Text) + 1;
998     // Compute an total tag size requirement
999     len_tag_requirement = (8+4+len_text+4+4+2*len_text+2+1+67);
1000     len_aligned = _cmsALIGNLONG(len_tag_requirement);
1001
1002   // * cmsUInt32Number       count;          * Description length
1003   // * cmsInt8Number         desc[count]     * NULL terminated ascii string
1004   // * cmsUInt32Number       ucLangCode;     * UniCode language code
1005   // * cmsUInt32Number       ucCount;        * UniCode description length
1006   // * cmsInt16Number        ucDesc[ucCount];* The UniCode description
1007   // * cmsUInt16Number       scCode;         * ScriptCode code
1008   // * cmsUInt8Number        scCount;        * ScriptCode count
1009   // * cmsInt8Number         scDesc[67];     * ScriptCode Description
1010
1011     if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1012     if (!io ->Write(io, len_text, Text)) goto Error;
1013
1014     if (!_cmsWriteUInt32Number(io, 0)) goto Error;  // ucLanguageCode
1015
1016     if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1017     // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1018     if (!_cmsWriteWCharArray(io, len_text, Wide)) goto Error;
1019
1020     // ScriptCode Code & count (unused)
1021     if (!_cmsWriteUInt16Number(io, 0)) goto Error;
1022     if (!_cmsWriteUInt8Number(io, 0)) goto Error;
1023
1024     if (!io ->Write(io, 67, Filler)) goto Error;
1025
1026     // possibly add pad at the end of tag
1027     if(len_aligned - len_tag_requirement > 0)
1028       if (!io ->Write(io, len_aligned - len_tag_requirement, Filler)) goto Error;
1029
1030     rc = TRUE;
1031
1032 Error:
1033     if (Text) _cmsFree(self ->ContextID, Text);
1034     if (Wide) _cmsFree(self ->ContextID, Wide);
1035
1036     return rc;
1037
1038     cmsUNUSED_PARAMETER(nItems);
1039 }
1040
1041
1042 static
1043 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1044 {
1045     return (void*) cmsMLUdup((cmsMLU*) Ptr);
1046
1047     cmsUNUSED_PARAMETER(n);
1048     cmsUNUSED_PARAMETER(self);
1049 }
1050
1051 static
1052 void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
1053 {
1054     cmsMLU* mlu = (cmsMLU*) Ptr;
1055
1056     cmsMLUfree(mlu);
1057     return;
1058
1059     cmsUNUSED_PARAMETER(self);
1060 }
1061
1062
1063 static
1064 cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
1065 {
1066     if (ICCVersion >= 4.0)
1067         return cmsSigMultiLocalizedUnicodeType;
1068
1069     return cmsSigTextDescriptionType;
1070
1071     cmsUNUSED_PARAMETER(Data);
1072 }
1073
1074
1075 // ********************************************************************************
1076 // Type cmsSigCurveType
1077 // ********************************************************************************
1078
1079 static
1080 void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1081 {
1082     cmsUInt32Number Count;
1083     cmsToneCurve* NewGamma;
1084     
1085     *nItems = 0;
1086     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1087
1088     switch (Count) {
1089
1090            case 0:   // Linear.
1091                {
1092                    cmsFloat64Number SingleGamma = 1.0;
1093
1094                    NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1095                    if (!NewGamma) return NULL;
1096                    *nItems = 1;
1097                    return NewGamma;
1098                }
1099               
1100            case 1:  // Specified as the exponent of gamma function
1101                {
1102                    cmsUInt16Number SingleGammaFixed;
1103                    cmsFloat64Number SingleGamma;
1104
1105                    if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
1106                    SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
1107
1108                    *nItems = 1;
1109                    return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1110                }
1111
1112            default:  // Curve
1113
1114                if (Count > 0x7FFF)
1115                    return NULL; // This is to prevent bad guys for doing bad things
1116
1117                NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
1118                if (!NewGamma) return NULL;
1119
1120                if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
1121
1122                *nItems = 1;
1123                return NewGamma;
1124     }
1125
1126     cmsUNUSED_PARAMETER(SizeOfTag);
1127 }
1128
1129
1130 static
1131 cmsBool  Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1132 {
1133     cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1134
1135     if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
1136
1137             // Single gamma, preserve number
1138             cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
1139
1140             if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
1141             if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
1142             return TRUE;
1143
1144     }
1145
1146     if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
1147     return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
1148
1149     cmsUNUSED_PARAMETER(nItems);
1150     cmsUNUSED_PARAMETER(self);
1151 }
1152
1153
1154 static
1155 void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1156 {
1157     return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1158
1159     cmsUNUSED_PARAMETER(n);
1160     cmsUNUSED_PARAMETER(self);
1161 }
1162
1163 static
1164 void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1165 {
1166     cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1167
1168     cmsFreeToneCurve(gamma);
1169     return;
1170
1171     cmsUNUSED_PARAMETER(self);
1172 }
1173
1174
1175 // ********************************************************************************
1176 // Type cmsSigParametricCurveType
1177 // ********************************************************************************
1178
1179
1180 // Decide which curve type to use on writting
1181 static
1182 cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
1183 {
1184     cmsToneCurve* Curve = (cmsToneCurve*) Data;
1185
1186     if (ICCVersion < 4.0) return cmsSigCurveType;
1187     if (Curve ->nSegments != 1) return cmsSigCurveType;          // Only 1-segment curves can be saved as parametric
1188     if (Curve ->Segments[0].Type < 0) return cmsSigCurveType;    // Only non-inverted curves
1189     if (Curve ->Segments[0].Type > 5) return cmsSigCurveType;    // Only ICC parametric curves
1190
1191     return cmsSigParametricCurveType;
1192 }
1193
1194 static
1195 void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1196 {
1197     static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
1198     cmsFloat64Number Params[10];
1199     cmsUInt16Number Type;
1200     int i, n;
1201     cmsToneCurve* NewGamma;
1202
1203     if (!_cmsReadUInt16Number(io, &Type)) return NULL;
1204     if (!_cmsReadUInt16Number(io, NULL)) return NULL;   // Reserved
1205
1206     if (Type > 4) {
1207
1208         cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
1209         return NULL;
1210     }
1211
1212     memset(Params, 0, sizeof(Params));
1213     n = ParamsByType[Type];
1214
1215     for (i=0; i < n; i++) {
1216
1217         if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
1218     }
1219
1220     NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
1221
1222     *nItems = 1;
1223     return NewGamma;
1224
1225     cmsUNUSED_PARAMETER(SizeOfTag);
1226 }
1227
1228
1229 static
1230 cmsBool  Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1231 {
1232     cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1233     int i, nParams, typen;
1234     static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
1235
1236     typen = Curve -> Segments[0].Type;
1237
1238     if (Curve ->nSegments > 1 || typen < 1) {
1239
1240         cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
1241         return FALSE;
1242     }
1243
1244     if (typen > 5) {
1245         cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
1246         return FALSE;
1247     }
1248
1249     nParams = ParamsByType[typen];
1250
1251     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
1252     if (!_cmsWriteUInt16Number(io, 0)) return FALSE;        // Reserved
1253
1254     for (i=0; i < nParams; i++) {
1255
1256         if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
1257     }
1258
1259     return TRUE;
1260
1261     cmsUNUSED_PARAMETER(nItems);
1262 }
1263
1264 static
1265 void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1266 {
1267     return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1268
1269     cmsUNUSED_PARAMETER(n);
1270     cmsUNUSED_PARAMETER(self);
1271 }
1272
1273 static
1274 void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1275 {
1276     cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1277
1278     cmsFreeToneCurve(gamma);
1279     return;
1280
1281     cmsUNUSED_PARAMETER(self);
1282 }
1283
1284
1285 // ********************************************************************************
1286 // Type cmsSigDateTimeType
1287 // ********************************************************************************
1288
1289 // A 12-byte value representation of the time and date, where the byte usage is assigned
1290 // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
1291 // (uInt16Number - see 5.1.6).
1292 //
1293 // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
1294 // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
1295 // time to UTC when setting these values. Programmes that display these values may show
1296 // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
1297 // display both UTC and local versions of the dateTimeNumber.
1298
1299 static
1300 void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1301 {
1302     cmsDateTimeNumber timestamp;
1303     struct tm * NewDateTime;
1304
1305     *nItems = 0;
1306     NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
1307     if (NewDateTime == NULL) return NULL;
1308
1309     if (io->Read(io, &timestamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
1310
1311      _cmsDecodeDateTimeNumber(&timestamp, NewDateTime);
1312
1313      *nItems = 1;
1314      return NewDateTime;
1315
1316      cmsUNUSED_PARAMETER(SizeOfTag);
1317 }
1318
1319
1320 static
1321 cmsBool  Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1322 {
1323     struct tm * DateTime = (struct tm*) Ptr;
1324     cmsDateTimeNumber timestamp;
1325
1326     _cmsEncodeDateTimeNumber(&timestamp, DateTime);
1327     if (!io ->Write(io, sizeof(cmsDateTimeNumber), &timestamp)) return FALSE;
1328
1329     return TRUE;
1330
1331     cmsUNUSED_PARAMETER(nItems);
1332     cmsUNUSED_PARAMETER(self);
1333 }
1334
1335 static
1336 void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1337 {
1338     return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
1339
1340     cmsUNUSED_PARAMETER(n);
1341 }
1342
1343 static
1344 void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
1345 {
1346     _cmsFree(self ->ContextID, Ptr);
1347 }
1348
1349
1350
1351 // ********************************************************************************
1352 // Type icMeasurementType
1353 // ********************************************************************************
1354
1355 /*
1356 The measurementType information refers only to the internal profile data and is
1357 meant to provide profile makers an alternative to the default measurement
1358 specifications.
1359 */
1360
1361 static
1362 void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1363 {
1364     cmsICCMeasurementConditions mc;
1365
1366         
1367     memset(&mc, 0, sizeof(mc));
1368         
1369     if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
1370     if (!_cmsReadXYZNumber(io,    &mc.Backing)) return NULL;
1371     if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
1372     if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
1373     if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
1374
1375     *nItems = 1;
1376     return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
1377
1378     cmsUNUSED_PARAMETER(SizeOfTag);
1379 }
1380
1381
1382 static
1383 cmsBool  Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1384 {
1385     cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
1386
1387     if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
1388     if (!_cmsWriteXYZNumber(io,    &mc->Backing)) return FALSE;
1389     if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
1390     if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
1391     if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
1392
1393     return TRUE;
1394
1395     cmsUNUSED_PARAMETER(nItems);
1396     cmsUNUSED_PARAMETER(self);
1397 }
1398
1399 static
1400 void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1401 {
1402      return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
1403
1404      cmsUNUSED_PARAMETER(n);
1405 }
1406
1407 static
1408 void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
1409 {
1410    _cmsFree(self ->ContextID, Ptr);
1411 }
1412
1413
1414 // ********************************************************************************
1415 // Type cmsSigMultiLocalizedUnicodeType
1416 // ********************************************************************************
1417 //
1418 //   Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
1419 //   Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
1420 //   taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
1421 //
1422
1423 static
1424 void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1425 {
1426     cmsMLU* mlu;
1427     cmsUInt32Number Count, RecLen, NumOfWchar;
1428     cmsUInt32Number SizeOfHeader;
1429     cmsUInt32Number  Len, Offset;
1430     cmsUInt32Number  i;
1431     wchar_t*         Block;
1432     cmsUInt32Number  BeginOfThisString, EndOfThisString, LargestPosition;
1433
1434     *nItems = 0;
1435     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1436     if (!_cmsReadUInt32Number(io, &RecLen)) return NULL;
1437
1438     if (RecLen != 12) {
1439
1440         cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported.");
1441         return NULL;
1442     }
1443
1444     mlu = cmsMLUalloc(self ->ContextID, Count);
1445     if (mlu == NULL) return NULL;
1446
1447     mlu ->UsedEntries = Count;
1448
1449     SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
1450     LargestPosition = 0;
1451
1452     for (i=0; i < Count; i++) {
1453
1454         if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
1455         if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country))  goto Error;
1456
1457         // Now deal with Len and offset.
1458         if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1459         if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1460
1461         // Check for overflow
1462         if (Offset < (SizeOfHeader + 8)) goto Error;
1463
1464         // True begin of the string
1465         BeginOfThisString = Offset - SizeOfHeader - 8;
1466
1467         // Ajust to wchar_t elements
1468         mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1469         mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1470
1471         // To guess maximum size, add offset + len
1472         EndOfThisString = BeginOfThisString + Len;
1473         if (EndOfThisString > LargestPosition)
1474             LargestPosition = EndOfThisString;
1475     }
1476
1477     // Now read the remaining of tag and fill all strings. Substract the directory
1478     SizeOfTag   = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1479     if (SizeOfTag == 0)
1480     {
1481         Block = NULL;
1482         NumOfWchar = 0;
1483
1484     }
1485     else
1486     {
1487         Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
1488         if (Block == NULL) goto Error;
1489         NumOfWchar = SizeOfTag / sizeof(wchar_t);
1490         if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
1491     }
1492
1493     mlu ->MemPool  = Block;
1494     mlu ->PoolSize = SizeOfTag;
1495     mlu ->PoolUsed = SizeOfTag;
1496
1497     *nItems = 1;
1498     return (void*) mlu;
1499
1500 Error:
1501     if (mlu) cmsMLUfree(mlu);
1502     return NULL;
1503 }
1504
1505 static
1506 cmsBool  Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1507 {
1508     cmsMLU* mlu =(cmsMLU*) Ptr;
1509     cmsUInt32Number HeaderSize;
1510     cmsUInt32Number  Len, Offset;
1511     cmsUInt32Number i;
1512
1513     if (Ptr == NULL) {
1514
1515           // Empty placeholder
1516           if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1517           if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1518           return TRUE;
1519     }
1520
1521     if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1522     if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1523
1524     HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1525
1526     for (i=0; i < mlu ->UsedEntries; i++) {
1527
1528         Len    =  mlu ->Entries[i].Len;
1529         Offset =  mlu ->Entries[i].StrW;
1530
1531         Len    = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
1532         Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
1533
1534         if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
1535         if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country))  return FALSE;
1536         if (!_cmsWriteUInt32Number(io, Len)) return FALSE;
1537         if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
1538     }
1539
1540     if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*)  mlu ->MemPool)) return FALSE;
1541
1542     return TRUE;
1543
1544     cmsUNUSED_PARAMETER(nItems);
1545     cmsUNUSED_PARAMETER(self);
1546 }
1547
1548
1549 static
1550 void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1551 {
1552     return (void*) cmsMLUdup((cmsMLU*) Ptr);
1553
1554     cmsUNUSED_PARAMETER(n);
1555     cmsUNUSED_PARAMETER(self);
1556 }
1557
1558 static
1559 void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
1560 {
1561     cmsMLUfree((cmsMLU*) Ptr);
1562     return;
1563
1564     cmsUNUSED_PARAMETER(self);
1565 }
1566
1567
1568 // ********************************************************************************
1569 // Type cmsSigLut8Type
1570 // ********************************************************************************
1571
1572 // Decide which LUT type to use on writting
1573 static
1574 cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
1575 {
1576     cmsPipeline* Lut = (cmsPipeline*) Data;
1577
1578     if (ICCVersion < 4.0) {
1579         if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1580         return cmsSigLut16Type;
1581     }
1582     else {
1583          return cmsSigLutAtoBType;
1584     }
1585 }
1586
1587 static
1588 cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data)
1589 {
1590     cmsPipeline* Lut = (cmsPipeline*) Data;
1591
1592     if (ICCVersion < 4.0) {
1593         if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1594         return cmsSigLut16Type;
1595     }
1596     else {
1597          return cmsSigLutBtoAType;
1598     }
1599 }
1600
1601 /*
1602 This structure represents a colour transform using tables of 8-bit precision.
1603 This type contains four processing elements: a 3 by 3 matrix (which shall be
1604 the identity matrix unless the input colour space is XYZ), a set of one dimensional
1605 input tables, a multidimensional lookup table, and a set of one dimensional output
1606 tables. Data is processed using these elements via the following sequence:
1607 (matrix) -> (1d input tables)  -> (multidimensional lookup table - CLUT) -> (1d output tables)
1608
1609 Byte Position   Field Length (bytes)  Content Encoded as...
1610 8                  1          Number of Input Channels (i)    uInt8Number
1611 9                  1          Number of Output Channels (o)   uInt8Number
1612 10                 1          Number of CLUT grid points (identical for each side) (g) uInt8Number
1613 11                 1          Reserved for padding (fill with 00h)
1614
1615 12..15             4          Encoded e00 parameter   s15Fixed16Number
1616 */
1617
1618
1619 // Read 8 bit tables as gamma functions
1620 static
1621 cmsBool  Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels)
1622 {
1623     cmsUInt8Number* Temp = NULL;
1624     int i, j;
1625     cmsToneCurve* Tables[cmsMAXCHANNELS];
1626
1627     if (nChannels > cmsMAXCHANNELS) return FALSE;
1628     if (nChannels <= 0) return FALSE;
1629
1630     memset(Tables, 0, sizeof(Tables));
1631
1632     Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256);
1633     if (Temp == NULL) return FALSE;
1634
1635     for (i=0; i < nChannels; i++) {
1636         Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
1637         if (Tables[i] == NULL) goto Error;
1638     }
1639
1640     for (i=0; i < nChannels; i++) {
1641
1642         if (io ->Read(io, Temp, 256, 1) != 1) goto Error;
1643
1644         for (j=0; j < 256; j++)
1645             Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]);
1646     }
1647
1648     _cmsFree(ContextID, Temp);
1649     Temp = NULL;
1650
1651     if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
1652         goto Error;
1653
1654     for (i=0; i < nChannels; i++)
1655         cmsFreeToneCurve(Tables[i]);
1656
1657     return TRUE;
1658
1659 Error:
1660     for (i=0; i < nChannels; i++) {
1661         if (Tables[i]) cmsFreeToneCurve(Tables[i]);
1662     }
1663
1664     if (Temp) _cmsFree(ContextID, Temp);
1665     return FALSE;
1666 }
1667
1668
1669 static
1670 cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables)
1671 {
1672     int j;
1673     cmsUInt32Number i;
1674     cmsUInt8Number val;
1675
1676     for (i=0; i < n; i++) {
1677
1678         if (Tables) {
1679
1680             // Usual case of identity curves
1681             if ((Tables ->TheCurves[i]->nEntries == 2) && 
1682                 (Tables->TheCurves[i]->Table16[0] == 0) && 
1683                 (Tables->TheCurves[i]->Table16[1] == 65535)) {
1684
1685                     for (j=0; j < 256; j++) {
1686                         if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE;
1687                     }
1688             }
1689             else 
1690                 if (Tables ->TheCurves[i]->nEntries != 256) {
1691                     cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization");
1692                     return FALSE;                
1693                 }
1694                 else
1695                     for (j=0; j < 256; j++) {
1696
1697                         val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]);
1698
1699                         if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1700                     }
1701         }
1702     }
1703     return TRUE;
1704 }
1705
1706
1707 // Check overflow
1708 static
1709 cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
1710 {
1711     cmsUInt32Number rv = 1, rc;
1712
1713     if (a == 0) return 0;
1714     if (n == 0) return 0;
1715
1716     for (; b > 0; b--) {
1717
1718         rv *= a;
1719
1720         // Check for overflow
1721         if (rv > UINT_MAX / a) return (cmsUInt32Number) -1;
1722
1723     }
1724
1725     rc = rv * n;
1726
1727     if (rv != rc / n) return (cmsUInt32Number) -1;
1728     return rc;
1729 }
1730
1731
1732 // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
1733 // 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust
1734 // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
1735
1736 static
1737 void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1738 {
1739     cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
1740     cmsUInt8Number* Temp = NULL;
1741     cmsPipeline* NewLUT = NULL;
1742     cmsUInt32Number nTabSize, i;
1743     cmsFloat64Number Matrix[3*3];
1744
1745     *nItems = 0;
1746
1747     if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error;
1748     if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error;
1749     if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error;
1750
1751      if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
1752
1753     // Padding
1754     if (!_cmsReadUInt8Number(io, NULL)) goto Error;
1755
1756     // Do some checking
1757     if (InputChannels > cmsMAXCHANNELS)  goto Error;
1758     if (OutputChannels > cmsMAXCHANNELS) goto Error;
1759
1760    // Allocates an empty Pipeline
1761     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
1762     if (NewLUT == NULL) goto Error;
1763
1764     // Read the Matrix
1765     if (!_cmsRead15Fixed16Number(io,  &Matrix[0])) goto Error;
1766     if (!_cmsRead15Fixed16Number(io,  &Matrix[1])) goto Error;
1767     if (!_cmsRead15Fixed16Number(io,  &Matrix[2])) goto Error;
1768     if (!_cmsRead15Fixed16Number(io,  &Matrix[3])) goto Error;
1769     if (!_cmsRead15Fixed16Number(io,  &Matrix[4])) goto Error;
1770     if (!_cmsRead15Fixed16Number(io,  &Matrix[5])) goto Error;
1771     if (!_cmsRead15Fixed16Number(io,  &Matrix[6])) goto Error;
1772     if (!_cmsRead15Fixed16Number(io,  &Matrix[7])) goto Error;
1773     if (!_cmsRead15Fixed16Number(io,  &Matrix[8])) goto Error;
1774
1775
1776     // Only operates if not identity...
1777     if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
1778
1779         if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
1780             goto Error;
1781     }
1782
1783     // Get input tables
1784     if (!Read8bitTables(self ->ContextID, io,  NewLUT, InputChannels)) goto Error;
1785
1786     // Get 3D CLUT. Check the overflow....
1787     nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
1788     if (nTabSize == (cmsUInt32Number) -1) goto Error;
1789     if (nTabSize > 0) {
1790
1791         cmsUInt16Number *PtrW, *T;
1792        
1793         PtrW = T  = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
1794         if (T  == NULL) goto Error;
1795
1796         Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
1797         if (Temp == NULL) {
1798             _cmsFree(self ->ContextID, T);
1799             goto Error;
1800         }
1801
1802         if (io ->Read(io, Temp, nTabSize, 1) != 1) {
1803             _cmsFree(self ->ContextID, T);
1804             _cmsFree(self ->ContextID, Temp);
1805             goto Error;
1806         }
1807
1808         for (i = 0; i < nTabSize; i++) {
1809
1810             *PtrW++ = FROM_8_TO_16(Temp[i]);
1811         }
1812         _cmsFree(self ->ContextID, Temp);
1813         Temp = NULL;
1814
1815         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T)))
1816             goto Error;
1817         _cmsFree(self ->ContextID, T);
1818     }
1819
1820
1821     // Get output tables
1822     if (!Read8bitTables(self ->ContextID, io,  NewLUT, OutputChannels)) goto Error;
1823
1824     *nItems = 1;
1825     return NewLUT;
1826
1827 Error:
1828     if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1829     return NULL;
1830
1831     cmsUNUSED_PARAMETER(SizeOfTag);
1832 }
1833
1834 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1835 static
1836 cmsBool  Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1837 {
1838     cmsUInt32Number j, nTabSize;
1839     cmsUInt8Number  val;
1840     cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1841     cmsStage* mpe;
1842     _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1843     _cmsStageMatrixData* MatMPE = NULL;
1844     _cmsStageCLutData* clut = NULL;
1845     int clutPoints;
1846
1847     // Disassemble the LUT into components.
1848     mpe = NewLUT -> Elements;
1849     if (mpe ->Type == cmsSigMatrixElemType) {
1850
1851         MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1852         mpe = mpe -> Next;
1853     }
1854
1855     if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1856         PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1857         mpe = mpe -> Next;
1858     }
1859
1860     if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
1861         clut  = (_cmsStageCLutData*) mpe -> Data;
1862         mpe = mpe ->Next;
1863     }
1864
1865     if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1866         PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1867         mpe = mpe -> Next;
1868     }
1869
1870     // That should be all
1871     if (mpe != NULL) {
1872         cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
1873         return FALSE;
1874     }
1875
1876
1877     if (clut == NULL)
1878         clutPoints = 0;
1879     else
1880         clutPoints    = clut->Params->nSamples[0];
1881
1882     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
1883     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
1884     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
1885     if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
1886
1887
1888     if (MatMPE != NULL) {
1889
1890         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
1891         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
1892         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
1893         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
1894         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
1895         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
1896         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
1897         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
1898         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
1899
1900     }
1901     else {
1902
1903         if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1904         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1905         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1906         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1907         if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1908         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1909         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1910         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1911         if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1912     }
1913
1914     // The prelinearization table
1915     if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1916
1917     nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1918     if (nTabSize == (cmsUInt32Number) -1) return FALSE;
1919     if (nTabSize > 0) {
1920
1921         // The 3D CLUT.
1922         if (clut != NULL) {
1923
1924             for (j=0; j < nTabSize; j++) {
1925
1926                 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
1927                 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1928             }
1929         }
1930     }
1931
1932     // The postlinearization table
1933     if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
1934
1935     return TRUE;
1936
1937     cmsUNUSED_PARAMETER(nItems);
1938 }
1939
1940
1941 static
1942 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1943 {
1944     return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
1945
1946     cmsUNUSED_PARAMETER(n);
1947     cmsUNUSED_PARAMETER(self);
1948 }
1949
1950 static
1951 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
1952 {
1953     cmsPipelineFree((cmsPipeline*) Ptr);
1954     return;
1955
1956     cmsUNUSED_PARAMETER(self);
1957 }
1958
1959 // ********************************************************************************
1960 // Type cmsSigLut16Type
1961 // ********************************************************************************
1962
1963 // Read 16 bit tables as gamma functions
1964 static
1965 cmsBool  Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
1966 {
1967     int i;
1968     cmsToneCurve* Tables[cmsMAXCHANNELS];
1969
1970     // Maybe an empty table? (this is a lcms extension)
1971     if (nEntries <= 0) return TRUE;
1972
1973     // Check for malicious profiles
1974     if (nEntries < 2) return FALSE;
1975     if (nChannels > cmsMAXCHANNELS) return FALSE;
1976
1977     // Init table to zero
1978     memset(Tables, 0, sizeof(Tables));
1979
1980     for (i=0; i < nChannels; i++) {
1981
1982         Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
1983         if (Tables[i] == NULL) goto Error;
1984
1985         if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error;
1986     }
1987
1988
1989     // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
1990     if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
1991         goto Error;
1992
1993     for (i=0; i < nChannels; i++)
1994         cmsFreeToneCurve(Tables[i]);
1995
1996     return TRUE;
1997
1998 Error:
1999     for (i=0; i < nChannels; i++) {
2000         if (Tables[i]) cmsFreeToneCurve(Tables[i]);
2001     }
2002
2003     return FALSE;
2004 }
2005
2006 static
2007 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
2008 {
2009     int j;
2010     cmsUInt32Number i;
2011     cmsUInt16Number val;
2012     int nEntries;
2013
2014     _cmsAssert(Tables != NULL);
2015
2016     nEntries = Tables->TheCurves[0]->nEntries;
2017
2018     for (i=0; i < Tables ->nCurves; i++) {
2019
2020         for (j=0; j < nEntries; j++) {
2021
2022             val = Tables->TheCurves[i]->Table16[j];        
2023             if (!_cmsWriteUInt16Number(io, val)) return FALSE;
2024         }
2025     }
2026     return TRUE;
2027
2028     cmsUNUSED_PARAMETER(ContextID);
2029 }
2030
2031 static
2032 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2033 {
2034     cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
2035     cmsPipeline* NewLUT = NULL;
2036     cmsUInt32Number nTabSize;
2037     cmsFloat64Number Matrix[3*3];
2038     cmsUInt16Number InputEntries, OutputEntries;
2039
2040     *nItems = 0;
2041
2042     if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
2043     if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
2044     if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL;   // 255 maximum
2045
2046     // Padding
2047     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2048
2049     // Do some checking
2050     if (InputChannels > cmsMAXCHANNELS)  goto Error;
2051     if (OutputChannels > cmsMAXCHANNELS) goto Error;
2052
2053     // Allocates an empty LUT
2054     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
2055     if (NewLUT == NULL) goto Error;
2056
2057     // Read the Matrix
2058     if (!_cmsRead15Fixed16Number(io,  &Matrix[0])) goto Error;
2059     if (!_cmsRead15Fixed16Number(io,  &Matrix[1])) goto Error;
2060     if (!_cmsRead15Fixed16Number(io,  &Matrix[2])) goto Error;
2061     if (!_cmsRead15Fixed16Number(io,  &Matrix[3])) goto Error;
2062     if (!_cmsRead15Fixed16Number(io,  &Matrix[4])) goto Error;
2063     if (!_cmsRead15Fixed16Number(io,  &Matrix[5])) goto Error;
2064     if (!_cmsRead15Fixed16Number(io,  &Matrix[6])) goto Error;
2065     if (!_cmsRead15Fixed16Number(io,  &Matrix[7])) goto Error;
2066     if (!_cmsRead15Fixed16Number(io,  &Matrix[8])) goto Error;
2067
2068
2069     // Only operates on 3 channels
2070     if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
2071
2072         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
2073             goto Error;
2074     }
2075
2076     if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error;
2077     if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error;
2078
2079     if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error;
2080     if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
2081
2082     // Get input tables
2083     if (!Read16bitTables(self ->ContextID, io,  NewLUT, InputChannels, InputEntries)) goto Error;
2084
2085     // Get 3D CLUT
2086     nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
2087     if (nTabSize == (cmsUInt32Number) -1) goto Error;
2088     if (nTabSize > 0) {
2089
2090         cmsUInt16Number *T;
2091
2092         T  = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
2093         if (T  == NULL) goto Error;
2094
2095         if (!_cmsReadUInt16Array(io, nTabSize, T)) {
2096             _cmsFree(self ->ContextID, T);
2097             goto Error;
2098         }
2099
2100         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
2101             _cmsFree(self ->ContextID, T);
2102             goto Error;
2103         }
2104         _cmsFree(self ->ContextID, T);
2105     }
2106
2107
2108     // Get output tables
2109     if (!Read16bitTables(self ->ContextID, io,  NewLUT, OutputChannels, OutputEntries)) goto Error;
2110
2111     *nItems = 1;
2112     return NewLUT;
2113
2114 Error:
2115     if (NewLUT != NULL) cmsPipelineFree(NewLUT);
2116     return NULL;
2117
2118     cmsUNUSED_PARAMETER(SizeOfTag);
2119 }
2120
2121 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2122 // Some empty defaults are created for missing parts
2123
2124 static
2125 cmsBool  Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2126 {
2127     cmsUInt32Number nTabSize;
2128     cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2129     cmsStage* mpe;
2130     _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2131     _cmsStageMatrixData* MatMPE = NULL;
2132     _cmsStageCLutData* clut = NULL;
2133     int i, InputChannels, OutputChannels, clutPoints;
2134
2135     // Disassemble the LUT into components.
2136     mpe = NewLUT -> Elements;
2137     if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2138
2139         MatMPE = (_cmsStageMatrixData*) mpe ->Data;
2140         mpe = mpe -> Next;
2141     }
2142
2143
2144     if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2145         PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2146         mpe = mpe -> Next;
2147     }
2148
2149     if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
2150         clut  = (_cmsStageCLutData*) mpe -> Data;
2151         mpe = mpe ->Next;
2152     }
2153
2154     if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2155         PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2156         mpe = mpe -> Next;
2157     }
2158
2159     // That should be all
2160     if (mpe != NULL) {
2161         cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
2162         return FALSE;
2163     }
2164
2165     InputChannels  = cmsPipelineInputChannels(NewLUT);
2166     OutputChannels = cmsPipelineOutputChannels(NewLUT);
2167
2168     if (clut == NULL)
2169         clutPoints = 0;
2170     else
2171         clutPoints    = clut->Params->nSamples[0];
2172
2173     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
2174     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
2175     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
2176     if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
2177
2178
2179     if (MatMPE != NULL) {
2180
2181         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
2182         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
2183         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
2184         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
2185         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
2186         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
2187         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
2188         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
2189         if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
2190     }
2191     else {
2192
2193         if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2194         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2195         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2196         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2197         if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2198         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2199         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2200         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2201         if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2202     }
2203
2204
2205     if (PreMPE != NULL) {
2206         if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
2207     } else {
2208             if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2209     }
2210
2211     if (PostMPE != NULL) {
2212         if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE;
2213     } else {
2214         if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2215
2216     }
2217
2218     // The prelinearization table
2219
2220     if (PreMPE != NULL) {
2221         if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
2222     }
2223     else {
2224         for (i=0; i < InputChannels; i++) {
2225
2226             if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2227             if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2228         }
2229     }
2230
2231     nTabSize = uipow(OutputChannels, clutPoints, InputChannels);
2232     if (nTabSize == (cmsUInt32Number) -1) return FALSE;
2233     if (nTabSize > 0) {
2234         // The 3D CLUT.
2235         if (clut != NULL) {
2236             if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
2237         }
2238     }
2239
2240     // The postlinearization table
2241     if (PostMPE != NULL) {
2242         if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
2243     }
2244     else {
2245         for (i=0; i < OutputChannels; i++) {
2246
2247             if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2248             if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2249         }
2250     }
2251
2252     return TRUE;
2253
2254     cmsUNUSED_PARAMETER(nItems);
2255 }
2256
2257 static
2258 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2259 {
2260     return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2261
2262     cmsUNUSED_PARAMETER(n);
2263     cmsUNUSED_PARAMETER(self);
2264 }
2265
2266 static
2267 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
2268 {
2269     cmsPipelineFree((cmsPipeline*) Ptr);
2270     return;
2271
2272     cmsUNUSED_PARAMETER(self);
2273 }
2274
2275
2276 // ********************************************************************************
2277 // Type cmsSigLutAToBType
2278 // ********************************************************************************
2279
2280
2281 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2282
2283 static
2284 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
2285 {
2286     cmsFloat64Number dMat[3*3];
2287     cmsFloat64Number dOff[3];
2288     cmsStage* Mat;
2289
2290     // Go to address
2291     if (!io -> Seek(io, Offset)) return NULL;
2292
2293     // Read the Matrix
2294     if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL;
2295     if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL;
2296     if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL;
2297     if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL;
2298     if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL;
2299     if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL;
2300     if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL;
2301     if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL;
2302     if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL;
2303
2304     if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL;
2305     if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL;
2306     if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL;
2307
2308     Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff);
2309
2310      return Mat;
2311 }
2312
2313
2314
2315
2316 //  V4 stuff. Read CLUT part for LutAtoB and LutBtoA
2317
2318 static
2319 cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels)
2320 {
2321     cmsUInt8Number  gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2322     cmsUInt32Number GridPoints[cmsMAXCHANNELS], i;
2323     cmsUInt8Number  Precision;
2324     cmsStage* CLUT;
2325     _cmsStageCLutData* Data;
2326
2327     if (!io -> Seek(io, Offset)) return NULL;
2328     if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL;
2329
2330
2331     for (i=0; i < cmsMAXCHANNELS; i++) {
2332
2333         if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least
2334         GridPoints[i] = gridPoints8[i];
2335     }
2336
2337     if (!_cmsReadUInt8Number(io, &Precision)) return NULL;
2338
2339     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2340     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2341     if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2342
2343     CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL);
2344     if (CLUT == NULL) return NULL;
2345
2346     Data = (_cmsStageCLutData*) CLUT ->Data;
2347
2348     // Precision can be 1 or 2 bytes
2349     if (Precision == 1) {
2350
2351         cmsUInt8Number  v;
2352
2353         for (i=0; i < Data ->nEntries; i++) {
2354
2355             if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
2356             Data ->Tab.T[i] = FROM_8_TO_16(v);
2357         }
2358
2359     }
2360     else
2361         if (Precision == 2) {
2362
2363             if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) {
2364                 cmsStageFree(CLUT);
2365                 return NULL;
2366             }
2367         }
2368         else {
2369             cmsStageFree(CLUT);
2370             cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2371             return NULL;
2372         }
2373
2374         return CLUT;
2375 }
2376
2377 static
2378 cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
2379 {
2380     cmsTagTypeSignature  BaseType;
2381     cmsUInt32Number nItems;
2382
2383     BaseType = _cmsReadTypeBase(io);
2384     switch (BaseType) {
2385
2386             case cmsSigCurveType:
2387                 return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0);
2388
2389             case cmsSigParametricCurveType:
2390                 return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0);
2391
2392             default:
2393                 {
2394                     char String[5];
2395
2396                     _cmsTagSignature2String(String, (cmsTagSignature) BaseType);
2397                     cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2398                 }
2399                 return NULL;
2400     }
2401 }
2402
2403
2404 // Read a set of curves from specific offset
2405 static
2406 cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves)
2407 {
2408     cmsToneCurve* Curves[cmsMAXCHANNELS];
2409     cmsUInt32Number i;
2410     cmsStage* Lin = NULL;
2411
2412     if (nCurves > cmsMAXCHANNELS) return FALSE;
2413
2414     if (!io -> Seek(io, Offset)) return FALSE;
2415
2416     for (i=0; i < nCurves; i++)
2417         Curves[i] = NULL;
2418
2419     for (i=0; i < nCurves; i++) {
2420
2421         Curves[i] = ReadEmbeddedCurve(self, io);
2422         if (Curves[i] == NULL) goto Error;
2423         if (!_cmsReadAlignment(io)) goto Error;
2424
2425     }
2426
2427     Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves);
2428
2429 Error:
2430     for (i=0; i < nCurves; i++)
2431         cmsFreeToneCurve(Curves[i]);
2432
2433     return Lin;
2434 }
2435
2436
2437 // LutAtoB type
2438
2439 // This structure represents a colour transform. The type contains up to five processing
2440 // elements which are stored in the AtoBTag tag in the following order: a set of one
2441 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
2442 // a multidimensional lookup table, and a set of one dimensional output curves.
2443 // Data are processed using these elements via the following sequence:
2444 //
2445 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
2446 //
2447 /*
2448 It is possible to use any or all of these processing elements. At least one processing element
2449 must be included.Only the following combinations are allowed:
2450
2451 B
2452 M - Matrix - B
2453 A - CLUT - B
2454 A - CLUT - M - Matrix - B
2455
2456 */
2457
2458 static
2459 void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2460 {
2461     cmsUInt32Number      BaseOffset;
2462     cmsUInt8Number       inputChan;      // Number of input channels
2463     cmsUInt8Number       outputChan;     // Number of output channels
2464     cmsUInt32Number      offsetB;        // Offset to first "B" curve
2465     cmsUInt32Number      offsetMat;      // Offset to matrix
2466     cmsUInt32Number      offsetM;        // Offset to first "M" curve
2467     cmsUInt32Number      offsetC;        // Offset to CLUT
2468     cmsUInt32Number      offsetA;        // Offset to first "A" curve
2469     cmsPipeline* NewLUT = NULL;
2470
2471
2472     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2473
2474     if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2475     if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2476
2477     if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2478
2479     if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2480     if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2481     if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2482     if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2483     if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2484
2485    // Allocates an empty LUT
2486     NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2487     if (NewLUT == NULL) return NULL;
2488
2489     if (offsetA!= 0) {
2490         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan)))
2491             goto Error;
2492     }
2493
2494     if (offsetC != 0) {
2495         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2496             goto Error;
2497     }
2498
2499     if (offsetM != 0) {
2500         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
2501             goto Error;
2502     }
2503
2504     if (offsetMat != 0) {
2505         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2506             goto Error;
2507     }
2508
2509     if (offsetB != 0) {
2510         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
2511             goto Error;
2512     }
2513
2514     *nItems = 1;
2515     return NewLUT;
2516 Error:
2517     cmsPipelineFree(NewLUT);
2518     return NULL;
2519
2520     cmsUNUSED_PARAMETER(SizeOfTag);
2521 }
2522
2523 // Write a set of curves
2524 static
2525 cmsBool  WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2526 {
2527     _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2528
2529     // Write the Matrix
2530     if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
2531     if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
2532     if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
2533     if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
2534     if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
2535     if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
2536     if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
2537     if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
2538     if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
2539
2540     if (m ->Offset != NULL) {
2541
2542     if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
2543     if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
2544     if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
2545     }
2546     else {
2547         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2548         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2549         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2550
2551     }
2552
2553
2554     return TRUE;
2555
2556     cmsUNUSED_PARAMETER(self);
2557 }
2558
2559
2560 // Write a set of curves
2561 static
2562 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2563 {
2564     cmsUInt32Number i, n;
2565     cmsTagTypeSignature CurrentType;
2566     cmsToneCurve** Curves;
2567
2568
2569     n      = cmsStageOutputChannels(mpe);
2570     Curves = _cmsStageGetPtrToCurveSet(mpe);
2571
2572     for (i=0; i < n; i++) {
2573
2574         // If this is a table-based curve, use curve type even on V4
2575         CurrentType = Type;
2576
2577         if ((Curves[i] ->nSegments == 0)||
2578             ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) )
2579             CurrentType = cmsSigCurveType;
2580         else
2581         if (Curves[i] ->Segments[0].Type < 0)
2582             CurrentType = cmsSigCurveType;
2583
2584         if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE;
2585
2586         switch (CurrentType) {
2587
2588             case cmsSigCurveType:
2589                 if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE;
2590                 break;
2591
2592             case cmsSigParametricCurveType:
2593                 if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE;
2594                 break;
2595
2596             default:
2597                 {
2598                     char String[5];
2599
2600                     _cmsTagSignature2String(String, (cmsTagSignature) Type);
2601                     cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2602                 }
2603                 return FALSE;
2604         }
2605
2606         if (!_cmsWriteAlignment(io)) return FALSE;
2607     }
2608
2609
2610     return TRUE;
2611 }
2612
2613
2614 static
2615 cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number  Precision, cmsStage* mpe)
2616 {
2617     cmsUInt8Number  gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2618     cmsUInt32Number i;
2619     _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data;
2620
2621     if (CLUT ->HasFloatValues) {
2622          cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only");
2623          return FALSE;
2624     }
2625
2626     memset(gridPoints, 0, sizeof(gridPoints));
2627     for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++)
2628         gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i];
2629
2630     if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE;
2631
2632     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE;
2633     if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2634     if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2635     if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2636
2637     // Precision can be 1 or 2 bytes
2638     if (Precision == 1) {
2639
2640         for (i=0; i < CLUT->nEntries; i++) {
2641
2642             if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE;
2643         }
2644     }
2645     else
2646         if (Precision == 2) {
2647
2648             if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE;
2649         }
2650         else {
2651              cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2652             return FALSE;
2653         }
2654
2655         if (!_cmsWriteAlignment(io)) return FALSE;
2656
2657         return TRUE;
2658 }
2659
2660
2661
2662
2663 static
2664 cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2665 {
2666     cmsPipeline* Lut = (cmsPipeline*) Ptr;
2667     int inputChan, outputChan;
2668     cmsStage *A = NULL, *B = NULL, *M = NULL;
2669     cmsStage * Matrix = NULL;
2670     cmsStage * CLUT = NULL;
2671     cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2672     cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2673
2674     // Get the base for all offsets
2675     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2676
2677     if (Lut ->Elements != NULL)
2678         if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2679             if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B))
2680                 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B))
2681                     if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType,
2682                         cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) {
2683
2684                             cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB");
2685                             return FALSE;
2686                     }
2687
2688     // Get input, output channels
2689     inputChan  = cmsPipelineInputChannels(Lut);
2690     outputChan = cmsPipelineOutputChannels(Lut);
2691
2692     // Write channel count
2693     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2694     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2695     if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2696
2697     // Keep directory to be filled latter
2698     DirectoryPos = io ->Tell(io);
2699
2700     // Write the directory
2701     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2702     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2703     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2704     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2705     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2706
2707     if (A != NULL) {
2708
2709         offsetA = io ->Tell(io) - BaseOffset;
2710         if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2711     }
2712
2713     if (CLUT != NULL) {
2714         offsetC = io ->Tell(io) - BaseOffset;
2715         if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
2716
2717     }
2718     if (M != NULL) {
2719
2720         offsetM = io ->Tell(io) - BaseOffset;
2721         if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2722     }
2723
2724     if (Matrix != NULL) {
2725         offsetMat = io ->Tell(io) - BaseOffset;
2726         if (!WriteMatrix(self, io, Matrix)) return FALSE;
2727     }
2728
2729     if (B != NULL) {
2730
2731         offsetB = io ->Tell(io) - BaseOffset;
2732         if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2733     }
2734
2735     CurrentPos = io ->Tell(io);
2736
2737     if (!io ->Seek(io, DirectoryPos)) return FALSE;
2738
2739     if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2740     if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2741     if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2742     if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2743     if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2744
2745     if (!io ->Seek(io, CurrentPos)) return FALSE;
2746
2747     return TRUE;
2748
2749     cmsUNUSED_PARAMETER(nItems);
2750 }
2751
2752
2753 static
2754 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2755 {
2756     return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2757
2758     cmsUNUSED_PARAMETER(n);
2759     cmsUNUSED_PARAMETER(self);
2760 }
2761
2762 static
2763 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
2764 {
2765     cmsPipelineFree((cmsPipeline*) Ptr);
2766     return;
2767
2768     cmsUNUSED_PARAMETER(self);
2769 }
2770
2771
2772 // LutBToA type
2773
2774 static
2775 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2776 {
2777     cmsUInt8Number       inputChan;      // Number of input channels
2778     cmsUInt8Number       outputChan;     // Number of output channels
2779     cmsUInt32Number      BaseOffset;     // Actual position in file
2780     cmsUInt32Number      offsetB;        // Offset to first "B" curve
2781     cmsUInt32Number      offsetMat;      // Offset to matrix
2782     cmsUInt32Number      offsetM;        // Offset to first "M" curve
2783     cmsUInt32Number      offsetC;        // Offset to CLUT
2784     cmsUInt32Number      offsetA;        // Offset to first "A" curve
2785     cmsPipeline* NewLUT = NULL;
2786
2787
2788     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2789
2790     if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2791     if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2792
2793     // Padding
2794     if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2795
2796     if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2797     if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2798     if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2799     if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2800     if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2801
2802     // Allocates an empty LUT
2803     NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2804     if (NewLUT == NULL) return NULL;
2805
2806     if (offsetB != 0) {
2807         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan)))
2808             goto Error;
2809     }
2810
2811     if (offsetMat != 0) {
2812         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2813             goto Error;
2814     }
2815
2816     if (offsetM != 0) {
2817         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan)))
2818             goto Error;
2819     }
2820
2821     if (offsetC != 0) {
2822         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2823             goto Error;
2824     }
2825
2826     if (offsetA!= 0) {
2827         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan)))
2828             goto Error;
2829     }
2830
2831     *nItems = 1;
2832     return NewLUT;
2833 Error:
2834     cmsPipelineFree(NewLUT);
2835     return NULL;
2836
2837     cmsUNUSED_PARAMETER(SizeOfTag);
2838 }
2839
2840
2841 /*
2842 B
2843 B - Matrix - M
2844 B - CLUT - A
2845 B - Matrix - M - CLUT - A
2846 */
2847
2848 static
2849 cmsBool  Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2850 {
2851     cmsPipeline* Lut = (cmsPipeline*) Ptr;
2852     int inputChan, outputChan;
2853     cmsStage *A = NULL, *B = NULL, *M = NULL;
2854     cmsStage *Matrix = NULL;
2855     cmsStage *CLUT = NULL;
2856     cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2857     cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2858
2859
2860     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2861
2862     if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2863         if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M))
2864             if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A))
2865                 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
2866                     cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) {
2867                         cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA");
2868                         return FALSE;
2869                 }
2870
2871     inputChan  = cmsPipelineInputChannels(Lut);
2872     outputChan = cmsPipelineOutputChannels(Lut);
2873
2874     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2875     if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2876     if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2877
2878     DirectoryPos = io ->Tell(io);
2879
2880     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2881     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2882     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2883     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2884     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2885
2886     if (A != NULL) {
2887
2888         offsetA = io ->Tell(io) - BaseOffset;
2889         if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2890     }
2891
2892     if (CLUT != NULL) {
2893         offsetC = io ->Tell(io) - BaseOffset;
2894         if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
2895
2896     }
2897     if (M != NULL) {
2898
2899         offsetM = io ->Tell(io) - BaseOffset;
2900         if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2901     }
2902
2903     if (Matrix != NULL) {
2904         offsetMat = io ->Tell(io) - BaseOffset;
2905         if (!WriteMatrix(self, io, Matrix)) return FALSE;
2906     }
2907
2908     if (B != NULL) {
2909
2910         offsetB = io ->Tell(io) - BaseOffset;
2911         if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2912     }
2913
2914     CurrentPos = io ->Tell(io);
2915
2916     if (!io ->Seek(io, DirectoryPos)) return FALSE;
2917
2918     if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2919     if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2920     if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2921     if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2922     if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2923
2924     if (!io ->Seek(io, CurrentPos)) return FALSE;
2925
2926     return TRUE;
2927
2928     cmsUNUSED_PARAMETER(nItems);
2929 }
2930
2931
2932
2933 static
2934 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2935 {
2936     return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2937
2938     cmsUNUSED_PARAMETER(n);
2939     cmsUNUSED_PARAMETER(self);
2940 }
2941
2942 static
2943 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
2944 {
2945     cmsPipelineFree((cmsPipeline*) Ptr);
2946     return;
2947
2948     cmsUNUSED_PARAMETER(self);
2949 }
2950
2951
2952
2953 // ********************************************************************************
2954 // Type cmsSigColorantTableType
2955 // ********************************************************************************
2956 /*
2957 The purpose of this tag is to identify the colorants used in the profile by a
2958 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
2959 value. The first colorant listed is the colorant of the first device channel of
2960 a lut tag. The second colorant listed is the colorant of the second device channel
2961 of a lut tag, and so on.
2962 */
2963
2964 static
2965 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2966 {
2967     cmsUInt32Number i, Count;
2968     cmsNAMEDCOLORLIST* List;
2969     char Name[34];
2970     cmsUInt16Number PCS[3];
2971
2972
2973     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
2974
2975     if (Count > cmsMAXCHANNELS) {
2976         cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count);
2977         return NULL;
2978     }
2979
2980     List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
2981     for (i=0; i < Count; i++) {
2982
2983         if (io ->Read(io, Name, 32, 1) != 1) goto Error;
2984         Name[33] = 0;
2985
2986         if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
2987
2988         if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
2989
2990     }
2991
2992     *nItems = 1;
2993     return List;
2994
2995 Error:
2996     *nItems = 0;
2997     cmsFreeNamedColorList(List);
2998     return NULL;
2999
3000     cmsUNUSED_PARAMETER(SizeOfTag);
3001 }
3002
3003
3004
3005 // Saves a colorant table. It is using the named color structure for simplicity sake
3006 static
3007 cmsBool  Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3008 {
3009     cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3010     int i, nColors;
3011
3012     nColors = cmsNamedColorCount(NamedColorList);
3013
3014     if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3015
3016     for (i=0; i < nColors; i++) {
3017
3018         char root[33];
3019         cmsUInt16Number PCS[3];
3020
3021         if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
3022         root[32] = 0;
3023
3024         if (!io ->Write(io, 32, root)) return FALSE;
3025         if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3026     }
3027
3028     return TRUE;
3029
3030     cmsUNUSED_PARAMETER(nItems);
3031     cmsUNUSED_PARAMETER(self);
3032 }
3033
3034
3035 static
3036 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3037 {
3038     cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3039     return (void*) cmsDupNamedColorList(nc);
3040
3041     cmsUNUSED_PARAMETER(n);
3042     cmsUNUSED_PARAMETER(self);
3043 }
3044
3045
3046 static
3047 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3048 {
3049     cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3050     return;
3051
3052     cmsUNUSED_PARAMETER(self);
3053 }
3054
3055
3056 // ********************************************************************************
3057 // Type cmsSigNamedColor2Type
3058 // ********************************************************************************
3059 //
3060 //The namedColor2Type is a count value and array of structures that provide color
3061 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3062 //device representation of the color are given. Both representations are 16-bit values.
3063 //The device representation corresponds to the header�s ï¿½color space of data� field.
3064 //This representation should be consistent with the ï¿½number of device components�
3065 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3066 //The PCS representation corresponds to the header�s PCS field. The PCS representation
3067 //is always provided. Color names are fixed-length, 32-byte fields including null
3068 //termination. In order to maintain maximum portability, it is strongly recommended
3069 //that special characters of the 7-bit ASCII set not be used.
3070
3071 static
3072 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3073 {
3074
3075     cmsUInt32Number      vendorFlag;     // Bottom 16 bits for ICC use
3076     cmsUInt32Number      count;          // Count of named colors
3077     cmsUInt32Number      nDeviceCoords;  // Num of device coordinates
3078     char                 prefix[32];     // Prefix for each color name
3079     char                 suffix[32];     // Suffix for each color name
3080     cmsNAMEDCOLORLIST*  v;
3081     cmsUInt32Number i;
3082
3083
3084     *nItems = 0;
3085     if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
3086     if (!_cmsReadUInt32Number(io, &count)) return NULL;
3087     if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL;
3088
3089     if (io -> Read(io, prefix, 32, 1) != 1) return NULL;
3090     if (io -> Read(io, suffix, 32, 1) != 1) return NULL;
3091
3092     prefix[31] = suffix[31] = 0;
3093
3094     v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
3095     if (v == NULL) {
3096         cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
3097         return NULL;
3098     }
3099
3100     if (nDeviceCoords > cmsMAXCHANNELS) {
3101         cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
3102         return 0;
3103     }
3104     for (i=0; i < count; i++) {
3105
3106         cmsUInt16Number PCS[3];
3107         cmsUInt16Number Colorant[cmsMAXCHANNELS];
3108         char Root[33];
3109
3110         memset(Colorant, 0, sizeof(Colorant));
3111         if (io -> Read(io, Root, 32, 1) != 1) return NULL;
3112         Root[32] = 0;  // To prevent exploits
3113
3114         if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3115         if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3116
3117         if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3118     }
3119
3120     *nItems = 1;
3121     return (void*) v ;
3122
3123 Error:
3124     cmsFreeNamedColorList(v);
3125     return NULL;
3126
3127     cmsUNUSED_PARAMETER(SizeOfTag);
3128 }
3129
3130
3131 // Saves a named color list into a named color profile
3132 static
3133 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3134 {
3135     cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3136     char                prefix[33];     // Prefix for each color name
3137     char                suffix[33];     // Suffix for each color name
3138     int i, nColors;
3139
3140     nColors = cmsNamedColorCount(NamedColorList);
3141
3142     if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3143     if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3144     if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3145
3146     strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
3147     strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
3148
3149     suffix[32] = prefix[32] = 0;
3150
3151     if (!io ->Write(io, 32, prefix)) return FALSE;
3152     if (!io ->Write(io, 32, suffix)) return FALSE;
3153
3154     for (i=0; i < nColors; i++) {
3155
3156        cmsUInt16Number PCS[3];
3157        cmsUInt16Number Colorant[cmsMAXCHANNELS];
3158        char Root[33];
3159
3160         if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3161         Root[32] = 0;
3162         if (!io ->Write(io, 32 , Root)) return FALSE;
3163         if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3164         if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3165     }
3166
3167     return TRUE;
3168
3169     cmsUNUSED_PARAMETER(nItems);
3170     cmsUNUSED_PARAMETER(self);
3171 }
3172
3173 static
3174 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3175 {
3176     cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3177
3178     return (void*) cmsDupNamedColorList(nc);
3179
3180     cmsUNUSED_PARAMETER(n);
3181     cmsUNUSED_PARAMETER(self);
3182 }
3183
3184
3185 static
3186 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
3187 {
3188     cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3189     return;
3190
3191     cmsUNUSED_PARAMETER(self);
3192 }
3193
3194
3195 // ********************************************************************************
3196 // Type cmsSigProfileSequenceDescType
3197 // ********************************************************************************
3198
3199 // This type is an array of structures, each of which contains information from the
3200 // header fields and tags from the original profiles which were combined to create
3201 // the final profile. The order of the structures is the order in which the profiles
3202 // were combined and includes a structure for the final profile. This provides a
3203 // description of the profile sequence from source to destination,
3204 // typically used with the DeviceLink profile.
3205
3206 static
3207 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
3208 {
3209     cmsTagTypeSignature  BaseType;
3210     cmsUInt32Number nItems;
3211
3212     BaseType = _cmsReadTypeBase(io);
3213
3214     switch (BaseType) {
3215
3216        case cmsSigTextType:
3217            if (*mlu) cmsMLUfree(*mlu);
3218            *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag);
3219            return (*mlu != NULL);
3220
3221        case cmsSigTextDescriptionType:
3222            if (*mlu) cmsMLUfree(*mlu);
3223            *mlu =  (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag);
3224            return (*mlu != NULL);
3225
3226            /*
3227            TBD: Size is needed for MLU, and we have no idea on which is the available size
3228            */
3229
3230        case cmsSigMultiLocalizedUnicodeType:
3231            if (*mlu) cmsMLUfree(*mlu);
3232            *mlu =  (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag);
3233            return (*mlu != NULL);
3234
3235        default: return FALSE;
3236     }
3237 }
3238
3239
3240 static
3241 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3242 {
3243     cmsSEQ* OutSeq;
3244     cmsUInt32Number i, Count;
3245
3246     *nItems = 0;
3247
3248     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3249
3250     if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3251     SizeOfTag -= sizeof(cmsUInt32Number);
3252
3253
3254     OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3255     if (OutSeq == NULL) return NULL;
3256
3257     OutSeq ->n = Count;
3258
3259     // Get structures as well
3260
3261     for (i=0; i < Count; i++) {
3262
3263         cmsPSEQDESC* sec = &OutSeq -> seq[i];
3264
3265         if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error;
3266         if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3267         SizeOfTag -= sizeof(cmsUInt32Number);
3268
3269         if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error;
3270         if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3271         SizeOfTag -= sizeof(cmsUInt32Number);
3272
3273         if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error;
3274         if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error;
3275         SizeOfTag -= sizeof(cmsUInt64Number);
3276
3277         if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error;
3278         if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3279         SizeOfTag -= sizeof(cmsUInt32Number);
3280
3281         if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error;
3282         if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error;
3283     }
3284
3285     *nItems = 1;
3286     return OutSeq;
3287
3288 Error:
3289     cmsFreeProfileSequenceDescription(OutSeq);
3290     return NULL;
3291 }
3292
3293
3294 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
3295 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack
3296 static
3297 cmsBool  SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text)
3298 {
3299     if (self ->ICCVersion < 0x4000000) {
3300
3301         if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
3302         return Type_Text_Description_Write(self, io, Text, 1);
3303     }
3304     else {
3305         if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE;
3306         return Type_MLU_Write(self, io, Text, 1);
3307     }
3308 }
3309
3310
3311 static
3312 cmsBool  Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3313 {
3314     cmsSEQ* Seq = (cmsSEQ*) Ptr;
3315     cmsUInt32Number i;
3316
3317     if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
3318
3319     for (i=0; i < Seq ->n; i++) {
3320
3321         cmsPSEQDESC* sec = &Seq -> seq[i];
3322
3323         if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
3324         if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
3325         if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE;
3326         if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
3327
3328         if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
3329         if (!SaveDescription(self, io, sec ->Model)) return FALSE;
3330     }
3331
3332      return TRUE;
3333
3334      cmsUNUSED_PARAMETER(nItems);
3335 }
3336
3337
3338 static
3339 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3340 {
3341     return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3342
3343     cmsUNUSED_PARAMETER(n);
3344     cmsUNUSED_PARAMETER(self);
3345 }
3346
3347 static
3348 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
3349 {
3350     cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3351     return;
3352
3353     cmsUNUSED_PARAMETER(self);
3354 }
3355
3356
3357 // ********************************************************************************
3358 // Type cmsSigProfileSequenceIdType
3359 // ********************************************************************************
3360 /*
3361 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3362 original profiles that were combined to create the Device Link Profile.
3363 This type is an array of structures, each of which contains information for
3364 identification of a profile used in a sequence
3365 */
3366
3367
3368 static
3369 cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
3370                                              cmsIOHANDLER* io,
3371                                              void* Cargo,
3372                                              cmsUInt32Number n,
3373                                              cmsUInt32Number SizeOfTag)
3374 {
3375     cmsSEQ* OutSeq = (cmsSEQ*) Cargo;
3376     cmsPSEQDESC* seq = &OutSeq ->seq[n];
3377
3378     if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE;
3379     if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE;
3380
3381     return TRUE;
3382 }
3383
3384
3385
3386 static
3387 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3388 {
3389     cmsSEQ* OutSeq;
3390     cmsUInt32Number Count;
3391     cmsUInt32Number BaseOffset;
3392
3393     *nItems = 0;
3394
3395     // Get actual position as a basis for element offsets
3396     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3397
3398     // Get table count
3399     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3400     SizeOfTag -= sizeof(cmsUInt32Number);
3401
3402     // Allocate an empty structure
3403     OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3404     if (OutSeq == NULL) return NULL;
3405
3406
3407     // Read the position table
3408     if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) {
3409
3410         cmsFreeProfileSequenceDescription(OutSeq);
3411         return NULL;
3412     }
3413
3414     // Success
3415     *nItems = 1;
3416     return OutSeq;
3417
3418 }
3419
3420
3421 static
3422 cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
3423                                              cmsIOHANDLER* io,
3424                                              void* Cargo,
3425                                              cmsUInt32Number n,
3426                                              cmsUInt32Number SizeOfTag)
3427 {
3428     cmsSEQ* Seq = (cmsSEQ*) Cargo;
3429
3430     if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
3431
3432     // Store here the MLU
3433     if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
3434
3435     return TRUE;
3436
3437     cmsUNUSED_PARAMETER(SizeOfTag);
3438 }
3439
3440 static
3441 cmsBool  Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3442 {
3443     cmsSEQ* Seq = (cmsSEQ*) Ptr;
3444     cmsUInt32Number BaseOffset;
3445
3446     // Keep the base offset
3447     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3448
3449     // This is the table count
3450     if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
3451
3452     // This is the position table and content
3453     if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
3454
3455     return TRUE;
3456
3457     cmsUNUSED_PARAMETER(nItems);
3458 }
3459
3460 static
3461 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3462 {
3463     return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3464
3465     cmsUNUSED_PARAMETER(n);
3466     cmsUNUSED_PARAMETER(self);
3467 }
3468
3469 static
3470 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
3471 {
3472     cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3473     return;
3474
3475     cmsUNUSED_PARAMETER(self);
3476 }
3477
3478
3479 // ********************************************************************************
3480 // Type cmsSigUcrBgType
3481 // ********************************************************************************
3482 /*
3483 This type contains curves representing the under color removal and black
3484 generation and a text string which is a general description of the method used
3485 for the ucr/bg.
3486 */
3487
3488 static
3489 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3490 {
3491     cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3492     cmsUInt32Number CountUcr, CountBg;
3493     char* ASCIIString;
3494
3495     *nItems = 0;
3496     if (n == NULL) return NULL;
3497
3498     // First curve is Under color removal
3499     if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
3500     if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3501     SizeOfTag -= sizeof(cmsUInt32Number);
3502
3503     n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
3504     if (n ->Ucr == NULL) return NULL;
3505
3506     if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL;
3507     if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3508     SizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
3509
3510     // Second curve is Black generation
3511     if (!_cmsReadUInt32Number(io, &CountBg)) return NULL;
3512     if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3513     SizeOfTag -= sizeof(cmsUInt32Number);
3514
3515     n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
3516     if (n ->Bg == NULL) return NULL;
3517     if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL;
3518     if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL;
3519     SizeOfTag -= CountBg * sizeof(cmsUInt16Number);
3520     if (SizeOfTag == UINT_MAX) return NULL;
3521
3522     // Now comes the text. The length is specified by the tag size
3523     n ->Desc = cmsMLUalloc(self ->ContextID, 1);
3524     if (n ->Desc == NULL) return NULL;
3525
3526     ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
3527     if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL;
3528     ASCIIString[SizeOfTag] = 0;
3529     cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
3530     _cmsFree(self ->ContextID, ASCIIString);
3531
3532     *nItems = 1;
3533     return (void*) n;
3534 }
3535
3536 static
3537 cmsBool  Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3538 {
3539     cmsUcrBg* Value = (cmsUcrBg*) Ptr;
3540     cmsUInt32Number TextSize;
3541     char* Text;
3542
3543     // First curve is Under color removal
3544     if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
3545     if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
3546
3547     // Then black generation
3548     if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
3549     if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
3550
3551     // Now comes the text. The length is specified by the tag size
3552     TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
3553     Text     = (char*) _cmsMalloc(self ->ContextID, TextSize);
3554     if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
3555
3556     if (!io ->Write(io, TextSize, Text)) return FALSE;
3557     _cmsFree(self ->ContextID, Text);
3558
3559     return TRUE;
3560
3561     cmsUNUSED_PARAMETER(nItems);
3562 }
3563
3564 static
3565 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3566 {
3567     cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3568     cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3569
3570     if (NewUcrBg == NULL) return NULL;
3571
3572     NewUcrBg ->Bg   = cmsDupToneCurve(Src ->Bg);
3573     NewUcrBg ->Ucr  = cmsDupToneCurve(Src ->Ucr);
3574     NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
3575
3576     return (void*) NewUcrBg;
3577
3578     cmsUNUSED_PARAMETER(n);
3579 }
3580
3581 static
3582 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
3583 {
3584    cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3585
3586    if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
3587    if (Src ->Bg)  cmsFreeToneCurve(Src ->Bg);
3588    if (Src ->Desc) cmsMLUfree(Src ->Desc);
3589
3590    _cmsFree(self ->ContextID, Ptr);
3591 }
3592
3593 // ********************************************************************************
3594 // Type cmsSigCrdInfoType
3595 // ********************************************************************************
3596
3597 /*
3598 This type contains the PostScript product name to which this profile corresponds
3599 and the names of the companion CRDs. Recall that a single profile can generate
3600 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3601 country varies for each element:
3602
3603                 nm: PostScript product name
3604                 #0: Rendering intent 0 CRD name
3605                 #1: Rendering intent 1 CRD name
3606                 #2: Rendering intent 2 CRD name
3607                 #3: Rendering intent 3 CRD name
3608 */
3609
3610
3611
3612 // Auxiliar, read an string specified as count + string
3613 static
3614 cmsBool  ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
3615 {
3616     cmsUInt32Number Count;
3617     char* Text;
3618
3619     if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
3620
3621     if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
3622
3623     if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
3624     if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
3625
3626     Text     = (char*) _cmsMalloc(self ->ContextID, Count+1);
3627     if (Text == NULL) return FALSE;
3628
3629     if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
3630         _cmsFree(self ->ContextID, Text);
3631         return FALSE;
3632     }
3633
3634     Text[Count] = 0;
3635
3636     cmsMLUsetASCII(mlu, "PS", Section, Text);
3637     _cmsFree(self ->ContextID, Text);
3638
3639     *SizeOfTag -= (Count + sizeof(cmsUInt32Number));
3640     return TRUE;
3641 }
3642
3643 static
3644 cmsBool  WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
3645 {
3646  cmsUInt32Number TextSize;
3647  char* Text;
3648
3649     TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0);
3650     Text     = (char*) _cmsMalloc(self ->ContextID, TextSize);
3651
3652     if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE;
3653
3654     if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE;
3655
3656     if (!io ->Write(io, TextSize, Text)) return FALSE;
3657     _cmsFree(self ->ContextID, Text);
3658
3659     return TRUE;
3660 }
3661
3662 static
3663 void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3664 {
3665     cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5);
3666
3667     *nItems = 0;
3668     if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error;
3669     if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error;
3670     if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error;
3671     if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error;
3672     if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error;
3673
3674     *nItems = 1;
3675     return (void*) mlu;
3676
3677 Error:
3678     cmsMLUfree(mlu);
3679     return NULL;
3680
3681 }
3682
3683 static
3684 cmsBool  Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3685 {
3686
3687     cmsMLU* mlu = (cmsMLU*) Ptr;
3688
3689     if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
3690     if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
3691     if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
3692     if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
3693     if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
3694
3695     return TRUE;
3696
3697 Error:
3698     return FALSE;
3699
3700     cmsUNUSED_PARAMETER(nItems);
3701 }
3702
3703
3704 static
3705 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3706 {
3707     return (void*) cmsMLUdup((cmsMLU*) Ptr);
3708
3709     cmsUNUSED_PARAMETER(n);
3710     cmsUNUSED_PARAMETER(self);
3711 }
3712
3713 static
3714 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
3715 {
3716     cmsMLUfree((cmsMLU*) Ptr);
3717     return;
3718
3719     cmsUNUSED_PARAMETER(self);
3720 }
3721
3722 // ********************************************************************************
3723 // Type cmsSigScreeningType
3724 // ********************************************************************************
3725 //
3726 //The screeningType describes various screening parameters including screen
3727 //frequency, screening angle, and spot shape.
3728
3729 static
3730 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3731 {
3732     cmsScreening* sc = NULL;
3733     cmsUInt32Number i;
3734
3735     sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
3736     if (sc == NULL) return NULL;
3737
3738     *nItems = 0;
3739
3740     if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error;
3741     if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error;
3742
3743     if (sc ->nChannels > cmsMAXCHANNELS - 1)
3744         sc ->nChannels = cmsMAXCHANNELS - 1;
3745
3746     for (i=0; i < sc ->nChannels; i++) {
3747
3748         if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
3749         if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
3750         if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
3751     }
3752
3753
3754     *nItems = 1;
3755
3756     return (void*) sc;
3757
3758 Error:
3759     if (sc != NULL)
3760         _cmsFree(self ->ContextID, sc);
3761
3762     return NULL;
3763
3764     cmsUNUSED_PARAMETER(SizeOfTag);
3765 }
3766
3767
3768 static
3769 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3770 {
3771     cmsScreening* sc = (cmsScreening* ) Ptr;
3772     cmsUInt32Number i;
3773
3774     if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
3775     if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
3776
3777     for (i=0; i < sc ->nChannels; i++) {
3778
3779         if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
3780         if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
3781         if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
3782     }
3783
3784     return TRUE;
3785
3786     cmsUNUSED_PARAMETER(nItems);
3787     cmsUNUSED_PARAMETER(self);
3788 }
3789
3790
3791 static
3792 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3793 {
3794    return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3795
3796    cmsUNUSED_PARAMETER(n);
3797 }
3798
3799
3800 static
3801 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3802 {
3803    _cmsFree(self ->ContextID, Ptr);
3804 }
3805
3806 // ********************************************************************************
3807 // Type cmsSigViewingConditionsType
3808 // ********************************************************************************
3809 //
3810 //This type represents a set of viewing condition parameters including:
3811 //CIE ï¿½absolute� illuminant white point tristimulus values and CIE ï¿½absolute�
3812 //surround tristimulus values.
3813
3814 static
3815 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3816 {
3817     cmsICCViewingConditions* vc = NULL;
3818
3819     vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3820     if (vc == NULL) return NULL;
3821
3822     *nItems = 0;
3823
3824     if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3825     if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3826     if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3827
3828     *nItems = 1;
3829
3830     return (void*) vc;
3831
3832 Error:
3833     if (vc != NULL)
3834         _cmsFree(self ->ContextID, vc);
3835
3836     return NULL;
3837
3838     cmsUNUSED_PARAMETER(SizeOfTag);
3839 }
3840
3841
3842 static
3843 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3844 {
3845     cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3846
3847     if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3848     if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3849     if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3850
3851     return TRUE;
3852
3853     cmsUNUSED_PARAMETER(nItems);
3854     cmsUNUSED_PARAMETER(self);
3855 }
3856
3857
3858 static
3859 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3860 {
3861    return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsICCViewingConditions));
3862
3863    cmsUNUSED_PARAMETER(n);
3864 }
3865
3866
3867 static
3868 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3869 {
3870    _cmsFree(self ->ContextID, Ptr);
3871 }
3872
3873
3874 // ********************************************************************************
3875 // Type cmsSigMultiProcessElementType
3876 // ********************************************************************************
3877
3878
3879 static
3880 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3881 {
3882     return (void*) cmsStageDup((cmsStage*) Ptr);
3883
3884     cmsUNUSED_PARAMETER(n);
3885     cmsUNUSED_PARAMETER(self);
3886 }
3887
3888 static
3889 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
3890 {
3891     cmsStageFree((cmsStage*) Ptr);
3892     return;
3893
3894     cmsUNUSED_PARAMETER(self);
3895 }
3896
3897 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
3898 // The first curve segment always starts at ï¿½Infinity, and the last curve segment always ends at +Infinity. The
3899 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
3900 // specified either in terms of a formula, or by a sampled curve.
3901
3902
3903 // Read an embedded segmented curve
3904 static
3905 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
3906 {
3907     cmsCurveSegSignature ElementSig;
3908     cmsUInt32Number i, j;
3909     cmsUInt16Number nSegments;
3910     cmsCurveSegment*  Segments;
3911     cmsToneCurve* Curve;
3912     cmsFloat32Number PrevBreak = -1E22F;    // - infinite
3913
3914     // Take signature and channels for each element.
3915      if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
3916
3917      // That should be a segmented curve
3918      if (ElementSig != cmsSigSegmentedCurve) return NULL;
3919
3920      if (!_cmsReadUInt32Number(io, NULL)) return NULL;
3921      if (!_cmsReadUInt16Number(io, &nSegments)) return NULL;
3922      if (!_cmsReadUInt16Number(io, NULL)) return NULL;
3923
3924      if (nSegments < 1) return NULL;
3925      Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment));
3926      if (Segments == NULL) return NULL;
3927
3928      // Read breakpoints
3929      for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) {
3930
3931          Segments[i].x0 = PrevBreak;
3932          if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error;
3933          PrevBreak = Segments[i].x1;
3934      }
3935
3936      Segments[nSegments-1].x0 = PrevBreak;
3937      Segments[nSegments-1].x1 = 1E22F;     // A big cmsFloat32Number number
3938
3939      // Read segments
3940      for (i=0; i < nSegments; i++) {
3941
3942           if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error;
3943           if (!_cmsReadUInt32Number(io, NULL)) goto Error;
3944
3945            switch (ElementSig) {
3946
3947             case cmsSigFormulaCurveSeg: {
3948
3949                 cmsUInt16Number Type;
3950                 cmsUInt32Number ParamsByType[] = {4, 5, 5 };
3951
3952                 if (!_cmsReadUInt16Number(io, &Type)) goto Error;
3953                 if (!_cmsReadUInt16Number(io, NULL)) goto Error;
3954
3955                 Segments[i].Type = Type + 6;
3956                 if (Type > 2) goto Error;
3957
3958                 for (j=0; j < ParamsByType[Type]; j++) {
3959
3960                     cmsFloat32Number f;
3961                     if (!_cmsReadFloat32Number(io, &f)) goto Error;
3962                     Segments[i].Params[j] = f;
3963                 }
3964                 }
3965                 break;
3966
3967
3968             case cmsSigSampledCurveSeg: {
3969                 cmsUInt32Number Count;
3970
3971                 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3972
3973                 Segments[i].nGridPoints = Count;
3974                 Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
3975                 if (Segments[i].SampledPoints == NULL) goto Error;
3976
3977                 for (j=0; j < Count; j++) {
3978                     if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
3979                 }
3980                 }
3981                 break;
3982
3983             default:
3984                 {
3985                 char String[5];
3986
3987                 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
3988                 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String);
3989                 }
3990                 return NULL;
3991
3992          }
3993      }
3994
3995      Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments);
3996
3997      for (i=0; i < nSegments; i++) {
3998          if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
3999      }
4000      _cmsFree(self ->ContextID, Segments);
4001      return Curve;
4002
4003 Error:
4004      if (Segments) _cmsFree(self ->ContextID, Segments);
4005      return NULL;
4006 }
4007
4008
4009 static
4010 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
4011                      cmsIOHANDLER* io,
4012                      void* Cargo,
4013                      cmsUInt32Number n,
4014                      cmsUInt32Number SizeOfTag)
4015 {
4016       cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
4017
4018       GammaTables[n] = ReadSegmentedCurve(self, io);
4019       return (GammaTables[n] != NULL);
4020
4021       cmsUNUSED_PARAMETER(SizeOfTag);
4022 }
4023
4024 static
4025 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4026 {
4027     cmsStage* mpe = NULL;
4028     cmsUInt16Number InputChans, OutputChans;
4029     cmsUInt32Number i, BaseOffset;
4030     cmsToneCurve** GammaTables;
4031
4032     *nItems = 0;
4033
4034     // Get actual position as a basis for element offsets
4035     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4036
4037     if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4038     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4039
4040     if (InputChans != OutputChans) return NULL;
4041
4042     GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
4043     if (GammaTables == NULL) return NULL;
4044
4045     if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
4046
4047         mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
4048     }
4049     else {
4050         mpe = NULL;
4051     }
4052
4053     for (i=0; i < InputChans; i++) {
4054         if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
4055     }
4056
4057     _cmsFree(self ->ContextID, GammaTables);
4058     *nItems = (mpe != NULL) ? 1 : 0;
4059     return mpe;
4060
4061     cmsUNUSED_PARAMETER(SizeOfTag);
4062 }
4063
4064
4065 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4066 static
4067 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
4068 {
4069     cmsUInt32Number i, j;
4070     cmsCurveSegment* Segments = g ->Segments;
4071     cmsUInt32Number nSegments = g ->nSegments;
4072
4073     if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
4074     if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4075     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
4076     if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4077
4078     // Write the break-points
4079     for (i=0; i < nSegments - 1; i++) {
4080         if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
4081     }
4082
4083     // Write the segments
4084     for (i=0; i < g ->nSegments; i++) {
4085
4086         cmsCurveSegment* ActualSeg = Segments + i;
4087
4088         if (ActualSeg -> Type == 0) {
4089
4090             // This is a sampled curve
4091             if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
4092             if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4093             if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error;
4094
4095             for (j=0; j < g ->Segments[i].nGridPoints; j++) {
4096                 if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
4097             }
4098
4099         }
4100         else {
4101             int Type;
4102             cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
4103
4104             // This is a formula-based
4105             if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error;
4106             if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4107
4108             // We only allow 1, 2 and 3 as types
4109             Type = ActualSeg ->Type - 6;
4110             if (Type > 2 || Type < 0) goto Error;
4111
4112             if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error;
4113             if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4114
4115             for (j=0; j < ParamsByType[Type]; j++) {
4116                 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error;
4117             }
4118         }
4119
4120         // It seems there is no need to align. Code is here, and for safety commented out
4121         // if (!_cmsWriteAlignment(io)) goto Error;
4122     }
4123
4124     return TRUE;
4125
4126 Error:
4127     return FALSE;
4128 }
4129
4130
4131 static
4132 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
4133                       cmsIOHANDLER* io,
4134                       void* Cargo,
4135                       cmsUInt32Number n,
4136                       cmsUInt32Number SizeOfTag)
4137 {
4138     _cmsStageToneCurvesData* Curves  = (_cmsStageToneCurvesData*) Cargo;
4139
4140     return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
4141
4142     cmsUNUSED_PARAMETER(SizeOfTag);
4143     cmsUNUSED_PARAMETER(self);
4144 }
4145
4146 // Write a curve, checking first for validity
4147 static
4148 cmsBool  Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4149 {
4150     cmsUInt32Number BaseOffset;
4151     cmsStage* mpe = (cmsStage*) Ptr;
4152     _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
4153
4154     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4155
4156     // Write the header. Since those are curves, input and output channels are same
4157     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4158     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4159
4160     if (!WritePositionTable(self, io, 0,
4161                                 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4162
4163
4164     return TRUE;
4165
4166     cmsUNUSED_PARAMETER(nItems);
4167 }
4168
4169
4170
4171 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4172 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4173 // is organized as follows:
4174 // array = [e11, e12, ï¿½, e1P, e21, e22, ï¿½, e2P, ï¿½, eQ1, eQ2, ï¿½, eQP, e1, e2, ï¿½, eQ]
4175
4176 static
4177 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4178 {
4179     cmsStage* mpe;
4180     cmsUInt16Number   InputChans, OutputChans;
4181     cmsUInt32Number   nElems, i;
4182     cmsFloat64Number* Matrix;
4183     cmsFloat64Number* Offsets;
4184
4185     if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4186     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4187
4188
4189     nElems = InputChans * OutputChans;
4190
4191     // Input and output chans may be ANY (up to 0xffff)
4192     Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
4193     if (Matrix == NULL) return NULL;
4194
4195     Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number));
4196     if (Offsets == NULL) {
4197
4198         _cmsFree(self ->ContextID, Matrix);
4199         return NULL;
4200     }
4201
4202     for (i=0; i < nElems; i++) {
4203
4204         cmsFloat32Number v;
4205
4206         if (!_cmsReadFloat32Number(io, &v)) return NULL;
4207         Matrix[i] = v;
4208     }
4209
4210
4211     for (i=0; i < OutputChans; i++) {
4212
4213         cmsFloat32Number v;
4214
4215         if (!_cmsReadFloat32Number(io, &v)) return NULL;
4216         Offsets[i] = v;
4217     }
4218
4219
4220     mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
4221     _cmsFree(self ->ContextID, Matrix);
4222     _cmsFree(self ->ContextID, Offsets);
4223
4224     *nItems = 1;
4225
4226     return mpe;
4227
4228     cmsUNUSED_PARAMETER(SizeOfTag);
4229 }
4230
4231 static
4232 cmsBool  Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4233 {
4234     cmsUInt32Number i, nElems;
4235     cmsStage* mpe = (cmsStage*) Ptr;
4236     _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
4237
4238     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4239     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4240
4241     nElems = mpe ->InputChannels * mpe ->OutputChannels;
4242
4243     for (i=0; i < nElems; i++) {
4244         if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
4245     }
4246
4247
4248     for (i=0; i < mpe ->OutputChannels; i++) {
4249
4250         if (Matrix ->Offset == NULL) {
4251
4252                if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
4253         }
4254         else {
4255                if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
4256         }
4257     }
4258
4259     return TRUE;
4260
4261     cmsUNUSED_PARAMETER(nItems);
4262     cmsUNUSED_PARAMETER(self);
4263 }
4264
4265
4266
4267 static
4268 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4269 {
4270     cmsStage* mpe = NULL;
4271     cmsUInt16Number InputChans, OutputChans;
4272     cmsUInt8Number Dimensions8[16];
4273     cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
4274     _cmsStageCLutData* clut;
4275
4276     if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4277     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4278
4279     if (InputChans == 0) goto Error;
4280     if (OutputChans == 0) goto Error;
4281
4282     if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
4283         goto Error;
4284
4285     // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
4286     nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
4287     for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i];
4288
4289     // Allocate the true CLUT
4290     mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
4291     if (mpe == NULL) goto Error;
4292
4293     // Read the data
4294     clut = (_cmsStageCLutData*) mpe ->Data;
4295     for (i=0; i < clut ->nEntries; i++) {
4296
4297         if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
4298     }
4299
4300     *nItems = 1;
4301     return mpe;
4302
4303 Error:
4304     *nItems = 0;
4305     if (mpe != NULL) cmsStageFree(mpe);
4306     return NULL;
4307
4308     cmsUNUSED_PARAMETER(SizeOfTag);
4309 }
4310
4311 // Write a CLUT in floating point
4312 static
4313 cmsBool  Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4314 {
4315     cmsUInt8Number Dimensions8[16];
4316     cmsUInt32Number i;
4317     cmsStage* mpe = (cmsStage*) Ptr;
4318     _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4319
4320     // Check for maximum number of channels
4321     if (mpe -> InputChannels > 15) return FALSE;
4322
4323     // Only floats are supported in MPE
4324     if (clut ->HasFloatValues == FALSE) return FALSE;
4325
4326     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4327     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4328
4329     memset(Dimensions8, 0, sizeof(Dimensions8));
4330
4331     for (i=0; i < mpe ->InputChannels; i++)
4332         Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4333
4334     if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4335
4336     for (i=0; i < clut ->nEntries; i++) {
4337
4338         if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4339     }
4340
4341     return TRUE;
4342
4343     cmsUNUSED_PARAMETER(nItems);
4344     cmsUNUSED_PARAMETER(self);
4345 }
4346
4347
4348
4349 // This is the list of built-in MPE types
4350 static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
4351
4352 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] },   // Ignore those elements for now
4353 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] },   // (That's what the spec says)
4354
4355 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType,     MPEcurve),      &SupportedMPEtypes[3] },
4356 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType,       MPEmatrix),     &SupportedMPEtypes[4] },
4357 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType,         MPEclut),        NULL },
4358 };
4359
4360 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL };
4361
4362 static
4363 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
4364                     cmsIOHANDLER* io,
4365                     void* Cargo,
4366                     cmsUInt32Number n,
4367                     cmsUInt32Number SizeOfTag)
4368 {
4369     cmsStageSignature ElementSig;
4370     cmsTagTypeHandler* TypeHandler;
4371     cmsUInt32Number nItems;
4372     cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
4373     _cmsTagTypePluginChunkType* MPETypePluginChunk  = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4374
4375
4376     // Take signature and channels for each element.
4377     if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
4378
4379     // The reserved placeholder
4380     if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
4381
4382     // Read diverse MPE types
4383     TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes);
4384     if (TypeHandler == NULL)  {
4385
4386         char String[5];
4387
4388         _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4389
4390         // An unknown element was found.
4391         cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
4392         return FALSE;
4393     }
4394
4395     // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4396     // Read the MPE. No size is given
4397     if (TypeHandler ->ReadPtr != NULL) {
4398
4399         // This is a real element which should be read and processed
4400         if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag)))
4401             return FALSE;
4402     }
4403
4404     return TRUE;
4405
4406     cmsUNUSED_PARAMETER(SizeOfTag);
4407     cmsUNUSED_PARAMETER(n);
4408 }
4409
4410
4411 // This is the main dispatcher for MPE
4412 static
4413 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4414 {
4415     cmsUInt16Number InputChans, OutputChans;
4416     cmsUInt32Number ElementCount;
4417     cmsPipeline *NewLUT = NULL;
4418     cmsUInt32Number BaseOffset;
4419
4420     // Get actual position as a basis for element offsets
4421     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4422
4423     // Read channels and element count
4424     if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4425     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4426
4427     // Allocates an empty LUT
4428     NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
4429     if (NewLUT == NULL) return NULL;
4430
4431     if (!_cmsReadUInt32Number(io, &ElementCount)) return NULL;
4432
4433     if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) {
4434         if (NewLUT != NULL) cmsPipelineFree(NewLUT);
4435         *nItems = 0;
4436         return NULL;
4437     }
4438
4439     // Success
4440     *nItems = 1;
4441     return NewLUT;
4442
4443     cmsUNUSED_PARAMETER(SizeOfTag);
4444 }
4445
4446
4447
4448 // This one is a liitle bit more complex, so we don't use position tables this time.
4449 static
4450 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4451 {
4452     cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
4453     int inputChan, outputChan;
4454     cmsUInt32Number ElemCount;
4455     cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
4456     cmsStageSignature ElementSig;
4457     cmsPipeline* Lut = (cmsPipeline*) Ptr;
4458     cmsStage* Elem = Lut ->Elements;
4459     cmsTagTypeHandler* TypeHandler;
4460     _cmsTagTypePluginChunkType* MPETypePluginChunk  = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4461
4462     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4463
4464     inputChan  = cmsPipelineInputChannels(Lut);
4465     outputChan = cmsPipelineOutputChannels(Lut);
4466     ElemCount  = cmsPipelineStageCount(Lut);
4467
4468     ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
4469     if (ElementOffsets == NULL) goto Error;
4470
4471     ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
4472     if (ElementSizes == NULL) goto Error;
4473
4474     // Write the head
4475     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error;
4476     if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error;
4477     if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error;
4478
4479     DirectoryPos = io ->Tell(io);
4480
4481     // Write a fake directory to be filled latter on
4482     for (i=0; i < ElemCount; i++) {
4483         if (!_cmsWriteUInt32Number(io, 0)) goto Error;  // Offset
4484         if (!_cmsWriteUInt32Number(io, 0)) goto Error;  // size
4485     }
4486
4487     // Write each single tag. Keep track of the size as well.
4488     for (i=0; i < ElemCount; i++) {
4489
4490         ElementOffsets[i] = io ->Tell(io) - BaseOffset;
4491
4492         ElementSig = Elem ->Type;
4493
4494         TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes);
4495         if (TypeHandler == NULL)  {
4496
4497                 char String[5];
4498
4499                 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4500
4501                  // An unknow element was found.
4502                  cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String);
4503                  goto Error;
4504         }
4505
4506         if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error;
4507         if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4508         Before = io ->Tell(io);
4509         if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error;
4510         if (!_cmsWriteAlignment(io)) goto Error;
4511
4512         ElementSizes[i] = io ->Tell(io) - Before;
4513
4514         Elem = Elem ->Next;
4515     }
4516
4517     // Write the directory
4518     CurrentPos = io ->Tell(io);
4519
4520     if (!io ->Seek(io, DirectoryPos)) goto Error;
4521
4522     for (i=0; i < ElemCount; i++) {
4523         if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
4524         if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
4525     }
4526
4527     if (!io ->Seek(io, CurrentPos)) goto Error;
4528
4529     if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4530     if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4531     return TRUE;
4532
4533 Error:
4534     if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4535     if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4536     return FALSE;
4537
4538     cmsUNUSED_PARAMETER(nItems);
4539 }
4540
4541
4542 static
4543 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4544 {
4545     return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
4546
4547     cmsUNUSED_PARAMETER(n);
4548     cmsUNUSED_PARAMETER(self);
4549 }
4550
4551 static
4552 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
4553 {
4554     cmsPipelineFree((cmsPipeline*) Ptr);
4555     return;
4556
4557     cmsUNUSED_PARAMETER(self);
4558 }
4559
4560
4561 // ********************************************************************************
4562 // Type cmsSigVcgtType
4563 // ********************************************************************************
4564
4565
4566 #define cmsVideoCardGammaTableType    0
4567 #define cmsVideoCardGammaFormulaType  1
4568
4569 // Used internally
4570 typedef struct {
4571     double Gamma;
4572     double Min;
4573     double Max;
4574 } _cmsVCGTGAMMA;
4575
4576
4577 static
4578 void *Type_vcgt_Read(struct _cms_typehandler_struct* self,
4579                      cmsIOHANDLER* io,
4580                      cmsUInt32Number* nItems,
4581                      cmsUInt32Number SizeOfTag)
4582 {
4583     cmsUInt32Number TagType, n, i;
4584     cmsToneCurve** Curves;
4585
4586     *nItems = 0;
4587
4588     // Read tag type
4589     if (!_cmsReadUInt32Number(io, &TagType)) return NULL;
4590
4591     // Allocate space for the array
4592     Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4593     if (Curves == NULL) return NULL;
4594
4595     // There are two possible flavors
4596     switch (TagType) {
4597
4598     // Gamma is stored as a table
4599     case cmsVideoCardGammaTableType:
4600     {
4601        cmsUInt16Number nChannels, nElems, nBytes;
4602
4603        // Check channel count, which should be 3 (we don't support monochrome this time)
4604        if (!_cmsReadUInt16Number(io, &nChannels)) goto Error;
4605
4606        if (nChannels != 3) {
4607            cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels);
4608            goto Error;
4609        }
4610
4611        // Get Table element count and bytes per element
4612        if (!_cmsReadUInt16Number(io, &nElems)) goto Error;
4613        if (!_cmsReadUInt16Number(io, &nBytes)) goto Error;
4614
4615        // Adobe's quirk fixup. Fixing broken profiles...
4616        if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576)
4617            nBytes = 2;
4618
4619
4620        // Populate tone curves
4621        for (n=0; n < 3; n++) {
4622
4623            Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL);
4624            if (Curves[n] == NULL) goto Error;
4625
4626            // On depending on byte depth
4627            switch (nBytes) {
4628
4629            // One byte, 0..255
4630            case 1:
4631                for (i=0; i < nElems; i++) {
4632
4633                    cmsUInt8Number v;
4634
4635                       if (!_cmsReadUInt8Number(io, &v)) goto Error;
4636                       Curves[n] ->Table16[i] = FROM_8_TO_16(v);
4637                }
4638                break;
4639
4640            // One word 0..65535
4641            case 2:
4642               if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error;
4643               break;
4644
4645           // Unsupported
4646            default:
4647               cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8);
4648               goto Error;
4649            }
4650        } // For all 3 channels
4651     }
4652     break;
4653
4654    // In this case, gamma is stored as a formula
4655    case cmsVideoCardGammaFormulaType:
4656    {
4657        _cmsVCGTGAMMA Colorant[3];
4658
4659         // Populate tone curves
4660        for (n=0; n < 3; n++) {
4661
4662            double Params[10];
4663
4664            if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
4665            if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
4666            if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
4667
4668             // Parametric curve type 5 is:
4669             // Y = (aX + b)^Gamma + e | X >= d
4670             // Y = cX + f             | X < d
4671
4672             // vcgt formula is:
4673             // Y = (Max ï¿½ Min) * (X ^ Gamma) + Min
4674
4675             // So, the translation is
4676             // a = (Max ï¿½ Min) ^ ( 1 / Gamma)
4677             // e = Min
4678             // b=c=d=f=0
4679
4680            Params[0] = Colorant[n].Gamma;
4681            Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
4682            Params[2] = 0;
4683            Params[3] = 0;
4684            Params[4] = 0;
4685            Params[5] = Colorant[n].Min;
4686            Params[6] = 0;
4687
4688            Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4689            if (Curves[n] == NULL) goto Error;
4690        }
4691    }
4692    break;
4693
4694    // Unsupported
4695    default:
4696       cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
4697       goto Error;
4698    }
4699
4700    *nItems = 1;
4701    return (void*) Curves;
4702
4703 // Regret,  free all resources
4704 Error:
4705
4706     cmsFreeToneCurveTriple(Curves);
4707     _cmsFree(self ->ContextID, Curves);
4708     return NULL;
4709
4710      cmsUNUSED_PARAMETER(SizeOfTag);
4711 }
4712
4713
4714 // We don't support all flavors, only 16bits tables and formula
4715 static
4716 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4717 {
4718     cmsToneCurve** Curves =  (cmsToneCurve**) Ptr;
4719     cmsUInt32Number i, j;
4720
4721     if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
4722         cmsGetToneCurveParametricType(Curves[1]) == 5 &&
4723         cmsGetToneCurveParametricType(Curves[2]) == 5) {
4724
4725             if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
4726
4727             // Save parameters
4728             for (i=0; i < 3; i++) {
4729
4730                 _cmsVCGTGAMMA v;
4731
4732                 v.Gamma = Curves[i] ->Segments[0].Params[0];
4733                 v.Min   = Curves[i] ->Segments[0].Params[5];
4734                 v.Max   = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
4735
4736                 if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
4737                 if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
4738                 if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
4739             }
4740     }
4741
4742     else {
4743
4744         // Always store as a table of 256 words
4745         if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
4746         if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
4747         if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
4748         if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
4749
4750         for (i=0; i < 3; i++) {
4751             for (j=0; j < 256; j++) {
4752
4753                 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
4754                 cmsUInt16Number  n = _cmsQuickSaturateWord(v * 65535.0);
4755
4756                 if (!_cmsWriteUInt16Number(io, n)) return FALSE;
4757             }
4758         }
4759     }
4760
4761     return TRUE;
4762
4763     cmsUNUSED_PARAMETER(self);
4764     cmsUNUSED_PARAMETER(nItems);
4765 }
4766
4767 static
4768 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4769 {
4770     cmsToneCurve** OldCurves =  (cmsToneCurve**) Ptr;
4771     cmsToneCurve** NewCurves;
4772
4773     NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4774     if (NewCurves == NULL) return NULL;
4775
4776     NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
4777     NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
4778     NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
4779
4780     return (void*) NewCurves;
4781
4782     cmsUNUSED_PARAMETER(n);
4783 }
4784
4785
4786 static
4787 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
4788 {
4789     cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
4790     _cmsFree(self ->ContextID, Ptr);
4791 }
4792
4793
4794 // ********************************************************************************
4795 // Type cmsSigDictType
4796 // ********************************************************************************
4797
4798 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4799 typedef struct {
4800     cmsContext ContextID;
4801     cmsUInt32Number *Offsets;
4802     cmsUInt32Number *Sizes;
4803 } _cmsDICelem;
4804
4805 typedef struct {
4806     _cmsDICelem Name, Value, DisplayName, DisplayValue;
4807
4808 } _cmsDICarray;
4809
4810 // Allocate an empty array element
4811 static
4812 cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e,  cmsUInt32Number Count)
4813 {
4814     e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
4815     if (e->Offsets == NULL) return FALSE;
4816
4817     e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
4818     if (e->Sizes == NULL) {
4819
4820         _cmsFree(ContextID, e -> Offsets);
4821         return FALSE;
4822     }
4823
4824     e ->ContextID = ContextID;
4825     return TRUE;
4826 }
4827
4828 // Free an array element
4829 static
4830 void FreeElem(_cmsDICelem* e)
4831 {
4832     if (e ->Offsets != NULL)  _cmsFree(e -> ContextID, e -> Offsets);
4833     if (e ->Sizes   != NULL)  _cmsFree(e -> ContextID, e -> Sizes);
4834     e->Offsets = e ->Sizes = NULL;
4835 }
4836
4837 // Get rid of whole array
4838 static
4839 void FreeArray( _cmsDICarray* a)
4840 {
4841     if (a ->Name.Offsets != NULL) FreeElem(&a->Name);
4842     if (a ->Value.Offsets != NULL) FreeElem(&a ->Value);
4843     if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName);
4844     if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue);
4845 }
4846
4847
4848 // Allocate whole array
4849 static
4850 cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
4851 {
4852     // Empty values
4853     memset(a, 0, sizeof(_cmsDICarray));
4854
4855     // On depending on record size, create column arrays
4856     if (!AllocElem(ContextID, &a ->Name, Count)) goto Error;
4857     if (!AllocElem(ContextID, &a ->Value, Count)) goto Error;
4858
4859     if (Length > 16) {
4860         if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error;
4861
4862     }
4863     if (Length > 24) {
4864         if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error;
4865     }
4866     return TRUE;
4867
4868 Error:
4869     FreeArray(a);
4870     return FALSE;
4871 }
4872
4873 // Read one element
4874 static
4875 cmsBool ReadOneElem(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset)
4876 {
4877     if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
4878     if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
4879
4880     // An offset of zero has special meaning and shal be preserved
4881     if (e ->Offsets[i] > 0)
4882         e ->Offsets[i] += BaseOffset;
4883     return TRUE;
4884 }
4885
4886
4887 static
4888 cmsBool ReadOffsetArray(cmsIOHANDLER* io,  _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset)
4889 {
4890     cmsUInt32Number i;
4891
4892     // Read column arrays
4893     for (i=0; i < Count; i++) {
4894
4895         if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
4896         if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
4897
4898         if (Length > 16) {
4899
4900             if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
4901
4902         }
4903
4904         if (Length > 24) {
4905
4906             if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
4907         }
4908     }
4909     return TRUE;
4910 }
4911
4912
4913 // Write one element
4914 static
4915 cmsBool WriteOneElem(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i)
4916 {
4917     if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE;
4918     if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE;
4919
4920     return TRUE;
4921 }
4922
4923 static
4924 cmsBool WriteOffsetArray(cmsIOHANDLER* io,  _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
4925 {
4926     cmsUInt32Number i;
4927
4928     for (i=0; i < Count; i++) {
4929
4930         if (!WriteOneElem(io, &a -> Name, i)) return FALSE;
4931         if (!WriteOneElem(io, &a -> Value, i))  return FALSE;
4932
4933         if (Length > 16) {
4934
4935             if (!WriteOneElem(io, &a -> DisplayName, i))  return FALSE;
4936         }
4937
4938         if (Length > 24) {
4939
4940             if (!WriteOneElem(io, &a -> DisplayValue, i))  return FALSE;
4941         }
4942     }
4943
4944     return TRUE;
4945 }
4946
4947 static
4948 cmsBool ReadOneWChar(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr)
4949 {
4950
4951     cmsUInt32Number nChars;
4952
4953       // Special case for undefined strings (see ICC Votable
4954       // Proposal Submission, Dictionary Type and Metadata TAG Definition)
4955       if (e -> Offsets[i] == 0) {
4956
4957           *wcstr = NULL;
4958           return TRUE;
4959       }
4960
4961       if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
4962
4963       nChars = e ->Sizes[i] / sizeof(cmsUInt16Number);
4964
4965
4966       *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t));
4967       if (*wcstr == NULL) return FALSE;
4968
4969       if (!_cmsReadWCharArray(io, nChars, *wcstr)) {
4970           _cmsFree(e ->ContextID, *wcstr);
4971           return FALSE;
4972       }
4973
4974       // End of string marker
4975       (*wcstr)[nChars] = 0;
4976       return TRUE;
4977 }
4978
4979 static
4980 cmsUInt32Number mywcslen(const wchar_t *s)
4981 {
4982     const wchar_t *p;
4983
4984     p = s;
4985     while (*p)
4986         p++;
4987
4988     return (cmsUInt32Number)(p - s);
4989 }
4990
4991 static
4992 cmsBool WriteOneWChar(cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset)
4993 {
4994     cmsUInt32Number Before = io ->Tell(io);
4995     cmsUInt32Number n;
4996
4997     e ->Offsets[i] = Before - BaseOffset;
4998
4999     if (wcstr == NULL) {
5000         e ->Sizes[i] = 0;
5001         e ->Offsets[i] = 0;
5002         return TRUE;
5003     }
5004
5005     n = mywcslen(wcstr);
5006     if (!_cmsWriteWCharArray(io,  n, wcstr)) return FALSE;
5007
5008     e ->Sizes[i] = io ->Tell(io) - Before;
5009     return TRUE;
5010 }
5011
5012 static
5013 cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu)
5014 {
5015     cmsUInt32Number nItems = 0;
5016
5017     // A way to get null MLUCs
5018     if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) {
5019
5020         *mlu = NULL;
5021         return TRUE;
5022     }
5023
5024     if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
5025
5026     *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]);
5027     return *mlu != NULL;
5028 }
5029
5030 static
5031 cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,  _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset)
5032 {
5033     cmsUInt32Number Before;
5034
5035      // Special case for undefined strings (see ICC Votable
5036      // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5037      if (mlu == NULL) {
5038         e ->Sizes[i] = 0;
5039         e ->Offsets[i] = 0;
5040         return TRUE;
5041     }
5042
5043     Before = io ->Tell(io);
5044     e ->Offsets[i] = Before - BaseOffset;
5045
5046     if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
5047
5048     e ->Sizes[i] = io ->Tell(io) - Before;
5049     return TRUE;
5050 }
5051
5052
5053 static
5054 void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
5055 {
5056    cmsHANDLE hDict;
5057    cmsUInt32Number i, Count, Length;
5058    cmsUInt32Number BaseOffset;
5059    _cmsDICarray a;
5060    wchar_t *NameWCS = NULL, *ValueWCS = NULL;
5061    cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
5062    cmsBool rc;
5063
5064     *nItems = 0;
5065
5066     // Get actual position as a basis for element offsets
5067     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5068
5069     // Get name-value record count
5070     if (!_cmsReadUInt32Number(io, &Count)) return NULL;
5071     SizeOfTag -= sizeof(cmsUInt32Number);
5072
5073     // Get rec length
5074     if (!_cmsReadUInt32Number(io, &Length)) return NULL;
5075     SizeOfTag -= sizeof(cmsUInt32Number);
5076
5077     // Check for valid lengths
5078     if (Length != 16 && Length != 24 && Length != 32) {
5079          cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length);
5080          return NULL;
5081     }
5082
5083     // Creates an empty dictionary
5084     hDict = cmsDictAlloc(self -> ContextID);
5085     if (hDict == NULL) return NULL;
5086
5087     // On depending on record size, create column arrays
5088     if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
5089
5090     // Read column arrays
5091     if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error;
5092
5093     // Seek to each element and read it
5094     for (i=0; i < Count; i++) {
5095
5096         if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error;
5097         if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error;
5098
5099         if (Length > 16) {
5100             if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error;
5101         }
5102
5103         if (Length > 24) {
5104             if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error;
5105         }
5106
5107         if (NameWCS == NULL || ValueWCS == NULL) {
5108         
5109             cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value");        
5110             rc = FALSE;
5111         }
5112         else {
5113
5114             rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
5115         }
5116
5117         if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
5118         if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS);
5119         if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU);
5120         if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU);
5121
5122         if (!rc) goto Error;
5123     }
5124
5125    FreeArray(&a);
5126    *nItems = 1;
5127    return (void*) hDict;
5128
5129 Error:
5130    FreeArray(&a);
5131    cmsDictFree(hDict);
5132    return NULL;
5133 }
5134
5135
5136 static
5137 cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
5138 {
5139     cmsHANDLE hDict = (cmsHANDLE) Ptr;
5140     const cmsDICTentry* p;
5141     cmsBool AnyName, AnyValue;
5142     cmsUInt32Number i, Count, Length;
5143     cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset;
5144    _cmsDICarray a;
5145
5146     if (hDict == NULL) return FALSE;
5147
5148     BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5149
5150     // Let's inspect the dictionary
5151     Count = 0; AnyName = FALSE; AnyValue = FALSE;
5152     for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) {
5153
5154         if (p ->DisplayName != NULL) AnyName = TRUE;
5155         if (p ->DisplayValue != NULL) AnyValue = TRUE;
5156         Count++;
5157     }
5158
5159     Length = 16;
5160     if (AnyName)  Length += 8;
5161     if (AnyValue) Length += 8;
5162
5163     if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
5164     if (!_cmsWriteUInt32Number(io, Length)) return FALSE;
5165
5166     // Keep starting position of offsets table
5167     DirectoryPos = io ->Tell(io);
5168
5169     // Allocate offsets array
5170     if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error;
5171
5172     // Write a fake directory to be filled latter on
5173     if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5174
5175     // Write each element. Keep track of the size as well.
5176     p = cmsDictGetEntryList(hDict);
5177     for (i=0; i < Count; i++) {
5178
5179         if (!WriteOneWChar(io, &a.Name, i,  p ->Name, BaseOffset)) goto Error;
5180         if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error;
5181
5182         if (p ->DisplayName != NULL) {
5183             if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error;
5184         }
5185
5186         if (p ->DisplayValue != NULL) {
5187             if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
5188         }
5189
5190        p = cmsDictNextEntry(p);
5191     }
5192
5193     // Write the directory
5194     CurrentPos = io ->Tell(io);
5195     if (!io ->Seek(io, DirectoryPos)) goto Error;
5196
5197     if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5198
5199     if (!io ->Seek(io, CurrentPos)) goto Error;
5200
5201     FreeArray(&a);
5202     return TRUE;
5203
5204 Error:
5205     FreeArray(&a);
5206     return FALSE;
5207
5208     cmsUNUSED_PARAMETER(nItems);
5209 }
5210
5211
5212 static
5213 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
5214 {
5215     return (void*)  cmsDictDup((cmsHANDLE) Ptr);
5216
5217     cmsUNUSED_PARAMETER(n);
5218     cmsUNUSED_PARAMETER(self);
5219 }
5220
5221
5222 static
5223 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
5224 {
5225     cmsDictFree((cmsHANDLE) Ptr);
5226     cmsUNUSED_PARAMETER(self);
5227 }
5228
5229
5230 // ********************************************************************************
5231 // Type support main routines
5232 // ********************************************************************************
5233
5234
5235 // This is the list of built-in types
5236 static _cmsTagTypeLinkedList SupportedTagTypes[] = {
5237
5238 {TYPE_HANDLER(cmsSigChromaticityType,          Chromaticity),        &SupportedTagTypes[1] },
5239 {TYPE_HANDLER(cmsSigColorantOrderType,         ColorantOrderType),   &SupportedTagTypes[2] },
5240 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType,       S15Fixed16),          &SupportedTagTypes[3] },
5241 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType,       U16Fixed16),          &SupportedTagTypes[4] },
5242 {TYPE_HANDLER(cmsSigTextType,                  Text),                &SupportedTagTypes[5] },
5243 {TYPE_HANDLER(cmsSigTextDescriptionType,       Text_Description),    &SupportedTagTypes[6] },
5244 {TYPE_HANDLER(cmsSigCurveType,                 Curve),               &SupportedTagTypes[7] },
5245 {TYPE_HANDLER(cmsSigParametricCurveType,       ParametricCurve),     &SupportedTagTypes[8] },
5246 {TYPE_HANDLER(cmsSigDateTimeType,              DateTime),            &SupportedTagTypes[9] },
5247 {TYPE_HANDLER(cmsSigLut8Type,                  LUT8),                &SupportedTagTypes[10] },
5248 {TYPE_HANDLER(cmsSigLut16Type,                 LUT16),               &SupportedTagTypes[11] },
5249 {TYPE_HANDLER(cmsSigColorantTableType,         ColorantTable),       &SupportedTagTypes[12] },
5250 {TYPE_HANDLER(cmsSigNamedColor2Type,           NamedColor),          &SupportedTagTypes[13] },
5251 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU),                 &SupportedTagTypes[14] },
5252 {TYPE_HANDLER(cmsSigProfileSequenceDescType,   ProfileSequenceDesc), &SupportedTagTypes[15] },
5253 {TYPE_HANDLER(cmsSigSignatureType,             Signature),           &SupportedTagTypes[16] },
5254 {TYPE_HANDLER(cmsSigMeasurementType,           Measurement),         &SupportedTagTypes[17] },
5255 {TYPE_HANDLER(cmsSigDataType,                  Data),                &SupportedTagTypes[18] },
5256 {TYPE_HANDLER(cmsSigLutAtoBType,               LUTA2B),              &SupportedTagTypes[19] },
5257 {TYPE_HANDLER(cmsSigLutBtoAType,               LUTB2A),              &SupportedTagTypes[20] },
5258 {TYPE_HANDLER(cmsSigUcrBgType,                 UcrBg),               &SupportedTagTypes[21] },
5259 {TYPE_HANDLER(cmsSigCrdInfoType,               CrdInfo),             &SupportedTagTypes[22] },
5260 {TYPE_HANDLER(cmsSigMultiProcessElementType,   MPE),                 &SupportedTagTypes[23] },
5261 {TYPE_HANDLER(cmsSigScreeningType,             Screening),           &SupportedTagTypes[24] },
5262 {TYPE_HANDLER(cmsSigViewingConditionsType,     ViewingConditions),   &SupportedTagTypes[25] },
5263 {TYPE_HANDLER(cmsSigXYZType,                   XYZ),                 &SupportedTagTypes[26] },
5264 {TYPE_HANDLER(cmsCorbisBrokenXYZtype,          XYZ),                 &SupportedTagTypes[27] },
5265 {TYPE_HANDLER(cmsMonacoBrokenCurveType,        Curve),               &SupportedTagTypes[28] },
5266 {TYPE_HANDLER(cmsSigProfileSequenceIdType,     ProfileSequenceId),   &SupportedTagTypes[29] },
5267 {TYPE_HANDLER(cmsSigDictType,                  Dictionary),          &SupportedTagTypes[30] },
5268 {TYPE_HANDLER(cmsSigVcgtType,                  vcgt),                NULL }
5269 };
5270
5271
5272 _cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL };
5273
5274
5275
5276 // Duplicates the zone of memory used by the plug-in in the new context
5277 static
5278 void DupTagTypeList(struct _cmsContext_struct* ctx, 
5279                     const struct _cmsContext_struct* src, 
5280                     int loc)
5281 {
5282    _cmsTagTypePluginChunkType newHead = { NULL };
5283    _cmsTagTypeLinkedList*  entry;
5284    _cmsTagTypeLinkedList*  Anterior = NULL;
5285    _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc];
5286
5287    // Walk the list copying all nodes
5288    for (entry = head->TagTypes;
5289        entry != NULL;
5290        entry = entry ->Next) {
5291
5292            _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList));
5293
5294            if (newEntry == NULL) 
5295                return;
5296
5297            // We want to keep the linked list order, so this is a little bit tricky
5298            newEntry -> Next = NULL;
5299            if (Anterior)
5300                Anterior -> Next = newEntry;
5301
5302            Anterior = newEntry;
5303
5304            if (newHead.TagTypes == NULL)
5305                newHead.TagTypes = newEntry;
5306    }
5307
5308    ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType));
5309 }
5310
5311
5312 void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, 
5313                                  const struct _cmsContext_struct* src)
5314 {
5315     if (src != NULL) {
5316         
5317         // Duplicate the LIST
5318         DupTagTypeList(ctx, src, TagTypePlugin);
5319     }
5320     else {
5321         static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
5322         ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
5323     }
5324 }
5325
5326 void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, 
5327                                const struct _cmsContext_struct* src)
5328 {
5329     if (src != NULL) {
5330         
5331         // Duplicate the LIST
5332         DupTagTypeList(ctx, src, MPEPlugin);
5333     }
5334     else {
5335         static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
5336         ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
5337     }
5338
5339 }
5340
5341
5342 // Both kind of plug-ins share same structure
5343 cmsBool  _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data)
5344 {
5345     return RegisterTypesPlugin(id, Data, TagTypePlugin);
5346 }
5347
5348 cmsBool  _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data)
5349 {
5350     return RegisterTypesPlugin(id, Data,MPEPlugin);
5351 }
5352
5353
5354 // Wrapper for tag types
5355 cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig)
5356 {
5357     _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin);
5358
5359     return GetHandler(sig, ctx->TagTypes, SupportedTagTypes);
5360 }
5361
5362 // ********************************************************************************
5363 // Tag support main routines
5364 // ********************************************************************************
5365
5366 typedef struct _cmsTagLinkedList_st {
5367
5368             cmsTagSignature Signature;
5369             cmsTagDescriptor Descriptor;
5370             struct _cmsTagLinkedList_st* Next;
5371
5372 } _cmsTagLinkedList;
5373
5374 // This is the list of built-in tags
5375 static _cmsTagLinkedList SupportedTags[] = {
5376
5377     { cmsSigAToB0Tag,               { 1, 3,  { cmsSigLut16Type,  cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]},
5378     { cmsSigAToB1Tag,               { 1, 3,  { cmsSigLut16Type,  cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]},
5379     { cmsSigAToB2Tag,               { 1, 3,  { cmsSigLut16Type,  cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]},
5380     { cmsSigBToA0Tag,               { 1, 3,  { cmsSigLut16Type,  cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]},
5381     { cmsSigBToA1Tag,               { 1, 3,  { cmsSigLut16Type,  cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]},
5382     { cmsSigBToA2Tag,               { 1, 3,  { cmsSigLut16Type,  cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]},
5383
5384     // Allow corbis  and its broken XYZ type
5385     { cmsSigRedColorantTag,         { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]},
5386     { cmsSigGreenColorantTag,       { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]},
5387     { cmsSigBlueColorantTag,        { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]},
5388
5389     { cmsSigRedTRCTag,              { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]},
5390     { cmsSigGreenTRCTag,            { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]},
5391     { cmsSigBlueTRCTag,             { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]},
5392
5393     { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]},
5394     { cmsSigCharTargetTag,          { 1, 1, { cmsSigTextType },     NULL}, &SupportedTags[14]},
5395
5396     { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]},
5397     { cmsSigChromaticityTag,        { 1, 1, { cmsSigChromaticityType    }, NULL}, &SupportedTags[16]},
5398     { cmsSigColorantOrderTag,       { 1, 1, { cmsSigColorantOrderType   }, NULL}, &SupportedTags[17]},
5399     { cmsSigColorantTableTag,       { 1, 1, { cmsSigColorantTableType   }, NULL}, &SupportedTags[18]},
5400     { cmsSigColorantTableOutTag,    { 1, 1, { cmsSigColorantTableType   }, NULL}, &SupportedTags[19]},
5401
5402     { cmsSigCopyrightTag,           { 1, 3, { cmsSigTextType,  cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]},
5403     { cmsSigDateTimeTag,            { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]},
5404
5405     { cmsSigDeviceMfgDescTag,       { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]},
5406     { cmsSigDeviceModelDescTag,     { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]},
5407
5408     { cmsSigGamutTag,               { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]},
5409
5410     { cmsSigGrayTRCTag,             { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]},
5411     { cmsSigLuminanceTag,           { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]},
5412
5413     { cmsSigMediaBlackPointTag,     { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]},
5414     { cmsSigMediaWhitePointTag,     { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]},
5415
5416     { cmsSigNamedColor2Tag,         { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]},
5417
5418     { cmsSigPreview0Tag,            { 1, 3,  { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]},
5419     { cmsSigPreview1Tag,            { 1, 3,  { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]},
5420     { cmsSigPreview2Tag,            { 1, 3,  { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]},
5421
5422     { cmsSigProfileDescriptionTag,  { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]},
5423     { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
5424     { cmsSigTechnologyTag,          { 1, 1, { cmsSigSignatureType }, NULL},  &SupportedTags[35]},
5425
5426     { cmsSigColorimetricIntentImageStateTag,   { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]},
5427     { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]},
5428     { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]},
5429
5430     { cmsSigMeasurementTag,         { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]},
5431
5432     { cmsSigPs2CRD0Tag,             { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]},
5433     { cmsSigPs2CRD1Tag,             { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]},
5434     { cmsSigPs2CRD2Tag,             { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]},
5435     { cmsSigPs2CRD3Tag,             { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]},
5436     { cmsSigPs2CSATag,              { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]},
5437     { cmsSigPs2RenderingIntentTag,  { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]},
5438
5439     { cmsSigViewingCondDescTag,     { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]},
5440
5441     { cmsSigUcrBgTag,               { 1, 1, { cmsSigUcrBgType}, NULL},    &SupportedTags[47]},
5442     { cmsSigCrdInfoTag,             { 1, 1, { cmsSigCrdInfoType}, NULL},  &SupportedTags[48]},
5443
5444     { cmsSigDToB0Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
5445     { cmsSigDToB1Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
5446     { cmsSigDToB2Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
5447     { cmsSigDToB3Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
5448     { cmsSigBToD0Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
5449     { cmsSigBToD1Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
5450     { cmsSigBToD2Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
5451     { cmsSigBToD3Tag,               { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
5452
5453     { cmsSigScreeningDescTag,       { 1, 1, { cmsSigTextDescriptionType },    NULL}, &SupportedTags[57]},
5454     { cmsSigViewingConditionsTag,   { 1, 1, { cmsSigViewingConditionsType },  NULL}, &SupportedTags[58]},
5455
5456     { cmsSigScreeningTag,           { 1, 1, { cmsSigScreeningType},          NULL }, &SupportedTags[59]},
5457     { cmsSigVcgtTag,                { 1, 1, { cmsSigVcgtType},               NULL }, &SupportedTags[60]},
5458     { cmsSigMetaTag,                { 1, 1, { cmsSigDictType},               NULL }, &SupportedTags[61]},
5459     { cmsSigProfileSequenceIdTag,   { 1, 1, { cmsSigProfileSequenceIdType},  NULL }, &SupportedTags[62]},
5460     { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
5461     { cmsSigArgyllArtsTag,          { 9, 1, { cmsSigS15Fixed16ArrayType},    NULL}, NULL}
5462
5463
5464 };
5465
5466 /*
5467     Not supported                 Why
5468     =======================       =========================================
5469     cmsSigOutputResponseTag   ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5470     cmsSigNamedColorTag       ==> Deprecated
5471     cmsSigDataTag             ==> Ancient, unused
5472     cmsSigDeviceSettingsTag   ==> Deprecated, useless
5473 */
5474
5475
5476 _cmsTagPluginChunkType _cmsTagPluginChunk = { NULL };
5477
5478
5479 // Duplicates the zone of memory used by the plug-in in the new context
5480 static
5481 void DupTagList(struct _cmsContext_struct* ctx, 
5482                     const struct _cmsContext_struct* src)
5483 {
5484    _cmsTagPluginChunkType newHead = { NULL };
5485    _cmsTagLinkedList*  entry;
5486    _cmsTagLinkedList*  Anterior = NULL;
5487    _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin];
5488
5489    // Walk the list copying all nodes
5490    for (entry = head->Tag;
5491        entry != NULL;
5492        entry = entry ->Next) {
5493
5494            _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList));
5495
5496            if (newEntry == NULL) 
5497                return;
5498
5499            // We want to keep the linked list order, so this is a little bit tricky
5500            newEntry -> Next = NULL;
5501            if (Anterior)
5502                Anterior -> Next = newEntry;
5503
5504            Anterior = newEntry;
5505
5506            if (newHead.Tag == NULL)
5507                newHead.Tag = newEntry;
5508    }
5509
5510    ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType));
5511 }
5512
5513 void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, 
5514                                  const struct _cmsContext_struct* src)
5515 {
5516     if (src != NULL) {
5517
5518         DupTagList(ctx, src);
5519     }
5520     else {
5521         static _cmsTagPluginChunkType TagPluginChunk = { NULL };
5522         ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType));
5523     }
5524
5525 }
5526
5527 cmsBool  _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data)
5528 {
5529     cmsPluginTag* Plugin = (cmsPluginTag*) Data;
5530     _cmsTagLinkedList *pt;
5531     _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin);
5532
5533     if (Data == NULL) {
5534
5535         TagPluginChunk->Tag = NULL;
5536         return TRUE;
5537     }
5538
5539     pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList));
5540     if (pt == NULL) return FALSE;
5541
5542     pt ->Signature  = Plugin ->Signature;
5543     pt ->Descriptor = Plugin ->Descriptor;
5544     pt ->Next       = TagPluginChunk ->Tag;
5545
5546     TagPluginChunk ->Tag = pt;
5547     
5548     return TRUE;
5549 }
5550
5551 // Return a descriptor for a given tag or NULL
5552 cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig)
5553 {
5554     _cmsTagLinkedList* pt;
5555     _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin);
5556
5557     for (pt = TagPluginChunk->Tag;
5558              pt != NULL;
5559              pt = pt ->Next) {
5560
5561                 if (sig == pt -> Signature) return &pt ->Descriptor;
5562     }
5563
5564     for (pt = SupportedTags;
5565             pt != NULL;
5566             pt = pt ->Next) {
5567
5568                 if (sig == pt -> Signature) return &pt ->Descriptor;
5569     }
5570
5571     return NULL;
5572 }
5573