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