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