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