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