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