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-2017 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 readed, 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 // Ajust 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; 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 1935 if (MatMPE != NULL) { 1936 1937 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; 1938 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; 1939 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; 1940 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; 1941 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; 1942 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; 1943 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; 1944 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; 1945 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; 1946 1947 } 1948 else { 1949 1950 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 1951 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1952 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1953 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1954 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 1955 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1956 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1957 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1958 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 1959 } 1960 1961 // The prelinearization table 1962 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; 1963 1964 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); 1965 if (nTabSize == (cmsUInt32Number) -1) return FALSE; 1966 if (nTabSize > 0) { 1967 1968 // The 3D CLUT. 1969 if (clut != NULL) { 1970 1971 for (j=0; j < nTabSize; j++) { 1972 1973 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); 1974 if (!_cmsWriteUInt8Number(io, val)) return FALSE; 1975 } 1976 } 1977 } 1978 1979 // The postlinearization table 1980 if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE; 1981 1982 return TRUE; 1983 1984 cmsUNUSED_PARAMETER(nItems); 1985 } 1986 1987 1988 static 1989 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 1990 { 1991 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 1992 1993 cmsUNUSED_PARAMETER(n); 1994 cmsUNUSED_PARAMETER(self); 1995 } 1996 1997 static 1998 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr) 1999 { 2000 cmsPipelineFree((cmsPipeline*) Ptr); 2001 return; 2002 2003 cmsUNUSED_PARAMETER(self); 2004 } 2005 2006 // ******************************************************************************** 2007 // Type cmsSigLut16Type 2008 // ******************************************************************************** 2009 2010 // Read 16 bit tables as gamma functions 2011 static 2012 cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, 2013 cmsUInt32Number nChannels, cmsUInt32Number nEntries) 2014 { 2015 cmsUInt32Number i; 2016 cmsToneCurve* Tables[cmsMAXCHANNELS]; 2017 2018 // Maybe an empty table? (this is a lcms extension) 2019 if (nEntries <= 0) return TRUE; 2020 2021 // Check for malicious profiles 2022 if (nEntries < 2) return FALSE; 2023 if (nChannels > cmsMAXCHANNELS) return FALSE; 2024 2025 // Init table to zero 2026 memset(Tables, 0, sizeof(Tables)); 2027 2028 for (i=0; i < nChannels; i++) { 2029 2030 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL); 2031 if (Tables[i] == NULL) goto Error; 2032 2033 if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error; 2034 } 2035 2036 2037 // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code) 2038 if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) 2039 goto Error; 2040 2041 for (i=0; i < nChannels; i++) 2042 cmsFreeToneCurve(Tables[i]); 2043 2044 return TRUE; 2045 2046 Error: 2047 for (i=0; i < nChannels; i++) { 2048 if (Tables[i]) cmsFreeToneCurve(Tables[i]); 2049 } 2050 2051 return FALSE; 2052 } 2053 2054 static 2055 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables) 2056 { 2057 cmsUInt32Number j; 2058 cmsUInt32Number i; 2059 cmsUInt16Number val; 2060 cmsUInt32Number nEntries; 2061 2062 _cmsAssert(Tables != NULL); 2063 2064 nEntries = Tables->TheCurves[0]->nEntries; 2065 2066 for (i=0; i < Tables ->nCurves; i++) { 2067 2068 for (j=0; j < nEntries; j++) { 2069 2070 val = Tables->TheCurves[i]->Table16[j]; 2071 if (!_cmsWriteUInt16Number(io, val)) return FALSE; 2072 } 2073 } 2074 return TRUE; 2075 2076 cmsUNUSED_PARAMETER(ContextID); 2077 } 2078 2079 static 2080 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 2081 { 2082 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; 2083 cmsPipeline* NewLUT = NULL; 2084 cmsUInt32Number nTabSize; 2085 cmsFloat64Number Matrix[3*3]; 2086 cmsUInt16Number InputEntries, OutputEntries; 2087 2088 *nItems = 0; 2089 2090 if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL; 2091 if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL; 2092 if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum 2093 2094 // Padding 2095 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2096 2097 // Do some checking 2098 if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error; 2099 if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error; 2100 2101 // Allocates an empty LUT 2102 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); 2103 if (NewLUT == NULL) goto Error; 2104 2105 // Read the Matrix 2106 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; 2107 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; 2108 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; 2109 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; 2110 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; 2111 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; 2112 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; 2113 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; 2114 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; 2115 2116 2117 // Only operates on 3 channels 2118 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { 2119 2120 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) 2121 goto Error; 2122 } 2123 2124 if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error; 2125 if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error; 2126 2127 if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error; 2128 if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least 2129 2130 // Get input tables 2131 if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error; 2132 2133 // Get 3D CLUT 2134 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); 2135 if (nTabSize == (cmsUInt32Number) -1) goto Error; 2136 if (nTabSize > 0) { 2137 2138 cmsUInt16Number *T; 2139 2140 T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); 2141 if (T == NULL) goto Error; 2142 2143 if (!_cmsReadUInt16Array(io, nTabSize, T)) { 2144 _cmsFree(self ->ContextID, T); 2145 goto Error; 2146 } 2147 2148 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) { 2149 _cmsFree(self ->ContextID, T); 2150 goto Error; 2151 } 2152 _cmsFree(self ->ContextID, T); 2153 } 2154 2155 2156 // Get output tables 2157 if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error; 2158 2159 *nItems = 1; 2160 return NewLUT; 2161 2162 Error: 2163 if (NewLUT != NULL) cmsPipelineFree(NewLUT); 2164 return NULL; 2165 2166 cmsUNUSED_PARAMETER(SizeOfTag); 2167 } 2168 2169 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin. 2170 // Some empty defaults are created for missing parts 2171 2172 static 2173 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 2174 { 2175 cmsUInt32Number nTabSize; 2176 cmsPipeline* NewLUT = (cmsPipeline*) Ptr; 2177 cmsStage* mpe; 2178 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; 2179 _cmsStageMatrixData* MatMPE = NULL; 2180 _cmsStageCLutData* clut = NULL; 2181 cmsUInt32Number i, InputChannels, OutputChannels, clutPoints; 2182 2183 // Disassemble the LUT into components. 2184 mpe = NewLUT -> Elements; 2185 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) { 2186 2187 MatMPE = (_cmsStageMatrixData*) mpe ->Data; 2188 mpe = mpe -> Next; 2189 } 2190 2191 2192 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { 2193 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; 2194 mpe = mpe -> Next; 2195 } 2196 2197 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { 2198 clut = (_cmsStageCLutData*) mpe -> Data; 2199 mpe = mpe ->Next; 2200 } 2201 2202 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { 2203 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; 2204 mpe = mpe -> Next; 2205 } 2206 2207 // That should be all 2208 if (mpe != NULL) { 2209 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16"); 2210 return FALSE; 2211 } 2212 2213 InputChannels = cmsPipelineInputChannels(NewLUT); 2214 OutputChannels = cmsPipelineOutputChannels(NewLUT); 2215 2216 if (clut == NULL) 2217 clutPoints = 0; 2218 else 2219 clutPoints = clut->Params->nSamples[0]; 2220 2221 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE; 2222 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE; 2223 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; 2224 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding 2225 2226 2227 if (MatMPE != NULL) { 2228 2229 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; 2230 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; 2231 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; 2232 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; 2233 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; 2234 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; 2235 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; 2236 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; 2237 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; 2238 } 2239 else { 2240 2241 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 2242 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2243 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2244 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2245 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 2246 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2247 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2248 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2249 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 2250 } 2251 2252 2253 if (PreMPE != NULL) { 2254 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE; 2255 } else { 2256 if (!_cmsWriteUInt16Number(io, 2)) return FALSE; 2257 } 2258 2259 if (PostMPE != NULL) { 2260 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE; 2261 } else { 2262 if (!_cmsWriteUInt16Number(io, 2)) return FALSE; 2263 2264 } 2265 2266 // The prelinearization table 2267 2268 if (PreMPE != NULL) { 2269 if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; 2270 } 2271 else { 2272 for (i=0; i < InputChannels; i++) { 2273 2274 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2275 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; 2276 } 2277 } 2278 2279 nTabSize = uipow(OutputChannels, clutPoints, InputChannels); 2280 if (nTabSize == (cmsUInt32Number) -1) return FALSE; 2281 if (nTabSize > 0) { 2282 // The 3D CLUT. 2283 if (clut != NULL) { 2284 if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; 2285 } 2286 } 2287 2288 // The postlinearization table 2289 if (PostMPE != NULL) { 2290 if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE; 2291 } 2292 else { 2293 for (i=0; i < OutputChannels; i++) { 2294 2295 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2296 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; 2297 } 2298 } 2299 2300 return TRUE; 2301 2302 cmsUNUSED_PARAMETER(nItems); 2303 } 2304 2305 static 2306 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 2307 { 2308 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 2309 2310 cmsUNUSED_PARAMETER(n); 2311 cmsUNUSED_PARAMETER(self); 2312 } 2313 2314 static 2315 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr) 2316 { 2317 cmsPipelineFree((cmsPipeline*) Ptr); 2318 return; 2319 2320 cmsUNUSED_PARAMETER(self); 2321 } 2322 2323 2324 // ******************************************************************************** 2325 // Type cmsSigLutAToBType 2326 // ******************************************************************************** 2327 2328 2329 // V4 stuff. Read matrix for LutAtoB and LutBtoA 2330 2331 static 2332 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset) 2333 { 2334 cmsFloat64Number dMat[3*3]; 2335 cmsFloat64Number dOff[3]; 2336 cmsStage* Mat; 2337 2338 // Go to address 2339 if (!io -> Seek(io, Offset)) return NULL; 2340 2341 // Read the Matrix 2342 if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL; 2343 if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL; 2344 if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL; 2345 if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL; 2346 if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL; 2347 if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL; 2348 if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL; 2349 if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL; 2350 if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL; 2351 2352 if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL; 2353 if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL; 2354 if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL; 2355 2356 Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff); 2357 2358 return Mat; 2359 } 2360 2361 2362 2363 2364 // V4 stuff. Read CLUT part for LutAtoB and LutBtoA 2365 2366 static 2367 cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, 2368 cmsUInt32Number Offset, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels) 2369 { 2370 cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension. 2371 cmsUInt32Number GridPoints[cmsMAXCHANNELS], i; 2372 cmsUInt8Number Precision; 2373 cmsStage* CLUT; 2374 _cmsStageCLutData* Data; 2375 2376 if (!io -> Seek(io, Offset)) return NULL; 2377 if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL; 2378 2379 2380 for (i=0; i < cmsMAXCHANNELS; i++) { 2381 2382 if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least 2383 GridPoints[i] = gridPoints8[i]; 2384 } 2385 2386 if (!_cmsReadUInt8Number(io, &Precision)) return NULL; 2387 2388 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2389 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2390 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2391 2392 CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL); 2393 if (CLUT == NULL) return NULL; 2394 2395 Data = (_cmsStageCLutData*) CLUT ->Data; 2396 2397 // Precision can be 1 or 2 bytes 2398 if (Precision == 1) { 2399 2400 cmsUInt8Number v; 2401 2402 for (i=0; i < Data ->nEntries; i++) { 2403 2404 if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) { 2405 cmsStageFree(CLUT); 2406 return NULL; 2407 } 2408 Data ->Tab.T[i] = FROM_8_TO_16(v); 2409 } 2410 2411 } 2412 else 2413 if (Precision == 2) { 2414 2415 if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) { 2416 cmsStageFree(CLUT); 2417 return NULL; 2418 } 2419 } 2420 else { 2421 cmsStageFree(CLUT); 2422 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); 2423 return NULL; 2424 } 2425 2426 return CLUT; 2427 } 2428 2429 static 2430 cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) 2431 { 2432 cmsTagTypeSignature BaseType; 2433 cmsUInt32Number nItems; 2434 2435 BaseType = _cmsReadTypeBase(io); 2436 switch (BaseType) { 2437 2438 case cmsSigCurveType: 2439 return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0); 2440 2441 case cmsSigParametricCurveType: 2442 return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0); 2443 2444 default: 2445 { 2446 char String[5]; 2447 2448 _cmsTagSignature2String(String, (cmsTagSignature) BaseType); 2449 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); 2450 } 2451 return NULL; 2452 } 2453 } 2454 2455 2456 // Read a set of curves from specific offset 2457 static 2458 cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves) 2459 { 2460 cmsToneCurve* Curves[cmsMAXCHANNELS]; 2461 cmsUInt32Number i; 2462 cmsStage* Lin = NULL; 2463 2464 if (nCurves > cmsMAXCHANNELS) return FALSE; 2465 2466 if (!io -> Seek(io, Offset)) return FALSE; 2467 2468 for (i=0; i < nCurves; i++) 2469 Curves[i] = NULL; 2470 2471 for (i=0; i < nCurves; i++) { 2472 2473 Curves[i] = ReadEmbeddedCurve(self, io); 2474 if (Curves[i] == NULL) goto Error; 2475 if (!_cmsReadAlignment(io)) goto Error; 2476 2477 } 2478 2479 Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves); 2480 2481 Error: 2482 for (i=0; i < nCurves; i++) 2483 cmsFreeToneCurve(Curves[i]); 2484 2485 return Lin; 2486 } 2487 2488 2489 // LutAtoB type 2490 2491 // This structure represents a colour transform. The type contains up to five processing 2492 // elements which are stored in the AtoBTag tag in the following order: a set of one 2493 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves, 2494 // a multidimensional lookup table, and a set of one dimensional output curves. 2495 // Data are processed using these elements via the following sequence: 2496 // 2497 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves). 2498 // 2499 /* 2500 It is possible to use any or all of these processing elements. At least one processing element 2501 must be included.Only the following combinations are allowed: 2502 2503 B 2504 M - Matrix - B 2505 A - CLUT - B 2506 A - CLUT - M - Matrix - B 2507 2508 */ 2509 2510 static 2511 void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 2512 { 2513 cmsUInt32Number BaseOffset; 2514 cmsUInt8Number inputChan; // Number of input channels 2515 cmsUInt8Number outputChan; // Number of output channels 2516 cmsUInt32Number offsetB; // Offset to first "B" curve 2517 cmsUInt32Number offsetMat; // Offset to matrix 2518 cmsUInt32Number offsetM; // Offset to first "M" curve 2519 cmsUInt32Number offsetC; // Offset to CLUT 2520 cmsUInt32Number offsetA; // Offset to first "A" curve 2521 cmsPipeline* NewLUT = NULL; 2522 2523 2524 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2525 2526 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; 2527 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; 2528 2529 if (!_cmsReadUInt16Number(io, NULL)) return NULL; 2530 2531 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; 2532 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; 2533 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; 2534 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; 2535 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; 2536 2537 if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; 2538 if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; 2539 2540 // Allocates an empty LUT 2541 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); 2542 if (NewLUT == NULL) return NULL; 2543 2544 if (offsetA!= 0) { 2545 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan))) 2546 goto Error; 2547 } 2548 2549 if (offsetC != 0) { 2550 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) 2551 goto Error; 2552 } 2553 2554 if (offsetM != 0) { 2555 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan))) 2556 goto Error; 2557 } 2558 2559 if (offsetMat != 0) { 2560 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) 2561 goto Error; 2562 } 2563 2564 if (offsetB != 0) { 2565 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan))) 2566 goto Error; 2567 } 2568 2569 *nItems = 1; 2570 return NewLUT; 2571 Error: 2572 cmsPipelineFree(NewLUT); 2573 return NULL; 2574 2575 cmsUNUSED_PARAMETER(SizeOfTag); 2576 } 2577 2578 // Write a set of curves 2579 static 2580 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe) 2581 { 2582 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data; 2583 2584 // Write the Matrix 2585 if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE; 2586 if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE; 2587 if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE; 2588 if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE; 2589 if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE; 2590 if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE; 2591 if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE; 2592 if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE; 2593 if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE; 2594 2595 if (m ->Offset != NULL) { 2596 2597 if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE; 2598 if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE; 2599 if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE; 2600 } 2601 else { 2602 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2603 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2604 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2605 2606 } 2607 2608 2609 return TRUE; 2610 2611 cmsUNUSED_PARAMETER(self); 2612 } 2613 2614 2615 // Write a set of curves 2616 static 2617 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe) 2618 { 2619 cmsUInt32Number i, n; 2620 cmsTagTypeSignature CurrentType; 2621 cmsToneCurve** Curves; 2622 2623 2624 n = cmsStageOutputChannels(mpe); 2625 Curves = _cmsStageGetPtrToCurveSet(mpe); 2626 2627 for (i=0; i < n; i++) { 2628 2629 // If this is a table-based curve, use curve type even on V4 2630 CurrentType = Type; 2631 2632 if ((Curves[i] ->nSegments == 0)|| 2633 ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) ) 2634 CurrentType = cmsSigCurveType; 2635 else 2636 if (Curves[i] ->Segments[0].Type < 0) 2637 CurrentType = cmsSigCurveType; 2638 2639 if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE; 2640 2641 switch (CurrentType) { 2642 2643 case cmsSigCurveType: 2644 if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE; 2645 break; 2646 2647 case cmsSigParametricCurveType: 2648 if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE; 2649 break; 2650 2651 default: 2652 { 2653 char String[5]; 2654 2655 _cmsTagSignature2String(String, (cmsTagSignature) Type); 2656 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); 2657 } 2658 return FALSE; 2659 } 2660 2661 if (!_cmsWriteAlignment(io)) return FALSE; 2662 } 2663 2664 2665 return TRUE; 2666 } 2667 2668 2669 static 2670 cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe) 2671 { 2672 cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension. 2673 cmsUInt32Number i; 2674 _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data; 2675 2676 if (CLUT ->HasFloatValues) { 2677 cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only"); 2678 return FALSE; 2679 } 2680 2681 memset(gridPoints, 0, sizeof(gridPoints)); 2682 for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++) 2683 gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i]; 2684 2685 if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE; 2686 2687 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE; 2688 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; 2689 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; 2690 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; 2691 2692 // Precision can be 1 or 2 bytes 2693 if (Precision == 1) { 2694 2695 for (i=0; i < CLUT->nEntries; i++) { 2696 2697 if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE; 2698 } 2699 } 2700 else 2701 if (Precision == 2) { 2702 2703 if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE; 2704 } 2705 else { 2706 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); 2707 return FALSE; 2708 } 2709 2710 if (!_cmsWriteAlignment(io)) return FALSE; 2711 2712 return TRUE; 2713 } 2714 2715 2716 2717 2718 static 2719 cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 2720 { 2721 cmsPipeline* Lut = (cmsPipeline*) Ptr; 2722 cmsUInt32Number inputChan, outputChan; 2723 cmsStage *A = NULL, *B = NULL, *M = NULL; 2724 cmsStage * Matrix = NULL; 2725 cmsStage * CLUT = NULL; 2726 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; 2727 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; 2728 2729 // Get the base for all offsets 2730 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2731 2732 if (Lut ->Elements != NULL) 2733 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) 2734 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B)) 2735 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B)) 2736 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, 2737 cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) { 2738 2739 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB"); 2740 return FALSE; 2741 } 2742 2743 // Get input, output channels 2744 inputChan = cmsPipelineInputChannels(Lut); 2745 outputChan = cmsPipelineOutputChannels(Lut); 2746 2747 // Write channel count 2748 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; 2749 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; 2750 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2751 2752 // Keep directory to be filled latter 2753 DirectoryPos = io ->Tell(io); 2754 2755 // Write the directory 2756 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2757 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2758 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2759 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2760 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2761 2762 if (A != NULL) { 2763 2764 offsetA = io ->Tell(io) - BaseOffset; 2765 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; 2766 } 2767 2768 if (CLUT != NULL) { 2769 offsetC = io ->Tell(io) - BaseOffset; 2770 if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE; 2771 2772 } 2773 if (M != NULL) { 2774 2775 offsetM = io ->Tell(io) - BaseOffset; 2776 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; 2777 } 2778 2779 if (Matrix != NULL) { 2780 offsetMat = io ->Tell(io) - BaseOffset; 2781 if (!WriteMatrix(self, io, Matrix)) return FALSE; 2782 } 2783 2784 if (B != NULL) { 2785 2786 offsetB = io ->Tell(io) - BaseOffset; 2787 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; 2788 } 2789 2790 CurrentPos = io ->Tell(io); 2791 2792 if (!io ->Seek(io, DirectoryPos)) return FALSE; 2793 2794 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; 2795 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; 2796 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; 2797 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; 2798 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; 2799 2800 if (!io ->Seek(io, CurrentPos)) return FALSE; 2801 2802 return TRUE; 2803 2804 cmsUNUSED_PARAMETER(nItems); 2805 } 2806 2807 2808 static 2809 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 2810 { 2811 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 2812 2813 cmsUNUSED_PARAMETER(n); 2814 cmsUNUSED_PARAMETER(self); 2815 } 2816 2817 static 2818 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr) 2819 { 2820 cmsPipelineFree((cmsPipeline*) Ptr); 2821 return; 2822 2823 cmsUNUSED_PARAMETER(self); 2824 } 2825 2826 2827 // LutBToA type 2828 2829 static 2830 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 2831 { 2832 cmsUInt8Number inputChan; // Number of input channels 2833 cmsUInt8Number outputChan; // Number of output channels 2834 cmsUInt32Number BaseOffset; // Actual position in file 2835 cmsUInt32Number offsetB; // Offset to first "B" curve 2836 cmsUInt32Number offsetMat; // Offset to matrix 2837 cmsUInt32Number offsetM; // Offset to first "M" curve 2838 cmsUInt32Number offsetC; // Offset to CLUT 2839 cmsUInt32Number offsetA; // Offset to first "A" curve 2840 cmsPipeline* NewLUT = NULL; 2841 2842 2843 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2844 2845 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; 2846 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; 2847 2848 if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL; 2849 if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL; 2850 2851 // Padding 2852 if (!_cmsReadUInt16Number(io, NULL)) return NULL; 2853 2854 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; 2855 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; 2856 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; 2857 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; 2858 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; 2859 2860 // Allocates an empty LUT 2861 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); 2862 if (NewLUT == NULL) return NULL; 2863 2864 if (offsetB != 0) { 2865 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan))) 2866 goto Error; 2867 } 2868 2869 if (offsetMat != 0) { 2870 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) 2871 goto Error; 2872 } 2873 2874 if (offsetM != 0) { 2875 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan))) 2876 goto Error; 2877 } 2878 2879 if (offsetC != 0) { 2880 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) 2881 goto Error; 2882 } 2883 2884 if (offsetA!= 0) { 2885 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan))) 2886 goto Error; 2887 } 2888 2889 *nItems = 1; 2890 return NewLUT; 2891 Error: 2892 cmsPipelineFree(NewLUT); 2893 return NULL; 2894 2895 cmsUNUSED_PARAMETER(SizeOfTag); 2896 } 2897 2898 2899 /* 2900 B 2901 B - Matrix - M 2902 B - CLUT - A 2903 B - Matrix - M - CLUT - A 2904 */ 2905 2906 static 2907 cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 2908 { 2909 cmsPipeline* Lut = (cmsPipeline*) Ptr; 2910 cmsUInt32Number inputChan, outputChan; 2911 cmsStage *A = NULL, *B = NULL, *M = NULL; 2912 cmsStage *Matrix = NULL; 2913 cmsStage *CLUT = NULL; 2914 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; 2915 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; 2916 2917 2918 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2919 2920 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) 2921 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M)) 2922 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A)) 2923 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, 2924 cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) { 2925 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA"); 2926 return FALSE; 2927 } 2928 2929 inputChan = cmsPipelineInputChannels(Lut); 2930 outputChan = cmsPipelineOutputChannels(Lut); 2931 2932 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; 2933 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; 2934 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2935 2936 DirectoryPos = io ->Tell(io); 2937 2938 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2939 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2940 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2941 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2942 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2943 2944 if (A != NULL) { 2945 2946 offsetA = io ->Tell(io) - BaseOffset; 2947 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; 2948 } 2949 2950 if (CLUT != NULL) { 2951 offsetC = io ->Tell(io) - BaseOffset; 2952 if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE; 2953 2954 } 2955 if (M != NULL) { 2956 2957 offsetM = io ->Tell(io) - BaseOffset; 2958 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; 2959 } 2960 2961 if (Matrix != NULL) { 2962 offsetMat = io ->Tell(io) - BaseOffset; 2963 if (!WriteMatrix(self, io, Matrix)) return FALSE; 2964 } 2965 2966 if (B != NULL) { 2967 2968 offsetB = io ->Tell(io) - BaseOffset; 2969 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; 2970 } 2971 2972 CurrentPos = io ->Tell(io); 2973 2974 if (!io ->Seek(io, DirectoryPos)) return FALSE; 2975 2976 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; 2977 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; 2978 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; 2979 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; 2980 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; 2981 2982 if (!io ->Seek(io, CurrentPos)) return FALSE; 2983 2984 return TRUE; 2985 2986 cmsUNUSED_PARAMETER(nItems); 2987 } 2988 2989 2990 2991 static 2992 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 2993 { 2994 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 2995 2996 cmsUNUSED_PARAMETER(n); 2997 cmsUNUSED_PARAMETER(self); 2998 } 2999 3000 static 3001 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr) 3002 { 3003 cmsPipelineFree((cmsPipeline*) Ptr); 3004 return; 3005 3006 cmsUNUSED_PARAMETER(self); 3007 } 3008 3009 3010 3011 // ******************************************************************************** 3012 // Type cmsSigColorantTableType 3013 // ******************************************************************************** 3014 /* 3015 The purpose of this tag is to identify the colorants used in the profile by a 3016 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous 3017 value. The first colorant listed is the colorant of the first device channel of 3018 a lut tag. The second colorant listed is the colorant of the second device channel 3019 of a lut tag, and so on. 3020 */ 3021 3022 static 3023 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3024 { 3025 cmsUInt32Number i, Count; 3026 cmsNAMEDCOLORLIST* List; 3027 char Name[34]; 3028 cmsUInt16Number PCS[3]; 3029 3030 3031 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 3032 3033 if (Count > cmsMAXCHANNELS) { 3034 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count); 3035 return NULL; 3036 } 3037 3038 List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", ""); 3039 for (i=0; i < Count; i++) { 3040 3041 if (io ->Read(io, Name, 32, 1) != 1) goto Error; 3042 Name[32] = 0; 3043 3044 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; 3045 3046 if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error; 3047 3048 } 3049 3050 *nItems = 1; 3051 return List; 3052 3053 Error: 3054 *nItems = 0; 3055 cmsFreeNamedColorList(List); 3056 return NULL; 3057 3058 cmsUNUSED_PARAMETER(SizeOfTag); 3059 } 3060 3061 3062 3063 // Saves a colorant table. It is using the named color structure for simplicity sake 3064 static 3065 cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3066 { 3067 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; 3068 cmsUInt32Number i, nColors; 3069 3070 nColors = cmsNamedColorCount(NamedColorList); 3071 3072 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; 3073 3074 for (i=0; i < nColors; i++) { 3075 3076 char root[cmsMAX_PATH]; 3077 cmsUInt16Number PCS[3]; 3078 3079 memset(root, 0, sizeof(root)); 3080 3081 if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0; 3082 root[32] = 0; 3083 3084 if (!io ->Write(io, 32, root)) return FALSE; 3085 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; 3086 } 3087 3088 return TRUE; 3089 3090 cmsUNUSED_PARAMETER(nItems); 3091 cmsUNUSED_PARAMETER(self); 3092 } 3093 3094 3095 static 3096 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3097 { 3098 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; 3099 return (void*) cmsDupNamedColorList(nc); 3100 3101 cmsUNUSED_PARAMETER(n); 3102 cmsUNUSED_PARAMETER(self); 3103 } 3104 3105 3106 static 3107 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) 3108 { 3109 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); 3110 return; 3111 3112 cmsUNUSED_PARAMETER(self); 3113 } 3114 3115 3116 // ******************************************************************************** 3117 // Type cmsSigNamedColor2Type 3118 // ******************************************************************************** 3119 // 3120 //The namedColor2Type is a count value and array of structures that provide color 3121 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional 3122 //device representation of the color are given. Both representations are 16-bit values. 3123 //The device representation corresponds to the headers color space of data field. 3124 //This representation should be consistent with the number of device components 3125 //field in the namedColor2Type. If this field is 0, device coordinates are not provided. 3126 //The PCS representation corresponds to the headers PCS field. The PCS representation 3127 //is always provided. Color names are fixed-length, 32-byte fields including null 3128 //termination. In order to maintain maximum portability, it is strongly recommended 3129 //that special characters of the 7-bit ASCII set not be used. 3130 3131 static 3132 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3133 { 3134 3135 cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use 3136 cmsUInt32Number count; // Count of named colors 3137 cmsUInt32Number nDeviceCoords; // Num of device coordinates 3138 char prefix[32]; // Prefix for each color name 3139 char suffix[32]; // Suffix for each color name 3140 cmsNAMEDCOLORLIST* v; 3141 cmsUInt32Number i; 3142 3143 3144 *nItems = 0; 3145 if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL; 3146 if (!_cmsReadUInt32Number(io, &count)) return NULL; 3147 if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL; 3148 3149 if (io -> Read(io, prefix, 32, 1) != 1) return NULL; 3150 if (io -> Read(io, suffix, 32, 1) != 1) return NULL; 3151 3152 prefix[31] = suffix[31] = 0; 3153 3154 v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix); 3155 if (v == NULL) { 3156 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count); 3157 return NULL; 3158 } 3159 3160 if (nDeviceCoords > cmsMAXCHANNELS) { 3161 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords); 3162 goto Error; 3163 } 3164 for (i=0; i < count; i++) { 3165 3166 cmsUInt16Number PCS[3]; 3167 cmsUInt16Number Colorant[cmsMAXCHANNELS]; 3168 char Root[33]; 3169 3170 memset(Colorant, 0, sizeof(Colorant)); 3171 if (io -> Read(io, Root, 32, 1) != 1) goto Error; 3172 Root[32] = 0; // To prevent exploits 3173 3174 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; 3175 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; 3176 3177 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error; 3178 } 3179 3180 *nItems = 1; 3181 return (void*) v ; 3182 3183 Error: 3184 cmsFreeNamedColorList(v); 3185 return NULL; 3186 3187 cmsUNUSED_PARAMETER(SizeOfTag); 3188 } 3189 3190 3191 // Saves a named color list into a named color profile 3192 static 3193 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3194 { 3195 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; 3196 char prefix[33]; // Prefix for each color name 3197 char suffix[33]; // Suffix for each color name 3198 cmsUInt32Number i, nColors; 3199 3200 nColors = cmsNamedColorCount(NamedColorList); 3201 3202 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 3203 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; 3204 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE; 3205 3206 strncpy(prefix, (const char*) NamedColorList->Prefix, 32); 3207 strncpy(suffix, (const char*) NamedColorList->Suffix, 32); 3208 3209 suffix[32] = prefix[32] = 0; 3210 3211 if (!io ->Write(io, 32, prefix)) return FALSE; 3212 if (!io ->Write(io, 32, suffix)) return FALSE; 3213 3214 for (i=0; i < nColors; i++) { 3215 3216 cmsUInt16Number PCS[3]; 3217 cmsUInt16Number Colorant[cmsMAXCHANNELS]; 3218 char Root[cmsMAX_PATH]; 3219 3220 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; 3221 Root[32] = 0; 3222 if (!io ->Write(io, 32 , Root)) return FALSE; 3223 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; 3224 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE; 3225 } 3226 3227 return TRUE; 3228 3229 cmsUNUSED_PARAMETER(nItems); 3230 cmsUNUSED_PARAMETER(self); 3231 } 3232 3233 static 3234 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3235 { 3236 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; 3237 3238 return (void*) cmsDupNamedColorList(nc); 3239 3240 cmsUNUSED_PARAMETER(n); 3241 cmsUNUSED_PARAMETER(self); 3242 } 3243 3244 3245 static 3246 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) 3247 { 3248 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); 3249 return; 3250 3251 cmsUNUSED_PARAMETER(self); 3252 } 3253 3254 3255 // ******************************************************************************** 3256 // Type cmsSigProfileSequenceDescType 3257 // ******************************************************************************** 3258 3259 // This type is an array of structures, each of which contains information from the 3260 // header fields and tags from the original profiles which were combined to create 3261 // the final profile. The order of the structures is the order in which the profiles 3262 // were combined and includes a structure for the final profile. This provides a 3263 // description of the profile sequence from source to destination, 3264 // typically used with the DeviceLink profile. 3265 3266 static 3267 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag) 3268 { 3269 cmsTagTypeSignature BaseType; 3270 cmsUInt32Number nItems; 3271 3272 BaseType = _cmsReadTypeBase(io); 3273 3274 switch (BaseType) { 3275 3276 case cmsSigTextType: 3277 if (*mlu) cmsMLUfree(*mlu); 3278 *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag); 3279 return (*mlu != NULL); 3280 3281 case cmsSigTextDescriptionType: 3282 if (*mlu) cmsMLUfree(*mlu); 3283 *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag); 3284 return (*mlu != NULL); 3285 3286 /* 3287 TBD: Size is needed for MLU, and we have no idea on which is the available size 3288 */ 3289 3290 case cmsSigMultiLocalizedUnicodeType: 3291 if (*mlu) cmsMLUfree(*mlu); 3292 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag); 3293 return (*mlu != NULL); 3294 3295 default: return FALSE; 3296 } 3297 } 3298 3299 3300 static 3301 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3302 { 3303 cmsSEQ* OutSeq; 3304 cmsUInt32Number i, Count; 3305 3306 *nItems = 0; 3307 3308 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 3309 3310 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3311 SizeOfTag -= sizeof(cmsUInt32Number); 3312 3313 3314 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); 3315 if (OutSeq == NULL) return NULL; 3316 3317 OutSeq ->n = Count; 3318 3319 // Get structures as well 3320 3321 for (i=0; i < Count; i++) { 3322 3323 cmsPSEQDESC* sec = &OutSeq -> seq[i]; 3324 3325 if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error; 3326 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; 3327 SizeOfTag -= sizeof(cmsUInt32Number); 3328 3329 if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error; 3330 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; 3331 SizeOfTag -= sizeof(cmsUInt32Number); 3332 3333 if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error; 3334 if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error; 3335 SizeOfTag -= sizeof(cmsUInt64Number); 3336 3337 if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error; 3338 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; 3339 SizeOfTag -= sizeof(cmsUInt32Number); 3340 3341 if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error; 3342 if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error; 3343 } 3344 3345 *nItems = 1; 3346 return OutSeq; 3347 3348 Error: 3349 cmsFreeProfileSequenceDescription(OutSeq); 3350 return NULL; 3351 } 3352 3353 3354 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode 3355 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack 3356 static 3357 cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text) 3358 { 3359 if (self ->ICCVersion < 0x4000000) { 3360 3361 if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; 3362 return Type_Text_Description_Write(self, io, Text, 1); 3363 } 3364 else { 3365 if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE; 3366 return Type_MLU_Write(self, io, Text, 1); 3367 } 3368 } 3369 3370 3371 static 3372 cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3373 { 3374 cmsSEQ* Seq = (cmsSEQ*) Ptr; 3375 cmsUInt32Number i; 3376 3377 if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE; 3378 3379 for (i=0; i < Seq ->n; i++) { 3380 3381 cmsPSEQDESC* sec = &Seq -> seq[i]; 3382 3383 if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE; 3384 if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE; 3385 if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE; 3386 if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE; 3387 3388 if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; 3389 if (!SaveDescription(self, io, sec ->Model)) return FALSE; 3390 } 3391 3392 return TRUE; 3393 3394 cmsUNUSED_PARAMETER(nItems); 3395 } 3396 3397 3398 static 3399 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3400 { 3401 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); 3402 3403 cmsUNUSED_PARAMETER(n); 3404 cmsUNUSED_PARAMETER(self); 3405 } 3406 3407 static 3408 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr) 3409 { 3410 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); 3411 return; 3412 3413 cmsUNUSED_PARAMETER(self); 3414 } 3415 3416 3417 // ******************************************************************************** 3418 // Type cmsSigProfileSequenceIdType 3419 // ******************************************************************************** 3420 /* 3421 In certain workflows using ICC Device Link Profiles, it is necessary to identify the 3422 original profiles that were combined to create the Device Link Profile. 3423 This type is an array of structures, each of which contains information for 3424 identification of a profile used in a sequence 3425 */ 3426 3427 3428 static 3429 cmsBool ReadSeqID(struct _cms_typehandler_struct* self, 3430 cmsIOHANDLER* io, 3431 void* Cargo, 3432 cmsUInt32Number n, 3433 cmsUInt32Number SizeOfTag) 3434 { 3435 cmsSEQ* OutSeq = (cmsSEQ*) Cargo; 3436 cmsPSEQDESC* seq = &OutSeq ->seq[n]; 3437 3438 if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE; 3439 if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE; 3440 3441 return TRUE; 3442 } 3443 3444 3445 3446 static 3447 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3448 { 3449 cmsSEQ* OutSeq; 3450 cmsUInt32Number Count; 3451 cmsUInt32Number BaseOffset; 3452 3453 *nItems = 0; 3454 3455 // Get actual position as a basis for element offsets 3456 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 3457 3458 // Get table count 3459 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 3460 SizeOfTag -= sizeof(cmsUInt32Number); 3461 3462 // Allocate an empty structure 3463 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); 3464 if (OutSeq == NULL) return NULL; 3465 3466 3467 // Read the position table 3468 if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) { 3469 3470 cmsFreeProfileSequenceDescription(OutSeq); 3471 return NULL; 3472 } 3473 3474 // Success 3475 *nItems = 1; 3476 return OutSeq; 3477 3478 } 3479 3480 3481 static 3482 cmsBool WriteSeqID(struct _cms_typehandler_struct* self, 3483 cmsIOHANDLER* io, 3484 void* Cargo, 3485 cmsUInt32Number n, 3486 cmsUInt32Number SizeOfTag) 3487 { 3488 cmsSEQ* Seq = (cmsSEQ*) Cargo; 3489 3490 if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE; 3491 3492 // Store here the MLU 3493 if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE; 3494 3495 return TRUE; 3496 3497 cmsUNUSED_PARAMETER(SizeOfTag); 3498 } 3499 3500 static 3501 cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3502 { 3503 cmsSEQ* Seq = (cmsSEQ*) Ptr; 3504 cmsUInt32Number BaseOffset; 3505 3506 // Keep the base offset 3507 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 3508 3509 // This is the table count 3510 if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE; 3511 3512 // This is the position table and content 3513 if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE; 3514 3515 return TRUE; 3516 3517 cmsUNUSED_PARAMETER(nItems); 3518 } 3519 3520 static 3521 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3522 { 3523 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); 3524 3525 cmsUNUSED_PARAMETER(n); 3526 cmsUNUSED_PARAMETER(self); 3527 } 3528 3529 static 3530 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr) 3531 { 3532 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); 3533 return; 3534 3535 cmsUNUSED_PARAMETER(self); 3536 } 3537 3538 3539 // ******************************************************************************** 3540 // Type cmsSigUcrBgType 3541 // ******************************************************************************** 3542 /* 3543 This type contains curves representing the under color removal and black 3544 generation and a text string which is a general description of the method used 3545 for the ucr/bg. 3546 */ 3547 3548 static 3549 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3550 { 3551 cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); 3552 cmsUInt32Number CountUcr, CountBg; 3553 char* ASCIIString; 3554 3555 *nItems = 0; 3556 if (n == NULL) return NULL; 3557 3558 // First curve is Under color removal 3559 if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL; 3560 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3561 SizeOfTag -= sizeof(cmsUInt32Number); 3562 3563 n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL); 3564 if (n ->Ucr == NULL) return NULL; 3565 3566 if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL; 3567 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3568 SizeOfTag -= CountUcr * sizeof(cmsUInt16Number); 3569 3570 // Second curve is Black generation 3571 if (!_cmsReadUInt32Number(io, &CountBg)) return NULL; 3572 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3573 SizeOfTag -= sizeof(cmsUInt32Number); 3574 3575 n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL); 3576 if (n ->Bg == NULL) return NULL; 3577 if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL; 3578 if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL; 3579 SizeOfTag -= CountBg * sizeof(cmsUInt16Number); 3580 if (SizeOfTag == UINT_MAX) return NULL; 3581 3582 // Now comes the text. The length is specified by the tag size 3583 n ->Desc = cmsMLUalloc(self ->ContextID, 1); 3584 if (n ->Desc == NULL) return NULL; 3585 3586 ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); 3587 if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL; 3588 ASCIIString[SizeOfTag] = 0; 3589 cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString); 3590 _cmsFree(self ->ContextID, ASCIIString); 3591 3592 *nItems = 1; 3593 return (void*) n; 3594 } 3595 3596 static 3597 cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3598 { 3599 cmsUcrBg* Value = (cmsUcrBg*) Ptr; 3600 cmsUInt32Number TextSize; 3601 char* Text; 3602 3603 // First curve is Under color removal 3604 if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE; 3605 if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE; 3606 3607 // Then black generation 3608 if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE; 3609 if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE; 3610 3611 // Now comes the text. The length is specified by the tag size 3612 TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0); 3613 Text = (char*) _cmsMalloc(self ->ContextID, TextSize); 3614 if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE; 3615 3616 if (!io ->Write(io, TextSize, Text)) return FALSE; 3617 _cmsFree(self ->ContextID, Text); 3618 3619 return TRUE; 3620 3621 cmsUNUSED_PARAMETER(nItems); 3622 } 3623 3624 static 3625 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3626 { 3627 cmsUcrBg* Src = (cmsUcrBg*) Ptr; 3628 cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); 3629 3630 if (NewUcrBg == NULL) return NULL; 3631 3632 NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg); 3633 NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr); 3634 NewUcrBg ->Desc = cmsMLUdup(Src ->Desc); 3635 3636 return (void*) NewUcrBg; 3637 3638 cmsUNUSED_PARAMETER(n); 3639 } 3640 3641 static 3642 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr) 3643 { 3644 cmsUcrBg* Src = (cmsUcrBg*) Ptr; 3645 3646 if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr); 3647 if (Src ->Bg) cmsFreeToneCurve(Src ->Bg); 3648 if (Src ->Desc) cmsMLUfree(Src ->Desc); 3649 3650 _cmsFree(self ->ContextID, Ptr); 3651 } 3652 3653 // ******************************************************************************** 3654 // Type cmsSigCrdInfoType 3655 // ******************************************************************************** 3656 3657 /* 3658 This type contains the PostScript product name to which this profile corresponds 3659 and the names of the companion CRDs. Recall that a single profile can generate 3660 multiple CRDs. It is implemented as a MLU being the language code "PS" and then 3661 country varies for each element: 3662 3663 nm: PostScript product name 3664 #0: Rendering intent 0 CRD name 3665 #1: Rendering intent 1 CRD name 3666 #2: Rendering intent 2 CRD name 3667 #3: Rendering intent 3 CRD name 3668 */ 3669 3670 3671 3672 // Auxiliary, read an string specified as count + string 3673 static 3674 cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section) 3675 { 3676 cmsUInt32Number Count; 3677 char* Text; 3678 3679 if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE; 3680 3681 if (!_cmsReadUInt32Number(io, &Count)) return FALSE; 3682 3683 if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE; 3684 if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE; 3685 3686 Text = (char*) _cmsMalloc(self ->ContextID, Count+1); 3687 if (Text == NULL) return FALSE; 3688 3689 if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) { 3690 _cmsFree(self ->ContextID, Text); 3691 return FALSE; 3692 } 3693 3694 Text[Count] = 0; 3695 3696 cmsMLUsetASCII(mlu, "PS", Section, Text); 3697 _cmsFree(self ->ContextID, Text); 3698 3699 *SizeOfTag -= (Count + sizeof(cmsUInt32Number)); 3700 return TRUE; 3701 } 3702 3703 static 3704 cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section) 3705 { 3706 cmsUInt32Number TextSize; 3707 char* Text; 3708 3709 TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0); 3710 Text = (char*) _cmsMalloc(self ->ContextID, TextSize); 3711 3712 if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE; 3713 3714 if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE; 3715 3716 if (!io ->Write(io, TextSize, Text)) return FALSE; 3717 _cmsFree(self ->ContextID, Text); 3718 3719 return TRUE; 3720 } 3721 3722 static 3723 void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3724 { 3725 cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5); 3726 3727 *nItems = 0; 3728 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error; 3729 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error; 3730 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error; 3731 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error; 3732 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error; 3733 3734 *nItems = 1; 3735 return (void*) mlu; 3736 3737 Error: 3738 cmsMLUfree(mlu); 3739 return NULL; 3740 3741 } 3742 3743 static 3744 cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3745 { 3746 3747 cmsMLU* mlu = (cmsMLU*) Ptr; 3748 3749 if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error; 3750 if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error; 3751 if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error; 3752 if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error; 3753 if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error; 3754 3755 return TRUE; 3756 3757 Error: 3758 return FALSE; 3759 3760 cmsUNUSED_PARAMETER(nItems); 3761 } 3762 3763 3764 static 3765 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3766 { 3767 return (void*) cmsMLUdup((cmsMLU*) Ptr); 3768 3769 cmsUNUSED_PARAMETER(n); 3770 cmsUNUSED_PARAMETER(self); 3771 } 3772 3773 static 3774 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr) 3775 { 3776 cmsMLUfree((cmsMLU*) Ptr); 3777 return; 3778 3779 cmsUNUSED_PARAMETER(self); 3780 } 3781 3782 // ******************************************************************************** 3783 // Type cmsSigScreeningType 3784 // ******************************************************************************** 3785 // 3786 //The screeningType describes various screening parameters including screen 3787 //frequency, screening angle, and spot shape. 3788 3789 static 3790 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3791 { 3792 cmsScreening* sc = NULL; 3793 cmsUInt32Number i; 3794 3795 sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening)); 3796 if (sc == NULL) return NULL; 3797 3798 *nItems = 0; 3799 3800 if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error; 3801 if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error; 3802 3803 if (sc ->nChannels > cmsMAXCHANNELS - 1) 3804 sc ->nChannels = cmsMAXCHANNELS - 1; 3805 3806 for (i=0; i < sc ->nChannels; i++) { 3807 3808 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error; 3809 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error; 3810 if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error; 3811 } 3812 3813 3814 *nItems = 1; 3815 3816 return (void*) sc; 3817 3818 Error: 3819 if (sc != NULL) 3820 _cmsFree(self ->ContextID, sc); 3821 3822 return NULL; 3823 3824 cmsUNUSED_PARAMETER(SizeOfTag); 3825 } 3826 3827 3828 static 3829 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3830 { 3831 cmsScreening* sc = (cmsScreening* ) Ptr; 3832 cmsUInt32Number i; 3833 3834 if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE; 3835 if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE; 3836 3837 for (i=0; i < sc ->nChannels; i++) { 3838 3839 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE; 3840 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE; 3841 if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE; 3842 } 3843 3844 return TRUE; 3845 3846 cmsUNUSED_PARAMETER(nItems); 3847 cmsUNUSED_PARAMETER(self); 3848 } 3849 3850 3851 static 3852 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3853 { 3854 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); 3855 3856 cmsUNUSED_PARAMETER(n); 3857 } 3858 3859 3860 static 3861 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) 3862 { 3863 _cmsFree(self ->ContextID, Ptr); 3864 } 3865 3866 // ******************************************************************************** 3867 // Type cmsSigViewingConditionsType 3868 // ******************************************************************************** 3869 // 3870 //This type represents a set of viewing condition parameters including: 3871 //CIE absolute illuminant white point tristimulus values and CIE absolute 3872 //surround tristimulus values. 3873 3874 static 3875 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3876 { 3877 cmsICCViewingConditions* vc = NULL; 3878 3879 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions)); 3880 if (vc == NULL) return NULL; 3881 3882 *nItems = 0; 3883 3884 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error; 3885 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error; 3886 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error; 3887 3888 *nItems = 1; 3889 3890 return (void*) vc; 3891 3892 Error: 3893 if (vc != NULL) 3894 _cmsFree(self ->ContextID, vc); 3895 3896 return NULL; 3897 3898 cmsUNUSED_PARAMETER(SizeOfTag); 3899 } 3900 3901 3902 static 3903 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3904 { 3905 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr; 3906 3907 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE; 3908 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE; 3909 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE; 3910 3911 return TRUE; 3912 3913 cmsUNUSED_PARAMETER(nItems); 3914 cmsUNUSED_PARAMETER(self); 3915 } 3916 3917 3918 static 3919 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3920 { 3921 return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsICCViewingConditions)); 3922 3923 cmsUNUSED_PARAMETER(n); 3924 } 3925 3926 3927 static 3928 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr) 3929 { 3930 _cmsFree(self ->ContextID, Ptr); 3931 } 3932 3933 3934 // ******************************************************************************** 3935 // Type cmsSigMultiProcessElementType 3936 // ******************************************************************************** 3937 3938 3939 static 3940 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3941 { 3942 return (void*) cmsStageDup((cmsStage*) Ptr); 3943 3944 cmsUNUSED_PARAMETER(n); 3945 cmsUNUSED_PARAMETER(self); 3946 } 3947 3948 static 3949 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) 3950 { 3951 cmsStageFree((cmsStage*) Ptr); 3952 return; 3953 3954 cmsUNUSED_PARAMETER(self); 3955 } 3956 3957 // Each curve is stored in one or more curve segments, with break-points specified between curve segments. 3958 // The first curve segment always starts at Infinity, and the last curve segment always ends at +Infinity. The 3959 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be 3960 // specified either in terms of a formula, or by a sampled curve. 3961 3962 3963 // Read an embedded segmented curve 3964 static 3965 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) 3966 { 3967 cmsCurveSegSignature ElementSig; 3968 cmsUInt32Number i, j; 3969 cmsUInt16Number nSegments; 3970 cmsCurveSegment* Segments; 3971 cmsToneCurve* Curve; 3972 cmsFloat32Number PrevBreak = MINUS_INF; // - infinite 3973 3974 // Take signature and channels for each element. 3975 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL; 3976 3977 // That should be a segmented curve 3978 if (ElementSig != cmsSigSegmentedCurve) return NULL; 3979 3980 if (!_cmsReadUInt32Number(io, NULL)) return NULL; 3981 if (!_cmsReadUInt16Number(io, &nSegments)) return NULL; 3982 if (!_cmsReadUInt16Number(io, NULL)) return NULL; 3983 3984 if (nSegments < 1) return NULL; 3985 Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment)); 3986 if (Segments == NULL) return NULL; 3987 3988 // Read breakpoints 3989 for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) { 3990 3991 Segments[i].x0 = PrevBreak; 3992 if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error; 3993 PrevBreak = Segments[i].x1; 3994 } 3995 3996 Segments[nSegments-1].x0 = PrevBreak; 3997 Segments[nSegments-1].x1 = PLUS_INF; // A big cmsFloat32Number number 3998 3999 // Read segments 4000 for (i=0; i < nSegments; i++) { 4001 4002 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error; 4003 if (!_cmsReadUInt32Number(io, NULL)) goto Error; 4004 4005 switch (ElementSig) { 4006 4007 case cmsSigFormulaCurveSeg: { 4008 4009 cmsUInt16Number Type; 4010 cmsUInt32Number ParamsByType[] = {4, 5, 5 }; 4011 4012 if (!_cmsReadUInt16Number(io, &Type)) goto Error; 4013 if (!_cmsReadUInt16Number(io, NULL)) goto Error; 4014 4015 Segments[i].Type = Type + 6; 4016 if (Type > 2) goto Error; 4017 4018 for (j=0; j < ParamsByType[Type]; j++) { 4019 4020 cmsFloat32Number f; 4021 if (!_cmsReadFloat32Number(io, &f)) goto Error; 4022 Segments[i].Params[j] = f; 4023 } 4024 } 4025 break; 4026 4027 4028 case cmsSigSampledCurveSeg: { 4029 cmsUInt32Number Count; 4030 4031 if (!_cmsReadUInt32Number(io, &Count)) goto Error; 4032 4033 Segments[i].nGridPoints = Count; 4034 Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); 4035 if (Segments[i].SampledPoints == NULL) goto Error; 4036 4037 for (j=0; j < Count; j++) { 4038 if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error; 4039 } 4040 } 4041 break; 4042 4043 default: 4044 { 4045 char String[5]; 4046 4047 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); 4048 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); 4049 } 4050 goto Error; 4051 4052 } 4053 } 4054 4055 Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments); 4056 4057 for (i=0; i < nSegments; i++) { 4058 if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); 4059 } 4060 _cmsFree(self ->ContextID, Segments); 4061 return Curve; 4062 4063 Error: 4064 if (Segments) { 4065 for (i=0; i < nSegments; i++) { 4066 if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); 4067 } 4068 _cmsFree(self ->ContextID, Segments); 4069 } 4070 return NULL; 4071 } 4072 4073 4074 static 4075 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self, 4076 cmsIOHANDLER* io, 4077 void* Cargo, 4078 cmsUInt32Number n, 4079 cmsUInt32Number SizeOfTag) 4080 { 4081 cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo; 4082 4083 GammaTables[n] = ReadSegmentedCurve(self, io); 4084 return (GammaTables[n] != NULL); 4085 4086 cmsUNUSED_PARAMETER(SizeOfTag); 4087 } 4088 4089 static 4090 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4091 { 4092 cmsStage* mpe = NULL; 4093 cmsUInt16Number InputChans, OutputChans; 4094 cmsUInt32Number i, BaseOffset; 4095 cmsToneCurve** GammaTables; 4096 4097 *nItems = 0; 4098 4099 // Get actual position as a basis for element offsets 4100 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4101 4102 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4103 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4104 4105 if (InputChans != OutputChans) return NULL; 4106 4107 GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*)); 4108 if (GammaTables == NULL) return NULL; 4109 4110 if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) { 4111 4112 mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables); 4113 } 4114 else { 4115 mpe = NULL; 4116 } 4117 4118 for (i=0; i < InputChans; i++) { 4119 if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]); 4120 } 4121 4122 _cmsFree(self ->ContextID, GammaTables); 4123 *nItems = (mpe != NULL) ? 1U : 0; 4124 return mpe; 4125 4126 cmsUNUSED_PARAMETER(SizeOfTag); 4127 } 4128 4129 4130 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY 4131 static 4132 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) 4133 { 4134 cmsUInt32Number i, j; 4135 cmsCurveSegment* Segments = g ->Segments; 4136 cmsUInt32Number nSegments = g ->nSegments; 4137 4138 if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error; 4139 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4140 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error; 4141 if (!_cmsWriteUInt16Number(io, 0)) goto Error; 4142 4143 // Write the break-points 4144 for (i=0; i < nSegments - 1; i++) { 4145 if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error; 4146 } 4147 4148 // Write the segments 4149 for (i=0; i < g ->nSegments; i++) { 4150 4151 cmsCurveSegment* ActualSeg = Segments + i; 4152 4153 if (ActualSeg -> Type == 0) { 4154 4155 // This is a sampled curve 4156 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error; 4157 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4158 if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error; 4159 4160 for (j=0; j < g ->Segments[i].nGridPoints; j++) { 4161 if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error; 4162 } 4163 4164 } 4165 else { 4166 int Type; 4167 cmsUInt32Number ParamsByType[] = { 4, 5, 5 }; 4168 4169 // This is a formula-based 4170 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error; 4171 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4172 4173 // We only allow 1, 2 and 3 as types 4174 Type = ActualSeg ->Type - 6; 4175 if (Type > 2 || Type < 0) goto Error; 4176 4177 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error; 4178 if (!_cmsWriteUInt16Number(io, 0)) goto Error; 4179 4180 for (j=0; j < ParamsByType[Type]; j++) { 4181 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error; 4182 } 4183 } 4184 4185 // It seems there is no need to align. Code is here, and for safety commented out 4186 // if (!_cmsWriteAlignment(io)) goto Error; 4187 } 4188 4189 return TRUE; 4190 4191 Error: 4192 return FALSE; 4193 } 4194 4195 4196 static 4197 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, 4198 cmsIOHANDLER* io, 4199 void* Cargo, 4200 cmsUInt32Number n, 4201 cmsUInt32Number SizeOfTag) 4202 { 4203 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo; 4204 4205 return WriteSegmentedCurve(io, Curves ->TheCurves[n]); 4206 4207 cmsUNUSED_PARAMETER(SizeOfTag); 4208 cmsUNUSED_PARAMETER(self); 4209 } 4210 4211 // Write a curve, checking first for validity 4212 static 4213 cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4214 { 4215 cmsUInt32Number BaseOffset; 4216 cmsStage* mpe = (cmsStage*) Ptr; 4217 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data; 4218 4219 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4220 4221 // Write the header. Since those are curves, input and output channels are same 4222 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4223 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4224 4225 if (!WritePositionTable(self, io, 0, 4226 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE; 4227 4228 4229 return TRUE; 4230 4231 cmsUNUSED_PARAMETER(nItems); 4232 } 4233 4234 4235 4236 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the 4237 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array 4238 // is organized as follows: 4239 // array = [e11, e12, , e1P, e21, e22, , e2P, , eQ1, eQ2, , eQP, e1, e2, , eQ] 4240 4241 static 4242 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4243 { 4244 cmsStage* mpe; 4245 cmsUInt16Number InputChans, OutputChans; 4246 cmsUInt32Number nElems, i; 4247 cmsFloat64Number* Matrix; 4248 cmsFloat64Number* Offsets; 4249 4250 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4251 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4252 4253 4254 // Input and output chans may be ANY (up to 0xffff), 4255 // but we choose to limit to 16 channels for now 4256 if (InputChans >= cmsMAXCHANNELS) return NULL; 4257 if (OutputChans >= cmsMAXCHANNELS) return NULL; 4258 4259 nElems = (cmsUInt32Number) InputChans * OutputChans; 4260 4261 Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number)); 4262 if (Matrix == NULL) return NULL; 4263 4264 Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number)); 4265 if (Offsets == NULL) { 4266 4267 _cmsFree(self ->ContextID, Matrix); 4268 return NULL; 4269 } 4270 4271 for (i=0; i < nElems; i++) { 4272 4273 cmsFloat32Number v; 4274 4275 if (!_cmsReadFloat32Number(io, &v)) { 4276 _cmsFree(self ->ContextID, Matrix); 4277 _cmsFree(self ->ContextID, Offsets); 4278 return NULL; 4279 } 4280 Matrix[i] = v; 4281 } 4282 4283 4284 for (i=0; i < OutputChans; i++) { 4285 4286 cmsFloat32Number v; 4287 4288 if (!_cmsReadFloat32Number(io, &v)) { 4289 _cmsFree(self ->ContextID, Matrix); 4290 _cmsFree(self ->ContextID, Offsets); 4291 return NULL; 4292 } 4293 Offsets[i] = v; 4294 } 4295 4296 4297 mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets); 4298 _cmsFree(self ->ContextID, Matrix); 4299 _cmsFree(self ->ContextID, Offsets); 4300 4301 *nItems = 1; 4302 4303 return mpe; 4304 4305 cmsUNUSED_PARAMETER(SizeOfTag); 4306 } 4307 4308 static 4309 cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4310 { 4311 cmsUInt32Number i, nElems; 4312 cmsStage* mpe = (cmsStage*) Ptr; 4313 _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data; 4314 4315 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4316 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; 4317 4318 nElems = mpe ->InputChannels * mpe ->OutputChannels; 4319 4320 for (i=0; i < nElems; i++) { 4321 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE; 4322 } 4323 4324 4325 for (i=0; i < mpe ->OutputChannels; i++) { 4326 4327 if (Matrix ->Offset == NULL) { 4328 4329 if (!_cmsWriteFloat32Number(io, 0)) return FALSE; 4330 } 4331 else { 4332 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE; 4333 } 4334 } 4335 4336 return TRUE; 4337 4338 cmsUNUSED_PARAMETER(nItems); 4339 cmsUNUSED_PARAMETER(self); 4340 } 4341 4342 4343 4344 static 4345 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4346 { 4347 cmsStage* mpe = NULL; 4348 cmsUInt16Number InputChans, OutputChans; 4349 cmsUInt8Number Dimensions8[16]; 4350 cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS]; 4351 _cmsStageCLutData* clut; 4352 4353 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4354 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4355 4356 if (InputChans == 0) goto Error; 4357 if (OutputChans == 0) goto Error; 4358 4359 if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) 4360 goto Error; 4361 4362 // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number 4363 nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? (cmsUInt32Number) MAX_INPUT_DIMENSIONS : InputChans; 4364 4365 for (i = 0; i < nMaxGrids; i++) { 4366 if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least 4367 GridPoints[i] = (cmsUInt32Number)Dimensions8[i]; 4368 } 4369 4370 // Allocate the true CLUT 4371 mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); 4372 if (mpe == NULL) goto Error; 4373 4374 // Read and sanitize the data 4375 clut = (_cmsStageCLutData*) mpe ->Data; 4376 for (i=0; i < clut ->nEntries; i++) { 4377 4378 if (!_cmsReadFloat32Number(io, &clut->Tab.TFloat[i])) goto Error; 4379 } 4380 4381 *nItems = 1; 4382 return mpe; 4383 4384 Error: 4385 *nItems = 0; 4386 if (mpe != NULL) cmsStageFree(mpe); 4387 return NULL; 4388 4389 cmsUNUSED_PARAMETER(SizeOfTag); 4390 } 4391 4392 // Write a CLUT in floating point 4393 static 4394 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4395 { 4396 cmsUInt8Number Dimensions8[16]; // 16 because the spec says 16 and not max number of channels 4397 cmsUInt32Number i; 4398 cmsStage* mpe = (cmsStage*) Ptr; 4399 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data; 4400 4401 // Check for maximum number of channels supported by lcms 4402 if (mpe -> InputChannels > MAX_INPUT_DIMENSIONS) return FALSE; 4403 4404 // Only floats are supported in MPE 4405 if (clut ->HasFloatValues == FALSE) return FALSE; 4406 4407 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4408 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; 4409 4410 memset(Dimensions8, 0, sizeof(Dimensions8)); 4411 4412 for (i=0; i < mpe ->InputChannels; i++) 4413 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i]; 4414 4415 if (!io ->Write(io, 16, Dimensions8)) return FALSE; 4416 4417 for (i=0; i < clut ->nEntries; i++) { 4418 4419 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE; 4420 } 4421 4422 return TRUE; 4423 4424 cmsUNUSED_PARAMETER(nItems); 4425 cmsUNUSED_PARAMETER(self); 4426 } 4427 4428 4429 4430 // This is the list of built-in MPE types 4431 static _cmsTagTypeLinkedList SupportedMPEtypes[] = { 4432 4433 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now 4434 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says) 4435 4436 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] }, 4437 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] }, 4438 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, 4439 }; 4440 4441 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; 4442 4443 static 4444 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, 4445 cmsIOHANDLER* io, 4446 void* Cargo, 4447 cmsUInt32Number n, 4448 cmsUInt32Number SizeOfTag) 4449 { 4450 cmsStageSignature ElementSig; 4451 cmsTagTypeHandler* TypeHandler; 4452 cmsUInt32Number nItems; 4453 cmsPipeline *NewLUT = (cmsPipeline *) Cargo; 4454 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); 4455 4456 4457 // Take signature and channels for each element. 4458 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; 4459 4460 // The reserved placeholder 4461 if (!_cmsReadUInt32Number(io, NULL)) return FALSE; 4462 4463 // Read diverse MPE types 4464 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); 4465 if (TypeHandler == NULL) { 4466 4467 char String[5]; 4468 4469 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); 4470 4471 // An unknown element was found. 4472 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String); 4473 return FALSE; 4474 } 4475 4476 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType) 4477 // Read the MPE. No size is given 4478 if (TypeHandler ->ReadPtr != NULL) { 4479 4480 // This is a real element which should be read and processed 4481 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag))) 4482 return FALSE; 4483 } 4484 4485 return TRUE; 4486 4487 cmsUNUSED_PARAMETER(SizeOfTag); 4488 cmsUNUSED_PARAMETER(n); 4489 } 4490 4491 4492 // This is the main dispatcher for MPE 4493 static 4494 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4495 { 4496 cmsUInt16Number InputChans, OutputChans; 4497 cmsUInt32Number ElementCount; 4498 cmsPipeline *NewLUT = NULL; 4499 cmsUInt32Number BaseOffset; 4500 4501 // Get actual position as a basis for element offsets 4502 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4503 4504 // Read channels and element count 4505 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4506 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4507 4508 if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL; 4509 if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL; 4510 4511 // Allocates an empty LUT 4512 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); 4513 if (NewLUT == NULL) return NULL; 4514 4515 if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error; 4516 if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error; 4517 4518 // Check channel count 4519 if (InputChans != NewLUT->InputChannels || 4520 OutputChans != NewLUT->OutputChannels) goto Error; 4521 4522 // Success 4523 *nItems = 1; 4524 return NewLUT; 4525 4526 // Error 4527 Error: 4528 if (NewLUT != NULL) cmsPipelineFree(NewLUT); 4529 *nItems = 0; 4530 return NULL; 4531 4532 cmsUNUSED_PARAMETER(SizeOfTag); 4533 } 4534 4535 4536 4537 // This one is a liitle bit more complex, so we don't use position tables this time. 4538 static 4539 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4540 { 4541 cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos; 4542 cmsUInt32Number inputChan, outputChan; 4543 cmsUInt32Number ElemCount; 4544 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before; 4545 cmsStageSignature ElementSig; 4546 cmsPipeline* Lut = (cmsPipeline*) Ptr; 4547 cmsStage* Elem = Lut ->Elements; 4548 cmsTagTypeHandler* TypeHandler; 4549 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); 4550 4551 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4552 4553 inputChan = cmsPipelineInputChannels(Lut); 4554 outputChan = cmsPipelineOutputChannels(Lut); 4555 ElemCount = cmsPipelineStageCount(Lut); 4556 4557 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); 4558 if (ElementOffsets == NULL) goto Error; 4559 4560 ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); 4561 if (ElementSizes == NULL) goto Error; 4562 4563 // Write the head 4564 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error; 4565 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error; 4566 if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error; 4567 4568 DirectoryPos = io ->Tell(io); 4569 4570 // Write a fake directory to be filled latter on 4571 for (i=0; i < ElemCount; i++) { 4572 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset 4573 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size 4574 } 4575 4576 // Write each single tag. Keep track of the size as well. 4577 for (i=0; i < ElemCount; i++) { 4578 4579 ElementOffsets[i] = io ->Tell(io) - BaseOffset; 4580 4581 ElementSig = Elem ->Type; 4582 4583 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); 4584 if (TypeHandler == NULL) { 4585 4586 char String[5]; 4587 4588 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); 4589 4590 // An unknown element was found. 4591 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String); 4592 goto Error; 4593 } 4594 4595 if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error; 4596 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4597 Before = io ->Tell(io); 4598 if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error; 4599 if (!_cmsWriteAlignment(io)) goto Error; 4600 4601 ElementSizes[i] = io ->Tell(io) - Before; 4602 4603 Elem = Elem ->Next; 4604 } 4605 4606 // Write the directory 4607 CurrentPos = io ->Tell(io); 4608 4609 if (!io ->Seek(io, DirectoryPos)) goto Error; 4610 4611 for (i=0; i < ElemCount; i++) { 4612 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; 4613 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; 4614 } 4615 4616 if (!io ->Seek(io, CurrentPos)) goto Error; 4617 4618 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); 4619 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); 4620 return TRUE; 4621 4622 Error: 4623 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); 4624 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); 4625 return FALSE; 4626 4627 cmsUNUSED_PARAMETER(nItems); 4628 } 4629 4630 4631 static 4632 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 4633 { 4634 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 4635 4636 cmsUNUSED_PARAMETER(n); 4637 cmsUNUSED_PARAMETER(self); 4638 } 4639 4640 static 4641 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr) 4642 { 4643 cmsPipelineFree((cmsPipeline*) Ptr); 4644 return; 4645 4646 cmsUNUSED_PARAMETER(self); 4647 } 4648 4649 4650 // ******************************************************************************** 4651 // Type cmsSigVcgtType 4652 // ******************************************************************************** 4653 4654 4655 #define cmsVideoCardGammaTableType 0 4656 #define cmsVideoCardGammaFormulaType 1 4657 4658 // Used internally 4659 typedef struct { 4660 double Gamma; 4661 double Min; 4662 double Max; 4663 } _cmsVCGTGAMMA; 4664 4665 4666 static 4667 void *Type_vcgt_Read(struct _cms_typehandler_struct* self, 4668 cmsIOHANDLER* io, 4669 cmsUInt32Number* nItems, 4670 cmsUInt32Number SizeOfTag) 4671 { 4672 cmsUInt32Number TagType, n, i; 4673 cmsToneCurve** Curves; 4674 4675 *nItems = 0; 4676 4677 // Read tag type 4678 if (!_cmsReadUInt32Number(io, &TagType)) return NULL; 4679 4680 // Allocate space for the array 4681 Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); 4682 if (Curves == NULL) return NULL; 4683 4684 // There are two possible flavors 4685 switch (TagType) { 4686 4687 // Gamma is stored as a table 4688 case cmsVideoCardGammaTableType: 4689 { 4690 cmsUInt16Number nChannels, nElems, nBytes; 4691 4692 // Check channel count, which should be 3 (we don't support monochrome this time) 4693 if (!_cmsReadUInt16Number(io, &nChannels)) goto Error; 4694 4695 if (nChannels != 3) { 4696 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels); 4697 goto Error; 4698 } 4699 4700 // Get Table element count and bytes per element 4701 if (!_cmsReadUInt16Number(io, &nElems)) goto Error; 4702 if (!_cmsReadUInt16Number(io, &nBytes)) goto Error; 4703 4704 // Adobe's quirk fixup. Fixing broken profiles... 4705 if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576) 4706 nBytes = 2; 4707 4708 4709 // Populate tone curves 4710 for (n=0; n < 3; n++) { 4711 4712 Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL); 4713 if (Curves[n] == NULL) goto Error; 4714 4715 // On depending on byte depth 4716 switch (nBytes) { 4717 4718 // One byte, 0..255 4719 case 1: 4720 for (i=0; i < nElems; i++) { 4721 4722 cmsUInt8Number v; 4723 4724 if (!_cmsReadUInt8Number(io, &v)) goto Error; 4725 Curves[n] ->Table16[i] = FROM_8_TO_16(v); 4726 } 4727 break; 4728 4729 // One word 0..65535 4730 case 2: 4731 if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error; 4732 break; 4733 4734 // Unsupported 4735 default: 4736 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8); 4737 goto Error; 4738 } 4739 } // For all 3 channels 4740 } 4741 break; 4742 4743 // In this case, gamma is stored as a formula 4744 case cmsVideoCardGammaFormulaType: 4745 { 4746 _cmsVCGTGAMMA Colorant[3]; 4747 4748 // Populate tone curves 4749 for (n=0; n < 3; n++) { 4750 4751 double Params[10]; 4752 4753 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error; 4754 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error; 4755 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error; 4756 4757 // Parametric curve type 5 is: 4758 // Y = (aX + b)^Gamma + e | X >= d 4759 // Y = cX + f | X < d 4760 4761 // vcgt formula is: 4762 // Y = (Max Min) * (X ^ Gamma) + Min 4763 4764 // So, the translation is 4765 // a = (Max Min) ^ ( 1 / Gamma) 4766 // e = Min 4767 // b=c=d=f=0 4768 4769 Params[0] = Colorant[n].Gamma; 4770 Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma)); 4771 Params[2] = 0; 4772 Params[3] = 0; 4773 Params[4] = 0; 4774 Params[5] = Colorant[n].Min; 4775 Params[6] = 0; 4776 4777 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params); 4778 if (Curves[n] == NULL) goto Error; 4779 } 4780 } 4781 break; 4782 4783 // Unsupported 4784 default: 4785 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType); 4786 goto Error; 4787 } 4788 4789 *nItems = 1; 4790 return (void*) Curves; 4791 4792 // Regret, free all resources 4793 Error: 4794 4795 cmsFreeToneCurveTriple(Curves); 4796 _cmsFree(self ->ContextID, Curves); 4797 return NULL; 4798 4799 cmsUNUSED_PARAMETER(SizeOfTag); 4800 } 4801 4802 4803 // We don't support all flavors, only 16bits tables and formula 4804 static 4805 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4806 { 4807 cmsToneCurve** Curves = (cmsToneCurve**) Ptr; 4808 cmsUInt32Number i, j; 4809 4810 if (cmsGetToneCurveParametricType(Curves[0]) == 5 && 4811 cmsGetToneCurveParametricType(Curves[1]) == 5 && 4812 cmsGetToneCurveParametricType(Curves[2]) == 5) { 4813 4814 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; 4815 4816 // Save parameters 4817 for (i=0; i < 3; i++) { 4818 4819 _cmsVCGTGAMMA v; 4820 4821 v.Gamma = Curves[i] ->Segments[0].Params[0]; 4822 v.Min = Curves[i] ->Segments[0].Params[5]; 4823 v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min; 4824 4825 if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE; 4826 if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE; 4827 if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE; 4828 } 4829 } 4830 4831 else { 4832 4833 // Always store as a table of 256 words 4834 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE; 4835 if (!_cmsWriteUInt16Number(io, 3)) return FALSE; 4836 if (!_cmsWriteUInt16Number(io, 256)) return FALSE; 4837 if (!_cmsWriteUInt16Number(io, 2)) return FALSE; 4838 4839 for (i=0; i < 3; i++) { 4840 for (j=0; j < 256; j++) { 4841 4842 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0)); 4843 cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0); 4844 4845 if (!_cmsWriteUInt16Number(io, n)) return FALSE; 4846 } 4847 } 4848 } 4849 4850 return TRUE; 4851 4852 cmsUNUSED_PARAMETER(self); 4853 cmsUNUSED_PARAMETER(nItems); 4854 } 4855 4856 static 4857 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 4858 { 4859 cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr; 4860 cmsToneCurve** NewCurves; 4861 4862 NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); 4863 if (NewCurves == NULL) return NULL; 4864 4865 NewCurves[0] = cmsDupToneCurve(OldCurves[0]); 4866 NewCurves[1] = cmsDupToneCurve(OldCurves[1]); 4867 NewCurves[2] = cmsDupToneCurve(OldCurves[2]); 4868 4869 return (void*) NewCurves; 4870 4871 cmsUNUSED_PARAMETER(n); 4872 } 4873 4874 4875 static 4876 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr) 4877 { 4878 cmsFreeToneCurveTriple((cmsToneCurve**) Ptr); 4879 _cmsFree(self ->ContextID, Ptr); 4880 } 4881 4882 4883 // ******************************************************************************** 4884 // Type cmsSigDictType 4885 // ******************************************************************************** 4886 4887 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data 4888 typedef struct { 4889 cmsContext ContextID; 4890 cmsUInt32Number *Offsets; 4891 cmsUInt32Number *Sizes; 4892 } _cmsDICelem; 4893 4894 typedef struct { 4895 _cmsDICelem Name, Value, DisplayName, DisplayValue; 4896 4897 } _cmsDICarray; 4898 4899 // Allocate an empty array element 4900 static 4901 cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count) 4902 { 4903 e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); 4904 if (e->Offsets == NULL) return FALSE; 4905 4906 e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); 4907 if (e->Sizes == NULL) { 4908 4909 _cmsFree(ContextID, e -> Offsets); 4910 return FALSE; 4911 } 4912 4913 e ->ContextID = ContextID; 4914 return TRUE; 4915 } 4916 4917 // Free an array element 4918 static 4919 void FreeElem(_cmsDICelem* e) 4920 { 4921 if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets); 4922 if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes); 4923 e->Offsets = e ->Sizes = NULL; 4924 } 4925 4926 // Get rid of whole array 4927 static 4928 void FreeArray( _cmsDICarray* a) 4929 { 4930 if (a ->Name.Offsets != NULL) FreeElem(&a->Name); 4931 if (a ->Value.Offsets != NULL) FreeElem(&a ->Value); 4932 if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName); 4933 if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue); 4934 } 4935 4936 4937 // Allocate whole array 4938 static 4939 cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) 4940 { 4941 // Empty values 4942 memset(a, 0, sizeof(_cmsDICarray)); 4943 4944 // On depending on record size, create column arrays 4945 if (!AllocElem(ContextID, &a ->Name, Count)) goto Error; 4946 if (!AllocElem(ContextID, &a ->Value, Count)) goto Error; 4947 4948 if (Length > 16) { 4949 if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error; 4950 4951 } 4952 if (Length > 24) { 4953 if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error; 4954 } 4955 return TRUE; 4956 4957 Error: 4958 FreeArray(a); 4959 return FALSE; 4960 } 4961 4962 // Read one element 4963 static 4964 cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset) 4965 { 4966 if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE; 4967 if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE; 4968 4969 // An offset of zero has special meaning and shal be preserved 4970 if (e ->Offsets[i] > 0) 4971 e ->Offsets[i] += BaseOffset; 4972 return TRUE; 4973 } 4974 4975 4976 static 4977 cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset) 4978 { 4979 cmsUInt32Number i; 4980 4981 // Read column arrays 4982 for (i=0; i < Count; i++) { 4983 4984 if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE; 4985 if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE; 4986 4987 if (Length > 16) { 4988 4989 if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE; 4990 4991 } 4992 4993 if (Length > 24) { 4994 4995 if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE; 4996 } 4997 } 4998 return TRUE; 4999 } 5000 5001 5002 // Write one element 5003 static 5004 cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i) 5005 { 5006 if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE; 5007 if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE; 5008 5009 return TRUE; 5010 } 5011 5012 static 5013 cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) 5014 { 5015 cmsUInt32Number i; 5016 5017 for (i=0; i < Count; i++) { 5018 5019 if (!WriteOneElem(io, &a -> Name, i)) return FALSE; 5020 if (!WriteOneElem(io, &a -> Value, i)) return FALSE; 5021 5022 if (Length > 16) { 5023 5024 if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE; 5025 } 5026 5027 if (Length > 24) { 5028 5029 if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE; 5030 } 5031 } 5032 5033 return TRUE; 5034 } 5035 5036 static 5037 cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr) 5038 { 5039 5040 cmsUInt32Number nChars; 5041 5042 // Special case for undefined strings (see ICC Votable 5043 // Proposal Submission, Dictionary Type and Metadata TAG Definition) 5044 if (e -> Offsets[i] == 0) { 5045 5046 *wcstr = NULL; 5047 return TRUE; 5048 } 5049 5050 if (!io -> Seek(io, e -> Offsets[i])) return FALSE; 5051 5052 nChars = e ->Sizes[i] / sizeof(cmsUInt16Number); 5053 5054 5055 *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t)); 5056 if (*wcstr == NULL) return FALSE; 5057 5058 if (!_cmsReadWCharArray(io, nChars, *wcstr)) { 5059 _cmsFree(e ->ContextID, *wcstr); 5060 return FALSE; 5061 } 5062 5063 // End of string marker 5064 (*wcstr)[nChars] = 0; 5065 return TRUE; 5066 } 5067 5068 static 5069 cmsUInt32Number mywcslen(const wchar_t *s) 5070 { 5071 const wchar_t *p; 5072 5073 p = s; 5074 while (*p) 5075 p++; 5076 5077 return (cmsUInt32Number)(p - s); 5078 } 5079 5080 static 5081 cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset) 5082 { 5083 cmsUInt32Number Before = io ->Tell(io); 5084 cmsUInt32Number n; 5085 5086 e ->Offsets[i] = Before - BaseOffset; 5087 5088 if (wcstr == NULL) { 5089 e ->Sizes[i] = 0; 5090 e ->Offsets[i] = 0; 5091 return TRUE; 5092 } 5093 5094 n = mywcslen(wcstr); 5095 if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE; 5096 5097 e ->Sizes[i] = io ->Tell(io) - Before; 5098 return TRUE; 5099 } 5100 5101 static 5102 cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu) 5103 { 5104 cmsUInt32Number nItems = 0; 5105 5106 // A way to get null MLUCs 5107 if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) { 5108 5109 *mlu = NULL; 5110 return TRUE; 5111 } 5112 5113 if (!io -> Seek(io, e -> Offsets[i])) return FALSE; 5114 5115 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]); 5116 return *mlu != NULL; 5117 } 5118 5119 static 5120 cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset) 5121 { 5122 cmsUInt32Number Before; 5123 5124 // Special case for undefined strings (see ICC Votable 5125 // Proposal Submission, Dictionary Type and Metadata TAG Definition) 5126 if (mlu == NULL) { 5127 e ->Sizes[i] = 0; 5128 e ->Offsets[i] = 0; 5129 return TRUE; 5130 } 5131 5132 Before = io ->Tell(io); 5133 e ->Offsets[i] = Before - BaseOffset; 5134 5135 if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE; 5136 5137 e ->Sizes[i] = io ->Tell(io) - Before; 5138 return TRUE; 5139 } 5140 5141 5142 static 5143 void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 5144 { 5145 cmsHANDLE hDict; 5146 cmsUInt32Number i, Count, Length; 5147 cmsUInt32Number BaseOffset; 5148 _cmsDICarray a; 5149 wchar_t *NameWCS = NULL, *ValueWCS = NULL; 5150 cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL; 5151 cmsBool rc; 5152 5153 *nItems = 0; 5154 5155 // Get actual position as a basis for element offsets 5156 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 5157 5158 // Get name-value record count 5159 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 5160 SizeOfTag -= sizeof(cmsUInt32Number); 5161 5162 // Get rec length 5163 if (!_cmsReadUInt32Number(io, &Length)) return NULL; 5164 SizeOfTag -= sizeof(cmsUInt32Number); 5165 5166 // Check for valid lengths 5167 if (Length != 16 && Length != 24 && Length != 32) { 5168 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length); 5169 return NULL; 5170 } 5171 5172 // Creates an empty dictionary 5173 hDict = cmsDictAlloc(self -> ContextID); 5174 if (hDict == NULL) return NULL; 5175 5176 // On depending on record size, create column arrays 5177 if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error; 5178 5179 // Read column arrays 5180 if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error; 5181 5182 // Seek to each element and read it 5183 for (i=0; i < Count; i++) { 5184 5185 if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error; 5186 if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error; 5187 5188 if (Length > 16) { 5189 if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error; 5190 } 5191 5192 if (Length > 24) { 5193 if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error; 5194 } 5195 5196 if (NameWCS == NULL || ValueWCS == NULL) { 5197 5198 cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value"); 5199 rc = FALSE; 5200 } 5201 else { 5202 5203 rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); 5204 } 5205 5206 if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); 5207 if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS); 5208 if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU); 5209 if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU); 5210 5211 if (!rc) goto Error; 5212 } 5213 5214 FreeArray(&a); 5215 *nItems = 1; 5216 return (void*) hDict; 5217 5218 Error: 5219 FreeArray(&a); 5220 cmsDictFree(hDict); 5221 return NULL; 5222 } 5223 5224 5225 static 5226 cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 5227 { 5228 cmsHANDLE hDict = (cmsHANDLE) Ptr; 5229 const cmsDICTentry* p; 5230 cmsBool AnyName, AnyValue; 5231 cmsUInt32Number i, Count, Length; 5232 cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset; 5233 _cmsDICarray a; 5234 5235 if (hDict == NULL) return FALSE; 5236 5237 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 5238 5239 // Let's inspect the dictionary 5240 Count = 0; AnyName = FALSE; AnyValue = FALSE; 5241 for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) { 5242 5243 if (p ->DisplayName != NULL) AnyName = TRUE; 5244 if (p ->DisplayValue != NULL) AnyValue = TRUE; 5245 Count++; 5246 } 5247 5248 Length = 16; 5249 if (AnyName) Length += 8; 5250 if (AnyValue) Length += 8; 5251 5252 if (!_cmsWriteUInt32Number(io, Count)) return FALSE; 5253 if (!_cmsWriteUInt32Number(io, Length)) return FALSE; 5254 5255 // Keep starting position of offsets table 5256 DirectoryPos = io ->Tell(io); 5257 5258 // Allocate offsets array 5259 if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error; 5260 5261 // Write a fake directory to be filled latter on 5262 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; 5263 5264 // Write each element. Keep track of the size as well. 5265 p = cmsDictGetEntryList(hDict); 5266 for (i=0; i < Count; i++) { 5267 5268 if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error; 5269 if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error; 5270 5271 if (p ->DisplayName != NULL) { 5272 if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error; 5273 } 5274 5275 if (p ->DisplayValue != NULL) { 5276 if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error; 5277 } 5278 5279 p = cmsDictNextEntry(p); 5280 } 5281 5282 // Write the directory 5283 CurrentPos = io ->Tell(io); 5284 if (!io ->Seek(io, DirectoryPos)) goto Error; 5285 5286 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; 5287 5288 if (!io ->Seek(io, CurrentPos)) goto Error; 5289 5290 FreeArray(&a); 5291 return TRUE; 5292 5293 Error: 5294 FreeArray(&a); 5295 return FALSE; 5296 5297 cmsUNUSED_PARAMETER(nItems); 5298 } 5299 5300 5301 static 5302 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 5303 { 5304 return (void*) cmsDictDup((cmsHANDLE) Ptr); 5305 5306 cmsUNUSED_PARAMETER(n); 5307 cmsUNUSED_PARAMETER(self); 5308 } 5309 5310 5311 static 5312 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr) 5313 { 5314 cmsDictFree((cmsHANDLE) Ptr); 5315 cmsUNUSED_PARAMETER(self); 5316 } 5317 5318 5319 // ******************************************************************************** 5320 // Type support main routines 5321 // ******************************************************************************** 5322 5323 5324 // This is the list of built-in types 5325 static const _cmsTagTypeLinkedList SupportedTagTypes[] = { 5326 5327 {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), (_cmsTagTypeLinkedList*) &SupportedTagTypes[1] }, 5328 {TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), (_cmsTagTypeLinkedList*) &SupportedTagTypes[2] }, 5329 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[3] }, 5330 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[4] }, 5331 {TYPE_HANDLER(cmsSigTextType, Text), (_cmsTagTypeLinkedList*) &SupportedTagTypes[5] }, 5332 {TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), (_cmsTagTypeLinkedList*) &SupportedTagTypes[6] }, 5333 {TYPE_HANDLER(cmsSigCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[7] }, 5334 {TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[8] }, 5335 {TYPE_HANDLER(cmsSigDateTimeType, DateTime), (_cmsTagTypeLinkedList*) &SupportedTagTypes[9] }, 5336 {TYPE_HANDLER(cmsSigLut8Type, LUT8), (_cmsTagTypeLinkedList*) &SupportedTagTypes[10] }, 5337 {TYPE_HANDLER(cmsSigLut16Type, LUT16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[11] }, 5338 {TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), (_cmsTagTypeLinkedList*) &SupportedTagTypes[12] }, 5339 {TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), (_cmsTagTypeLinkedList*) &SupportedTagTypes[13] }, 5340 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), (_cmsTagTypeLinkedList*) &SupportedTagTypes[14] }, 5341 {TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc),(_cmsTagTypeLinkedList*) &SupportedTagTypes[15] }, 5342 {TYPE_HANDLER(cmsSigSignatureType, Signature), (_cmsTagTypeLinkedList*) &SupportedTagTypes[16] }, 5343 {TYPE_HANDLER(cmsSigMeasurementType, Measurement), (_cmsTagTypeLinkedList*) &SupportedTagTypes[17] }, 5344 {TYPE_HANDLER(cmsSigDataType, Data), (_cmsTagTypeLinkedList*) &SupportedTagTypes[18] }, 5345 {TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), (_cmsTagTypeLinkedList*) &SupportedTagTypes[19] }, 5346 {TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), (_cmsTagTypeLinkedList*) &SupportedTagTypes[20] }, 5347 {TYPE_HANDLER(cmsSigUcrBgType, UcrBg), (_cmsTagTypeLinkedList*) &SupportedTagTypes[21] }, 5348 {TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), (_cmsTagTypeLinkedList*) &SupportedTagTypes[22] }, 5349 {TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), (_cmsTagTypeLinkedList*) &SupportedTagTypes[23] }, 5350 {TYPE_HANDLER(cmsSigScreeningType, Screening), (_cmsTagTypeLinkedList*) &SupportedTagTypes[24] }, 5351 {TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), (_cmsTagTypeLinkedList*) &SupportedTagTypes[25] }, 5352 {TYPE_HANDLER(cmsSigXYZType, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[26] }, 5353 {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[27] }, 5354 {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[28] }, 5355 {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] }, 5356 {TYPE_HANDLER(cmsSigDictType, Dictionary), (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] }, 5357 {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } 5358 }; 5359 5360 5361 _cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; 5362 5363 5364 5365 // Duplicates the zone of memory used by the plug-in in the new context 5366 static 5367 void DupTagTypeList(struct _cmsContext_struct* ctx, 5368 const struct _cmsContext_struct* src, 5369 int loc) 5370 { 5371 _cmsTagTypePluginChunkType newHead = { NULL }; 5372 _cmsTagTypeLinkedList* entry; 5373 _cmsTagTypeLinkedList* Anterior = NULL; 5374 _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; 5375 5376 // Walk the list copying all nodes 5377 for (entry = head->TagTypes; 5378 entry != NULL; 5379 entry = entry ->Next) { 5380 5381 _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); 5382 5383 if (newEntry == NULL) 5384 return; 5385 5386 // We want to keep the linked list order, so this is a little bit tricky 5387 newEntry -> Next = NULL; 5388 if (Anterior) 5389 Anterior -> Next = newEntry; 5390 5391 Anterior = newEntry; 5392 5393 if (newHead.TagTypes == NULL) 5394 newHead.TagTypes = newEntry; 5395 } 5396 5397 ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); 5398 } 5399 5400 5401 void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, 5402 const struct _cmsContext_struct* src) 5403 { 5404 if (src != NULL) { 5405 5406 // Duplicate the LIST 5407 DupTagTypeList(ctx, src, TagTypePlugin); 5408 } 5409 else { 5410 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; 5411 ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); 5412 } 5413 } 5414 5415 void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, 5416 const struct _cmsContext_struct* src) 5417 { 5418 if (src != NULL) { 5419 5420 // Duplicate the LIST 5421 DupTagTypeList(ctx, src, MPEPlugin); 5422 } 5423 else { 5424 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; 5425 ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); 5426 } 5427 5428 } 5429 5430 5431 // Both kind of plug-ins share same structure 5432 cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) 5433 { 5434 return RegisterTypesPlugin(id, Data, TagTypePlugin); 5435 } 5436 5437 cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) 5438 { 5439 return RegisterTypesPlugin(id, Data,MPEPlugin); 5440 } 5441 5442 5443 // Wrapper for tag types 5444 cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) 5445 { 5446 _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); 5447 5448 return GetHandler(sig, ctx->TagTypes, (_cmsTagTypeLinkedList*) SupportedTagTypes); 5449 } 5450 5451 // ******************************************************************************** 5452 // Tag support main routines 5453 // ******************************************************************************** 5454 5455 typedef struct _cmsTagLinkedList_st { 5456 5457 cmsTagSignature Signature; 5458 cmsTagDescriptor Descriptor; 5459 struct _cmsTagLinkedList_st* Next; 5460 5461 } _cmsTagLinkedList; 5462 5463 // This is the list of built-in tags. The data of this list can be modified by plug-ins 5464 static _cmsTagLinkedList SupportedTags[] = { 5465 5466 { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]}, 5467 { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]}, 5468 { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]}, 5469 { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]}, 5470 { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]}, 5471 { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]}, 5472 5473 // Allow corbis and its broken XYZ type 5474 { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]}, 5475 { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]}, 5476 { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]}, 5477 5478 { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]}, 5479 { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]}, 5480 { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]}, 5481 5482 { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]}, 5483 { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]}, 5484 5485 { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]}, 5486 { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]}, 5487 { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]}, 5488 { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]}, 5489 { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]}, 5490 5491 { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]}, 5492 { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]}, 5493 5494 { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]}, 5495 { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]}, 5496 5497 { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]}, 5498 5499 { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]}, 5500 { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]}, 5501 5502 { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]}, 5503 { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]}, 5504 5505 { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]}, 5506 5507 { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]}, 5508 { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]}, 5509 { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]}, 5510 5511 { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]}, 5512 { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]}, 5513 { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]}, 5514 5515 { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]}, 5516 { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]}, 5517 { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]}, 5518 5519 { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]}, 5520 5521 { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]}, 5522 { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]}, 5523 { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]}, 5524 { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]}, 5525 { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]}, 5526 { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]}, 5527 5528 { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]}, 5529 5530 { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]}, 5531 { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]}, 5532 5533 { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]}, 5534 { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]}, 5535 { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]}, 5536 { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]}, 5537 { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]}, 5538 { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]}, 5539 { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]}, 5540 { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]}, 5541 5542 { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]}, 5543 { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]}, 5544 5545 { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, 5546 { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, 5547 { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]}, 5548 { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, 5549 5550 { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]}, 5551 { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL} 5552 5553 }; 5554 5555 /* 5556 Not supported Why 5557 ======================= ========================================= 5558 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT! 5559 cmsSigNamedColorTag ==> Deprecated 5560 cmsSigDataTag ==> Ancient, unused 5561 cmsSigDeviceSettingsTag ==> Deprecated, useless 5562 */ 5563 5564 5565 _cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; 5566 5567 5568 // Duplicates the zone of memory used by the plug-in in the new context 5569 static 5570 void DupTagList(struct _cmsContext_struct* ctx, 5571 const struct _cmsContext_struct* src) 5572 { 5573 _cmsTagPluginChunkType newHead = { NULL }; 5574 _cmsTagLinkedList* entry; 5575 _cmsTagLinkedList* Anterior = NULL; 5576 _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; 5577 5578 // Walk the list copying all nodes 5579 for (entry = head->Tag; 5580 entry != NULL; 5581 entry = entry ->Next) { 5582 5583 _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); 5584 5585 if (newEntry == NULL) 5586 return; 5587 5588 // We want to keep the linked list order, so this is a little bit tricky 5589 newEntry -> Next = NULL; 5590 if (Anterior) 5591 Anterior -> Next = newEntry; 5592 5593 Anterior = newEntry; 5594 5595 if (newHead.Tag == NULL) 5596 newHead.Tag = newEntry; 5597 } 5598 5599 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); 5600 } 5601 5602 void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, 5603 const struct _cmsContext_struct* src) 5604 { 5605 if (src != NULL) { 5606 5607 DupTagList(ctx, src); 5608 } 5609 else { 5610 static _cmsTagPluginChunkType TagPluginChunk = { NULL }; 5611 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); 5612 } 5613 5614 } 5615 5616 cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) 5617 { 5618 cmsPluginTag* Plugin = (cmsPluginTag*) Data; 5619 _cmsTagLinkedList *pt; 5620 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); 5621 5622 if (Data == NULL) { 5623 5624 TagPluginChunk->Tag = NULL; 5625 return TRUE; 5626 } 5627 5628 pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); 5629 if (pt == NULL) return FALSE; 5630 5631 pt ->Signature = Plugin ->Signature; 5632 pt ->Descriptor = Plugin ->Descriptor; 5633 pt ->Next = TagPluginChunk ->Tag; 5634 5635 TagPluginChunk ->Tag = pt; 5636 5637 return TRUE; 5638 } 5639 5640 // Return a descriptor for a given tag or NULL 5641 cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) 5642 { 5643 _cmsTagLinkedList* pt; 5644 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); 5645 5646 for (pt = TagPluginChunk->Tag; 5647 pt != NULL; 5648 pt = pt ->Next) { 5649 5650 if (sig == pt -> Signature) return &pt ->Descriptor; 5651 } 5652 5653 for (pt = SupportedTags; 5654 pt != NULL; 5655 pt = pt ->Next) { 5656 5657 if (sig == pt -> Signature) return &pt ->Descriptor; 5658 } 5659 5660 return NULL; 5661 } 5662