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