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