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