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