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