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