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