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