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