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