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 if (((Offset + Len) < Len) || ((Offset + Len) > SizeOfTag + 8)) goto Error; 1488 1489 // True begin of the string 1490 BeginOfThisString = Offset - SizeOfHeader - 8; 1491 1492 // Ajust to wchar_t elements 1493 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number); 1494 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number); 1495 1496 // To guess maximum size, add offset + len 1497 EndOfThisString = BeginOfThisString + Len; 1498 if (EndOfThisString > LargestPosition) 1499 LargestPosition = EndOfThisString; 1500 } 1501 1502 // Now read the remaining of tag and fill all strings. Substract the directory 1503 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number); 1504 if (SizeOfTag == 0) 1505 { 1506 Block = NULL; 1507 NumOfWchar = 0; 1508 1509 } 1510 else 1511 { 1512 Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); 1513 if (Block == NULL) goto Error; 1514 NumOfWchar = SizeOfTag / sizeof(wchar_t); 1515 if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error; 1516 } 1517 1518 mlu ->MemPool = Block; 1519 mlu ->PoolSize = SizeOfTag; 1520 mlu ->PoolUsed = SizeOfTag; 1521 1522 *nItems = 1; 1523 return (void*) mlu; 1524 1525 Error: 1526 if (mlu) cmsMLUfree(mlu); 1527 return NULL; 1528 } 1529 1530 static 1531 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 1532 { 1533 cmsMLU* mlu =(cmsMLU*) Ptr; 1534 cmsUInt32Number HeaderSize; 1535 cmsUInt32Number Len, Offset; 1536 int i; 1537 1538 if (Ptr == NULL) { 1539 1540 // Empty placeholder 1541 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 1542 if (!_cmsWriteUInt32Number(io, 12)) return FALSE; 1543 return TRUE; 1544 } 1545 1546 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE; 1547 if (!_cmsWriteUInt32Number(io, 12)) return FALSE; 1548 1549 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase); 1550 1551 for (i=0; i < mlu ->UsedEntries; i++) { 1552 1553 Len = mlu ->Entries[i].Len; 1554 Offset = mlu ->Entries[i].StrW; 1555 1556 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t); 1557 Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8; 1558 1559 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE; 1560 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE; 1561 if (!_cmsWriteUInt32Number(io, Len)) return FALSE; 1562 if (!_cmsWriteUInt32Number(io, Offset)) return FALSE; 1563 } 1564 1565 if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE; 1566 1567 return TRUE; 1568 1569 cmsUNUSED_PARAMETER(nItems); 1570 cmsUNUSED_PARAMETER(self); 1571 } 1572 1573 1574 static 1575 void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 1576 { 1577 return (void*) cmsMLUdup((cmsMLU*) Ptr); 1578 1579 cmsUNUSED_PARAMETER(n); 1580 cmsUNUSED_PARAMETER(self); 1581 } 1582 1583 static 1584 void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr) 1585 { 1586 cmsMLUfree((cmsMLU*) Ptr); 1587 return; 1588 1589 cmsUNUSED_PARAMETER(self); 1590 } 1591 1592 1593 // ******************************************************************************** 1594 // Type cmsSigLut8Type 1595 // ******************************************************************************** 1596 1597 // Decide which LUT type to use on writting 1598 static 1599 cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data) 1600 { 1601 cmsPipeline* Lut = (cmsPipeline*) Data; 1602 1603 if (ICCVersion < 4.0) { 1604 if (Lut ->SaveAs8Bits) return cmsSigLut8Type; 1605 return cmsSigLut16Type; 1606 } 1607 else { 1608 return cmsSigLutAtoBType; 1609 } 1610 } 1611 1612 static 1613 cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data) 1614 { 1615 cmsPipeline* Lut = (cmsPipeline*) Data; 1616 1617 if (ICCVersion < 4.0) { 1618 if (Lut ->SaveAs8Bits) return cmsSigLut8Type; 1619 return cmsSigLut16Type; 1620 } 1621 else { 1622 return cmsSigLutBtoAType; 1623 } 1624 } 1625 1626 /* 1627 This structure represents a colour transform using tables of 8-bit precision. 1628 This type contains four processing elements: a 3 by 3 matrix (which shall be 1629 the identity matrix unless the input colour space is XYZ), a set of one dimensional 1630 input tables, a multidimensional lookup table, and a set of one dimensional output 1631 tables. Data is processed using these elements via the following sequence: 1632 (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables) 1633 1634 Byte Position Field Length (bytes) Content Encoded as... 1635 8 1 Number of Input Channels (i) uInt8Number 1636 9 1 Number of Output Channels (o) uInt8Number 1637 10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number 1638 11 1 Reserved for padding (fill with 00h) 1639 1640 12..15 4 Encoded e00 parameter s15Fixed16Number 1641 */ 1642 1643 1644 // Read 8 bit tables as gamma functions 1645 static 1646 cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels) 1647 { 1648 cmsUInt8Number* Temp = NULL; 1649 int i, j; 1650 cmsToneCurve* Tables[cmsMAXCHANNELS]; 1651 1652 if (nChannels > cmsMAXCHANNELS) return FALSE; 1653 if (nChannels <= 0) return FALSE; 1654 1655 memset(Tables, 0, sizeof(Tables)); 1656 1657 Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256); 1658 if (Temp == NULL) return FALSE; 1659 1660 for (i=0; i < nChannels; i++) { 1661 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL); 1662 if (Tables[i] == NULL) goto Error; 1663 } 1664 1665 for (i=0; i < nChannels; i++) { 1666 1667 if (io ->Read(io, Temp, 256, 1) != 1) goto Error; 1668 1669 for (j=0; j < 256; j++) 1670 Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]); 1671 } 1672 1673 _cmsFree(ContextID, Temp); 1674 Temp = NULL; 1675 1676 if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) 1677 goto Error; 1678 1679 for (i=0; i < nChannels; i++) 1680 cmsFreeToneCurve(Tables[i]); 1681 1682 return TRUE; 1683 1684 Error: 1685 for (i=0; i < nChannels; i++) { 1686 if (Tables[i]) cmsFreeToneCurve(Tables[i]); 1687 } 1688 1689 if (Temp) _cmsFree(ContextID, Temp); 1690 return FALSE; 1691 } 1692 1693 1694 static 1695 cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables) 1696 { 1697 int j; 1698 cmsUInt32Number i; 1699 cmsUInt8Number val; 1700 1701 for (i=0; i < n; i++) { 1702 1703 if (Tables) { 1704 1705 // Usual case of identity curves 1706 if ((Tables ->TheCurves[i]->nEntries == 2) && 1707 (Tables->TheCurves[i]->Table16[0] == 0) && 1708 (Tables->TheCurves[i]->Table16[1] == 65535)) { 1709 1710 for (j=0; j < 256; j++) { 1711 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE; 1712 } 1713 } 1714 else 1715 if (Tables ->TheCurves[i]->nEntries != 256) { 1716 cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); 1717 return FALSE; 1718 } 1719 else 1720 for (j=0; j < 256; j++) { 1721 1722 val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); 1723 1724 if (!_cmsWriteUInt8Number(io, val)) return FALSE; 1725 } 1726 } 1727 } 1728 return TRUE; 1729 } 1730 1731 1732 // Check overflow 1733 static 1734 cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) 1735 { 1736 cmsUInt32Number rv = 1, rc; 1737 1738 if (a == 0) return 0; 1739 if (n == 0) return 0; 1740 1741 for (; b > 0; b--) { 1742 1743 rv *= a; 1744 1745 // Check for overflow 1746 if (rv > UINT_MAX / a) return (cmsUInt32Number) -1; 1747 1748 } 1749 1750 rc = rv * n; 1751 1752 if (rv != rc / n) return (cmsUInt32Number) -1; 1753 return rc; 1754 } 1755 1756 1757 // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables. 1758 // 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust 1759 // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction. 1760 1761 static 1762 void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 1763 { 1764 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; 1765 cmsUInt8Number* Temp = NULL; 1766 cmsPipeline* NewLUT = NULL; 1767 cmsUInt32Number nTabSize, i; 1768 cmsFloat64Number Matrix[3*3]; 1769 1770 *nItems = 0; 1771 1772 if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error; 1773 if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error; 1774 if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error; 1775 1776 if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least 1777 1778 // Padding 1779 if (!_cmsReadUInt8Number(io, NULL)) goto Error; 1780 1781 // Do some checking 1782 if (InputChannels > cmsMAXCHANNELS) goto Error; 1783 if (OutputChannels > cmsMAXCHANNELS) goto Error; 1784 1785 // Allocates an empty Pipeline 1786 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); 1787 if (NewLUT == NULL) goto Error; 1788 1789 // Read the Matrix 1790 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; 1791 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; 1792 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; 1793 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; 1794 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; 1795 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; 1796 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; 1797 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; 1798 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; 1799 1800 1801 // Only operates if not identity... 1802 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { 1803 1804 if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) 1805 goto Error; 1806 } 1807 1808 // Get input tables 1809 if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error; 1810 1811 // Get 3D CLUT. Check the overflow.... 1812 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); 1813 if (nTabSize == (cmsUInt32Number) -1) goto Error; 1814 if (nTabSize > 0) { 1815 1816 cmsUInt16Number *PtrW, *T; 1817 1818 PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); 1819 if (T == NULL) goto Error; 1820 1821 Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize); 1822 if (Temp == NULL) { 1823 _cmsFree(self ->ContextID, T); 1824 goto Error; 1825 } 1826 1827 if (io ->Read(io, Temp, nTabSize, 1) != 1) { 1828 _cmsFree(self ->ContextID, T); 1829 _cmsFree(self ->ContextID, Temp); 1830 goto Error; 1831 } 1832 1833 for (i = 0; i < nTabSize; i++) { 1834 1835 *PtrW++ = FROM_8_TO_16(Temp[i]); 1836 } 1837 _cmsFree(self ->ContextID, Temp); 1838 Temp = NULL; 1839 1840 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) 1841 goto Error; 1842 _cmsFree(self ->ContextID, T); 1843 } 1844 1845 1846 // Get output tables 1847 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error; 1848 1849 *nItems = 1; 1850 return NewLUT; 1851 1852 Error: 1853 if (NewLUT != NULL) cmsPipelineFree(NewLUT); 1854 return NULL; 1855 1856 cmsUNUSED_PARAMETER(SizeOfTag); 1857 } 1858 1859 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin. 1860 static 1861 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 1862 { 1863 cmsUInt32Number j, nTabSize; 1864 cmsUInt8Number val; 1865 cmsPipeline* NewLUT = (cmsPipeline*) Ptr; 1866 cmsStage* mpe; 1867 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; 1868 _cmsStageMatrixData* MatMPE = NULL; 1869 _cmsStageCLutData* clut = NULL; 1870 int clutPoints; 1871 1872 // Disassemble the LUT into components. 1873 mpe = NewLUT -> Elements; 1874 if (mpe ->Type == cmsSigMatrixElemType) { 1875 1876 MatMPE = (_cmsStageMatrixData*) mpe ->Data; 1877 mpe = mpe -> Next; 1878 } 1879 1880 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { 1881 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; 1882 mpe = mpe -> Next; 1883 } 1884 1885 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { 1886 clut = (_cmsStageCLutData*) mpe -> Data; 1887 mpe = mpe ->Next; 1888 } 1889 1890 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { 1891 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; 1892 mpe = mpe -> Next; 1893 } 1894 1895 // That should be all 1896 if (mpe != NULL) { 1897 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8"); 1898 return FALSE; 1899 } 1900 1901 1902 if (clut == NULL) 1903 clutPoints = 0; 1904 else 1905 clutPoints = clut->Params->nSamples[0]; 1906 1907 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE; 1908 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE; 1909 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; 1910 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding 1911 1912 1913 if (MatMPE != NULL) { 1914 1915 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; 1916 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; 1917 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; 1918 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; 1919 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; 1920 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; 1921 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; 1922 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; 1923 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; 1924 1925 } 1926 else { 1927 1928 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 1929 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1930 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1931 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1932 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 1933 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1934 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1935 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 1936 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 1937 } 1938 1939 // The prelinearization table 1940 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; 1941 1942 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); 1943 if (nTabSize == (cmsUInt32Number) -1) return FALSE; 1944 if (nTabSize > 0) { 1945 1946 // The 3D CLUT. 1947 if (clut != NULL) { 1948 1949 for (j=0; j < nTabSize; j++) { 1950 1951 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); 1952 if (!_cmsWriteUInt8Number(io, val)) return FALSE; 1953 } 1954 } 1955 } 1956 1957 // The postlinearization table 1958 if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE; 1959 1960 return TRUE; 1961 1962 cmsUNUSED_PARAMETER(nItems); 1963 } 1964 1965 1966 static 1967 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 1968 { 1969 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 1970 1971 cmsUNUSED_PARAMETER(n); 1972 cmsUNUSED_PARAMETER(self); 1973 } 1974 1975 static 1976 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr) 1977 { 1978 cmsPipelineFree((cmsPipeline*) Ptr); 1979 return; 1980 1981 cmsUNUSED_PARAMETER(self); 1982 } 1983 1984 // ******************************************************************************** 1985 // Type cmsSigLut16Type 1986 // ******************************************************************************** 1987 1988 // Read 16 bit tables as gamma functions 1989 static 1990 cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries) 1991 { 1992 int i; 1993 cmsToneCurve* Tables[cmsMAXCHANNELS]; 1994 1995 // Maybe an empty table? (this is a lcms extension) 1996 if (nEntries <= 0) return TRUE; 1997 1998 // Check for malicious profiles 1999 if (nEntries < 2) return FALSE; 2000 if (nChannels > cmsMAXCHANNELS) return FALSE; 2001 2002 // Init table to zero 2003 memset(Tables, 0, sizeof(Tables)); 2004 2005 for (i=0; i < nChannels; i++) { 2006 2007 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL); 2008 if (Tables[i] == NULL) goto Error; 2009 2010 if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error; 2011 } 2012 2013 2014 // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code) 2015 if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) 2016 goto Error; 2017 2018 for (i=0; i < nChannels; i++) 2019 cmsFreeToneCurve(Tables[i]); 2020 2021 return TRUE; 2022 2023 Error: 2024 for (i=0; i < nChannels; i++) { 2025 if (Tables[i]) cmsFreeToneCurve(Tables[i]); 2026 } 2027 2028 return FALSE; 2029 } 2030 2031 static 2032 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables) 2033 { 2034 int j; 2035 cmsUInt32Number i; 2036 cmsUInt16Number val; 2037 int nEntries; 2038 2039 _cmsAssert(Tables != NULL); 2040 2041 nEntries = Tables->TheCurves[0]->nEntries; 2042 2043 for (i=0; i < Tables ->nCurves; i++) { 2044 2045 for (j=0; j < nEntries; j++) { 2046 2047 val = Tables->TheCurves[i]->Table16[j]; 2048 if (!_cmsWriteUInt16Number(io, val)) return FALSE; 2049 } 2050 } 2051 return TRUE; 2052 2053 cmsUNUSED_PARAMETER(ContextID); 2054 } 2055 2056 static 2057 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 2058 { 2059 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; 2060 cmsPipeline* NewLUT = NULL; 2061 cmsUInt32Number nTabSize; 2062 cmsFloat64Number Matrix[3*3]; 2063 cmsUInt16Number InputEntries, OutputEntries; 2064 2065 *nItems = 0; 2066 2067 if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL; 2068 if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL; 2069 if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum 2070 2071 // Padding 2072 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2073 2074 // Do some checking 2075 if (InputChannels > cmsMAXCHANNELS) goto Error; 2076 if (OutputChannels > cmsMAXCHANNELS) goto Error; 2077 2078 // Allocates an empty LUT 2079 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels); 2080 if (NewLUT == NULL) goto Error; 2081 2082 // Read the Matrix 2083 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error; 2084 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error; 2085 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error; 2086 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error; 2087 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error; 2088 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error; 2089 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error; 2090 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error; 2091 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error; 2092 2093 2094 // Only operates on 3 channels 2095 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { 2096 2097 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) 2098 goto Error; 2099 } 2100 2101 if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error; 2102 if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error; 2103 2104 if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error; 2105 if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least 2106 2107 // Get input tables 2108 if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error; 2109 2110 // Get 3D CLUT 2111 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); 2112 if (nTabSize == (cmsUInt32Number) -1) goto Error; 2113 if (nTabSize > 0) { 2114 2115 cmsUInt16Number *T; 2116 2117 T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); 2118 if (T == NULL) goto Error; 2119 2120 if (!_cmsReadUInt16Array(io, nTabSize, T)) { 2121 _cmsFree(self ->ContextID, T); 2122 goto Error; 2123 } 2124 2125 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) { 2126 _cmsFree(self ->ContextID, T); 2127 goto Error; 2128 } 2129 _cmsFree(self ->ContextID, T); 2130 } 2131 2132 2133 // Get output tables 2134 if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error; 2135 2136 *nItems = 1; 2137 return NewLUT; 2138 2139 Error: 2140 if (NewLUT != NULL) cmsPipelineFree(NewLUT); 2141 return NULL; 2142 2143 cmsUNUSED_PARAMETER(SizeOfTag); 2144 } 2145 2146 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin. 2147 // Some empty defaults are created for missing parts 2148 2149 static 2150 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 2151 { 2152 cmsUInt32Number nTabSize; 2153 cmsPipeline* NewLUT = (cmsPipeline*) Ptr; 2154 cmsStage* mpe; 2155 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; 2156 _cmsStageMatrixData* MatMPE = NULL; 2157 _cmsStageCLutData* clut = NULL; 2158 int i, InputChannels, OutputChannels, clutPoints; 2159 2160 // Disassemble the LUT into components. 2161 mpe = NewLUT -> Elements; 2162 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) { 2163 2164 MatMPE = (_cmsStageMatrixData*) mpe ->Data; 2165 mpe = mpe -> Next; 2166 } 2167 2168 2169 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { 2170 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data; 2171 mpe = mpe -> Next; 2172 } 2173 2174 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) { 2175 clut = (_cmsStageCLutData*) mpe -> Data; 2176 mpe = mpe ->Next; 2177 } 2178 2179 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) { 2180 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data; 2181 mpe = mpe -> Next; 2182 } 2183 2184 // That should be all 2185 if (mpe != NULL) { 2186 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16"); 2187 return FALSE; 2188 } 2189 2190 InputChannels = cmsPipelineInputChannels(NewLUT); 2191 OutputChannels = cmsPipelineOutputChannels(NewLUT); 2192 2193 if (clut == NULL) 2194 clutPoints = 0; 2195 else 2196 clutPoints = clut->Params->nSamples[0]; 2197 2198 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE; 2199 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE; 2200 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE; 2201 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding 2202 2203 2204 if (MatMPE != NULL) { 2205 2206 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE; 2207 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE; 2208 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE; 2209 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE; 2210 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE; 2211 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE; 2212 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE; 2213 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE; 2214 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE; 2215 } 2216 else { 2217 2218 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 2219 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2220 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2221 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2222 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 2223 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2224 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2225 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2226 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE; 2227 } 2228 2229 2230 if (PreMPE != NULL) { 2231 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE; 2232 } else { 2233 if (!_cmsWriteUInt16Number(io, 2)) return FALSE; 2234 } 2235 2236 if (PostMPE != NULL) { 2237 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE; 2238 } else { 2239 if (!_cmsWriteUInt16Number(io, 2)) return FALSE; 2240 2241 } 2242 2243 // The prelinearization table 2244 2245 if (PreMPE != NULL) { 2246 if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; 2247 } 2248 else { 2249 for (i=0; i < InputChannels; i++) { 2250 2251 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2252 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; 2253 } 2254 } 2255 2256 nTabSize = uipow(OutputChannels, clutPoints, InputChannels); 2257 if (nTabSize == (cmsUInt32Number) -1) return FALSE; 2258 if (nTabSize > 0) { 2259 // The 3D CLUT. 2260 if (clut != NULL) { 2261 if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; 2262 } 2263 } 2264 2265 // The postlinearization table 2266 if (PostMPE != NULL) { 2267 if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE; 2268 } 2269 else { 2270 for (i=0; i < OutputChannels; i++) { 2271 2272 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2273 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; 2274 } 2275 } 2276 2277 return TRUE; 2278 2279 cmsUNUSED_PARAMETER(nItems); 2280 } 2281 2282 static 2283 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 2284 { 2285 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 2286 2287 cmsUNUSED_PARAMETER(n); 2288 cmsUNUSED_PARAMETER(self); 2289 } 2290 2291 static 2292 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr) 2293 { 2294 cmsPipelineFree((cmsPipeline*) Ptr); 2295 return; 2296 2297 cmsUNUSED_PARAMETER(self); 2298 } 2299 2300 2301 // ******************************************************************************** 2302 // Type cmsSigLutAToBType 2303 // ******************************************************************************** 2304 2305 2306 // V4 stuff. Read matrix for LutAtoB and LutBtoA 2307 2308 static 2309 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset) 2310 { 2311 cmsFloat64Number dMat[3*3]; 2312 cmsFloat64Number dOff[3]; 2313 cmsStage* Mat; 2314 2315 // Go to address 2316 if (!io -> Seek(io, Offset)) return NULL; 2317 2318 // Read the Matrix 2319 if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL; 2320 if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL; 2321 if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL; 2322 if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL; 2323 if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL; 2324 if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL; 2325 if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL; 2326 if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL; 2327 if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL; 2328 2329 if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL; 2330 if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL; 2331 if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL; 2332 2333 Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff); 2334 2335 return Mat; 2336 } 2337 2338 2339 2340 2341 // V4 stuff. Read CLUT part for LutAtoB and LutBtoA 2342 2343 static 2344 cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels) 2345 { 2346 cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension. 2347 cmsUInt32Number GridPoints[cmsMAXCHANNELS], i; 2348 cmsUInt8Number Precision; 2349 cmsStage* CLUT; 2350 _cmsStageCLutData* Data; 2351 2352 if (!io -> Seek(io, Offset)) return NULL; 2353 if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL; 2354 2355 2356 for (i=0; i < cmsMAXCHANNELS; i++) { 2357 2358 if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least 2359 GridPoints[i] = gridPoints8[i]; 2360 } 2361 2362 if (!_cmsReadUInt8Number(io, &Precision)) return NULL; 2363 2364 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2365 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2366 if (!_cmsReadUInt8Number(io, NULL)) return NULL; 2367 2368 CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL); 2369 if (CLUT == NULL) return NULL; 2370 2371 Data = (_cmsStageCLutData*) CLUT ->Data; 2372 2373 // Precision can be 1 or 2 bytes 2374 if (Precision == 1) { 2375 2376 cmsUInt8Number v; 2377 2378 for (i=0; i < Data ->nEntries; i++) { 2379 2380 if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL; 2381 Data ->Tab.T[i] = FROM_8_TO_16(v); 2382 } 2383 2384 } 2385 else 2386 if (Precision == 2) { 2387 2388 if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) { 2389 cmsStageFree(CLUT); 2390 return NULL; 2391 } 2392 } 2393 else { 2394 cmsStageFree(CLUT); 2395 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); 2396 return NULL; 2397 } 2398 2399 return CLUT; 2400 } 2401 2402 static 2403 cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) 2404 { 2405 cmsTagTypeSignature BaseType; 2406 cmsUInt32Number nItems; 2407 2408 BaseType = _cmsReadTypeBase(io); 2409 switch (BaseType) { 2410 2411 case cmsSigCurveType: 2412 return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0); 2413 2414 case cmsSigParametricCurveType: 2415 return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0); 2416 2417 default: 2418 { 2419 char String[5]; 2420 2421 _cmsTagSignature2String(String, (cmsTagSignature) BaseType); 2422 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); 2423 } 2424 return NULL; 2425 } 2426 } 2427 2428 2429 // Read a set of curves from specific offset 2430 static 2431 cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves) 2432 { 2433 cmsToneCurve* Curves[cmsMAXCHANNELS]; 2434 cmsUInt32Number i; 2435 cmsStage* Lin = NULL; 2436 2437 if (nCurves > cmsMAXCHANNELS) return FALSE; 2438 2439 if (!io -> Seek(io, Offset)) return FALSE; 2440 2441 for (i=0; i < nCurves; i++) 2442 Curves[i] = NULL; 2443 2444 for (i=0; i < nCurves; i++) { 2445 2446 Curves[i] = ReadEmbeddedCurve(self, io); 2447 if (Curves[i] == NULL) goto Error; 2448 if (!_cmsReadAlignment(io)) goto Error; 2449 2450 } 2451 2452 Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves); 2453 2454 Error: 2455 for (i=0; i < nCurves; i++) 2456 cmsFreeToneCurve(Curves[i]); 2457 2458 return Lin; 2459 } 2460 2461 2462 // LutAtoB type 2463 2464 // This structure represents a colour transform. The type contains up to five processing 2465 // elements which are stored in the AtoBTag tag in the following order: a set of one 2466 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves, 2467 // a multidimensional lookup table, and a set of one dimensional output curves. 2468 // Data are processed using these elements via the following sequence: 2469 // 2470 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves). 2471 // 2472 /* 2473 It is possible to use any or all of these processing elements. At least one processing element 2474 must be included.Only the following combinations are allowed: 2475 2476 B 2477 M - Matrix - B 2478 A - CLUT - B 2479 A - CLUT - M - Matrix - B 2480 2481 */ 2482 2483 static 2484 void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 2485 { 2486 cmsUInt32Number BaseOffset; 2487 cmsUInt8Number inputChan; // Number of input channels 2488 cmsUInt8Number outputChan; // Number of output channels 2489 cmsUInt32Number offsetB; // Offset to first "B" curve 2490 cmsUInt32Number offsetMat; // Offset to matrix 2491 cmsUInt32Number offsetM; // Offset to first "M" curve 2492 cmsUInt32Number offsetC; // Offset to CLUT 2493 cmsUInt32Number offsetA; // Offset to first "A" curve 2494 cmsPipeline* NewLUT = NULL; 2495 2496 2497 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2498 2499 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; 2500 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; 2501 2502 if (!_cmsReadUInt16Number(io, NULL)) return NULL; 2503 2504 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; 2505 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; 2506 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; 2507 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; 2508 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; 2509 2510 // Allocates an empty LUT 2511 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); 2512 if (NewLUT == NULL) return NULL; 2513 2514 if (offsetA!= 0) { 2515 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan))) 2516 goto Error; 2517 } 2518 2519 if (offsetC != 0) { 2520 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) 2521 goto Error; 2522 } 2523 2524 if (offsetM != 0) { 2525 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan))) 2526 goto Error; 2527 } 2528 2529 if (offsetMat != 0) { 2530 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) 2531 goto Error; 2532 } 2533 2534 if (offsetB != 0) { 2535 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan))) 2536 goto Error; 2537 } 2538 2539 *nItems = 1; 2540 return NewLUT; 2541 Error: 2542 cmsPipelineFree(NewLUT); 2543 return NULL; 2544 2545 cmsUNUSED_PARAMETER(SizeOfTag); 2546 } 2547 2548 // Write a set of curves 2549 static 2550 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe) 2551 { 2552 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data; 2553 2554 // Write the Matrix 2555 if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE; 2556 if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE; 2557 if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE; 2558 if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE; 2559 if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE; 2560 if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE; 2561 if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE; 2562 if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE; 2563 if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE; 2564 2565 if (m ->Offset != NULL) { 2566 2567 if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE; 2568 if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE; 2569 if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE; 2570 } 2571 else { 2572 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2573 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2574 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; 2575 2576 } 2577 2578 2579 return TRUE; 2580 2581 cmsUNUSED_PARAMETER(self); 2582 } 2583 2584 2585 // Write a set of curves 2586 static 2587 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe) 2588 { 2589 cmsUInt32Number i, n; 2590 cmsTagTypeSignature CurrentType; 2591 cmsToneCurve** Curves; 2592 2593 2594 n = cmsStageOutputChannels(mpe); 2595 Curves = _cmsStageGetPtrToCurveSet(mpe); 2596 2597 for (i=0; i < n; i++) { 2598 2599 // If this is a table-based curve, use curve type even on V4 2600 CurrentType = Type; 2601 2602 if ((Curves[i] ->nSegments == 0)|| 2603 ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) ) 2604 CurrentType = cmsSigCurveType; 2605 else 2606 if (Curves[i] ->Segments[0].Type < 0) 2607 CurrentType = cmsSigCurveType; 2608 2609 if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE; 2610 2611 switch (CurrentType) { 2612 2613 case cmsSigCurveType: 2614 if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE; 2615 break; 2616 2617 case cmsSigParametricCurveType: 2618 if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE; 2619 break; 2620 2621 default: 2622 { 2623 char String[5]; 2624 2625 _cmsTagSignature2String(String, (cmsTagSignature) Type); 2626 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); 2627 } 2628 return FALSE; 2629 } 2630 2631 if (!_cmsWriteAlignment(io)) return FALSE; 2632 } 2633 2634 2635 return TRUE; 2636 } 2637 2638 2639 static 2640 cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe) 2641 { 2642 cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension. 2643 cmsUInt32Number i; 2644 _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data; 2645 2646 if (CLUT ->HasFloatValues) { 2647 cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only"); 2648 return FALSE; 2649 } 2650 2651 memset(gridPoints, 0, sizeof(gridPoints)); 2652 for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++) 2653 gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i]; 2654 2655 if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE; 2656 2657 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE; 2658 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; 2659 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; 2660 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; 2661 2662 // Precision can be 1 or 2 bytes 2663 if (Precision == 1) { 2664 2665 for (i=0; i < CLUT->nEntries; i++) { 2666 2667 if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE; 2668 } 2669 } 2670 else 2671 if (Precision == 2) { 2672 2673 if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE; 2674 } 2675 else { 2676 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); 2677 return FALSE; 2678 } 2679 2680 if (!_cmsWriteAlignment(io)) return FALSE; 2681 2682 return TRUE; 2683 } 2684 2685 2686 2687 2688 static 2689 cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 2690 { 2691 cmsPipeline* Lut = (cmsPipeline*) Ptr; 2692 int inputChan, outputChan; 2693 cmsStage *A = NULL, *B = NULL, *M = NULL; 2694 cmsStage * Matrix = NULL; 2695 cmsStage * CLUT = NULL; 2696 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; 2697 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; 2698 2699 // Get the base for all offsets 2700 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2701 2702 if (Lut ->Elements != NULL) 2703 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) 2704 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B)) 2705 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B)) 2706 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, 2707 cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) { 2708 2709 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB"); 2710 return FALSE; 2711 } 2712 2713 // Get input, output channels 2714 inputChan = cmsPipelineInputChannels(Lut); 2715 outputChan = cmsPipelineOutputChannels(Lut); 2716 2717 // Write channel count 2718 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; 2719 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; 2720 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2721 2722 // Keep directory to be filled latter 2723 DirectoryPos = io ->Tell(io); 2724 2725 // Write the directory 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 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2731 2732 if (A != NULL) { 2733 2734 offsetA = io ->Tell(io) - BaseOffset; 2735 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; 2736 } 2737 2738 if (CLUT != NULL) { 2739 offsetC = io ->Tell(io) - BaseOffset; 2740 if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; 2741 2742 } 2743 if (M != NULL) { 2744 2745 offsetM = io ->Tell(io) - BaseOffset; 2746 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; 2747 } 2748 2749 if (Matrix != NULL) { 2750 offsetMat = io ->Tell(io) - BaseOffset; 2751 if (!WriteMatrix(self, io, Matrix)) return FALSE; 2752 } 2753 2754 if (B != NULL) { 2755 2756 offsetB = io ->Tell(io) - BaseOffset; 2757 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; 2758 } 2759 2760 CurrentPos = io ->Tell(io); 2761 2762 if (!io ->Seek(io, DirectoryPos)) return FALSE; 2763 2764 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; 2765 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; 2766 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; 2767 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; 2768 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; 2769 2770 if (!io ->Seek(io, CurrentPos)) return FALSE; 2771 2772 return TRUE; 2773 2774 cmsUNUSED_PARAMETER(nItems); 2775 } 2776 2777 2778 static 2779 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 2780 { 2781 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 2782 2783 cmsUNUSED_PARAMETER(n); 2784 cmsUNUSED_PARAMETER(self); 2785 } 2786 2787 static 2788 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr) 2789 { 2790 cmsPipelineFree((cmsPipeline*) Ptr); 2791 return; 2792 2793 cmsUNUSED_PARAMETER(self); 2794 } 2795 2796 2797 // LutBToA type 2798 2799 static 2800 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 2801 { 2802 cmsUInt8Number inputChan; // Number of input channels 2803 cmsUInt8Number outputChan; // Number of output channels 2804 cmsUInt32Number BaseOffset; // Actual position in file 2805 cmsUInt32Number offsetB; // Offset to first "B" curve 2806 cmsUInt32Number offsetMat; // Offset to matrix 2807 cmsUInt32Number offsetM; // Offset to first "M" curve 2808 cmsUInt32Number offsetC; // Offset to CLUT 2809 cmsUInt32Number offsetA; // Offset to first "A" curve 2810 cmsPipeline* NewLUT = NULL; 2811 2812 2813 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2814 2815 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL; 2816 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL; 2817 2818 // Padding 2819 if (!_cmsReadUInt16Number(io, NULL)) return NULL; 2820 2821 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL; 2822 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL; 2823 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL; 2824 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL; 2825 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL; 2826 2827 // Allocates an empty LUT 2828 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan); 2829 if (NewLUT == NULL) return NULL; 2830 2831 if (offsetB != 0) { 2832 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan))) 2833 goto Error; 2834 } 2835 2836 if (offsetMat != 0) { 2837 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) 2838 goto Error; 2839 } 2840 2841 if (offsetM != 0) { 2842 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan))) 2843 goto Error; 2844 } 2845 2846 if (offsetC != 0) { 2847 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) 2848 goto Error; 2849 } 2850 2851 if (offsetA!= 0) { 2852 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan))) 2853 goto Error; 2854 } 2855 2856 *nItems = 1; 2857 return NewLUT; 2858 Error: 2859 cmsPipelineFree(NewLUT); 2860 return NULL; 2861 2862 cmsUNUSED_PARAMETER(SizeOfTag); 2863 } 2864 2865 2866 /* 2867 B 2868 B - Matrix - M 2869 B - CLUT - A 2870 B - Matrix - M - CLUT - A 2871 */ 2872 2873 static 2874 cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 2875 { 2876 cmsPipeline* Lut = (cmsPipeline*) Ptr; 2877 int inputChan, outputChan; 2878 cmsStage *A = NULL, *B = NULL, *M = NULL; 2879 cmsStage *Matrix = NULL; 2880 cmsStage *CLUT = NULL; 2881 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0; 2882 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos; 2883 2884 2885 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 2886 2887 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B)) 2888 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M)) 2889 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A)) 2890 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, 2891 cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) { 2892 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA"); 2893 return FALSE; 2894 } 2895 2896 inputChan = cmsPipelineInputChannels(Lut); 2897 outputChan = cmsPipelineOutputChannels(Lut); 2898 2899 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE; 2900 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE; 2901 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; 2902 2903 DirectoryPos = io ->Tell(io); 2904 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 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 2910 2911 if (A != NULL) { 2912 2913 offsetA = io ->Tell(io) - BaseOffset; 2914 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE; 2915 } 2916 2917 if (CLUT != NULL) { 2918 offsetC = io ->Tell(io) - BaseOffset; 2919 if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE; 2920 2921 } 2922 if (M != NULL) { 2923 2924 offsetM = io ->Tell(io) - BaseOffset; 2925 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE; 2926 } 2927 2928 if (Matrix != NULL) { 2929 offsetMat = io ->Tell(io) - BaseOffset; 2930 if (!WriteMatrix(self, io, Matrix)) return FALSE; 2931 } 2932 2933 if (B != NULL) { 2934 2935 offsetB = io ->Tell(io) - BaseOffset; 2936 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE; 2937 } 2938 2939 CurrentPos = io ->Tell(io); 2940 2941 if (!io ->Seek(io, DirectoryPos)) return FALSE; 2942 2943 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE; 2944 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE; 2945 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE; 2946 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE; 2947 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE; 2948 2949 if (!io ->Seek(io, CurrentPos)) return FALSE; 2950 2951 return TRUE; 2952 2953 cmsUNUSED_PARAMETER(nItems); 2954 } 2955 2956 2957 2958 static 2959 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 2960 { 2961 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 2962 2963 cmsUNUSED_PARAMETER(n); 2964 cmsUNUSED_PARAMETER(self); 2965 } 2966 2967 static 2968 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr) 2969 { 2970 cmsPipelineFree((cmsPipeline*) Ptr); 2971 return; 2972 2973 cmsUNUSED_PARAMETER(self); 2974 } 2975 2976 2977 2978 // ******************************************************************************** 2979 // Type cmsSigColorantTableType 2980 // ******************************************************************************** 2981 /* 2982 The purpose of this tag is to identify the colorants used in the profile by a 2983 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous 2984 value. The first colorant listed is the colorant of the first device channel of 2985 a lut tag. The second colorant listed is the colorant of the second device channel 2986 of a lut tag, and so on. 2987 */ 2988 2989 static 2990 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 2991 { 2992 cmsUInt32Number i, Count; 2993 cmsNAMEDCOLORLIST* List; 2994 char Name[34]; 2995 cmsUInt16Number PCS[3]; 2996 2997 2998 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 2999 3000 if (Count > cmsMAXCHANNELS) { 3001 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count); 3002 return NULL; 3003 } 3004 3005 List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", ""); 3006 for (i=0; i < Count; i++) { 3007 3008 if (io ->Read(io, Name, 32, 1) != 1) goto Error; 3009 Name[33] = 0; 3010 3011 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; 3012 3013 if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error; 3014 3015 } 3016 3017 *nItems = 1; 3018 return List; 3019 3020 Error: 3021 *nItems = 0; 3022 cmsFreeNamedColorList(List); 3023 return NULL; 3024 3025 cmsUNUSED_PARAMETER(SizeOfTag); 3026 } 3027 3028 3029 3030 // Saves a colorant table. It is using the named color structure for simplicity sake 3031 static 3032 cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3033 { 3034 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; 3035 int i, nColors; 3036 3037 nColors = cmsNamedColorCount(NamedColorList); 3038 3039 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; 3040 3041 for (i=0; i < nColors; i++) { 3042 3043 char root[33]; 3044 cmsUInt16Number PCS[3]; 3045 3046 if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0; 3047 root[32] = 0; 3048 3049 if (!io ->Write(io, 32, root)) return FALSE; 3050 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; 3051 } 3052 3053 return TRUE; 3054 3055 cmsUNUSED_PARAMETER(nItems); 3056 cmsUNUSED_PARAMETER(self); 3057 } 3058 3059 3060 static 3061 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3062 { 3063 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; 3064 return (void*) cmsDupNamedColorList(nc); 3065 3066 cmsUNUSED_PARAMETER(n); 3067 cmsUNUSED_PARAMETER(self); 3068 } 3069 3070 3071 static 3072 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) 3073 { 3074 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); 3075 return; 3076 3077 cmsUNUSED_PARAMETER(self); 3078 } 3079 3080 3081 // ******************************************************************************** 3082 // Type cmsSigNamedColor2Type 3083 // ******************************************************************************** 3084 // 3085 //The namedColor2Type is a count value and array of structures that provide color 3086 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional 3087 //device representation of the color are given. Both representations are 16-bit values. 3088 //The device representation corresponds to the headers color space of data field. 3089 //This representation should be consistent with the number of device components 3090 //field in the namedColor2Type. If this field is 0, device coordinates are not provided. 3091 //The PCS representation corresponds to the headers PCS field. The PCS representation 3092 //is always provided. Color names are fixed-length, 32-byte fields including null 3093 //termination. In order to maintain maximum portability, it is strongly recommended 3094 //that special characters of the 7-bit ASCII set not be used. 3095 3096 static 3097 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3098 { 3099 3100 cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use 3101 cmsUInt32Number count; // Count of named colors 3102 cmsUInt32Number nDeviceCoords; // Num of device coordinates 3103 char prefix[32]; // Prefix for each color name 3104 char suffix[32]; // Suffix for each color name 3105 cmsNAMEDCOLORLIST* v; 3106 cmsUInt32Number i; 3107 3108 3109 *nItems = 0; 3110 if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL; 3111 if (!_cmsReadUInt32Number(io, &count)) return NULL; 3112 if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL; 3113 3114 if (io -> Read(io, prefix, 32, 1) != 1) return NULL; 3115 if (io -> Read(io, suffix, 32, 1) != 1) return NULL; 3116 3117 prefix[31] = suffix[31] = 0; 3118 3119 v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix); 3120 if (v == NULL) { 3121 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count); 3122 return NULL; 3123 } 3124 3125 if (nDeviceCoords > cmsMAXCHANNELS) { 3126 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords); 3127 return 0; 3128 } 3129 for (i=0; i < count; i++) { 3130 3131 cmsUInt16Number PCS[3]; 3132 cmsUInt16Number Colorant[cmsMAXCHANNELS]; 3133 char Root[33]; 3134 3135 memset(Colorant, 0, sizeof(Colorant)); 3136 if (io -> Read(io, Root, 32, 1) != 1) return NULL; 3137 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error; 3138 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error; 3139 3140 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error; 3141 } 3142 3143 *nItems = 1; 3144 return (void*) v ; 3145 3146 Error: 3147 cmsFreeNamedColorList(v); 3148 return NULL; 3149 3150 cmsUNUSED_PARAMETER(SizeOfTag); 3151 } 3152 3153 3154 // Saves a named color list into a named color profile 3155 static 3156 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3157 { 3158 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr; 3159 char prefix[32]; // Prefix for each color name 3160 char suffix[32]; // Suffix for each color name 3161 int i, nColors; 3162 3163 nColors = cmsNamedColorCount(NamedColorList); 3164 3165 if (!_cmsWriteUInt32Number(io, 0)) return FALSE; 3166 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; 3167 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE; 3168 3169 strncpy(prefix, (const char*) NamedColorList->Prefix, 32); 3170 strncpy(suffix, (const char*) NamedColorList->Suffix, 32); 3171 3172 suffix[31] = prefix[31] = 0; 3173 3174 if (!io ->Write(io, 32, prefix)) return FALSE; 3175 if (!io ->Write(io, 32, suffix)) return FALSE; 3176 3177 for (i=0; i < nColors; i++) { 3178 3179 cmsUInt16Number PCS[3]; 3180 cmsUInt16Number Colorant[cmsMAXCHANNELS]; 3181 char Root[33]; 3182 3183 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; 3184 if (!io ->Write(io, 32 , Root)) return FALSE; 3185 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE; 3186 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE; 3187 } 3188 3189 return TRUE; 3190 3191 cmsUNUSED_PARAMETER(nItems); 3192 cmsUNUSED_PARAMETER(self); 3193 } 3194 3195 static 3196 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3197 { 3198 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr; 3199 3200 return (void*) cmsDupNamedColorList(nc); 3201 3202 cmsUNUSED_PARAMETER(n); 3203 cmsUNUSED_PARAMETER(self); 3204 } 3205 3206 3207 static 3208 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) 3209 { 3210 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr); 3211 return; 3212 3213 cmsUNUSED_PARAMETER(self); 3214 } 3215 3216 3217 // ******************************************************************************** 3218 // Type cmsSigProfileSequenceDescType 3219 // ******************************************************************************** 3220 3221 // This type is an array of structures, each of which contains information from the 3222 // header fields and tags from the original profiles which were combined to create 3223 // the final profile. The order of the structures is the order in which the profiles 3224 // were combined and includes a structure for the final profile. This provides a 3225 // description of the profile sequence from source to destination, 3226 // typically used with the DeviceLink profile. 3227 3228 static 3229 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag) 3230 { 3231 cmsTagTypeSignature BaseType; 3232 cmsUInt32Number nItems; 3233 3234 BaseType = _cmsReadTypeBase(io); 3235 3236 switch (BaseType) { 3237 3238 case cmsSigTextType: 3239 if (*mlu) cmsMLUfree(*mlu); 3240 *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag); 3241 return (*mlu != NULL); 3242 3243 case cmsSigTextDescriptionType: 3244 if (*mlu) cmsMLUfree(*mlu); 3245 *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag); 3246 return (*mlu != NULL); 3247 3248 /* 3249 TBD: Size is needed for MLU, and we have no idea on which is the available size 3250 */ 3251 3252 case cmsSigMultiLocalizedUnicodeType: 3253 if (*mlu) cmsMLUfree(*mlu); 3254 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag); 3255 return (*mlu != NULL); 3256 3257 default: return FALSE; 3258 } 3259 } 3260 3261 3262 static 3263 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3264 { 3265 cmsSEQ* OutSeq; 3266 cmsUInt32Number i, Count; 3267 3268 *nItems = 0; 3269 3270 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 3271 3272 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3273 SizeOfTag -= sizeof(cmsUInt32Number); 3274 3275 3276 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); 3277 if (OutSeq == NULL) return NULL; 3278 3279 OutSeq ->n = Count; 3280 3281 // Get structures as well 3282 3283 for (i=0; i < Count; i++) { 3284 3285 cmsPSEQDESC* sec = &OutSeq -> seq[i]; 3286 3287 if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error; 3288 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; 3289 SizeOfTag -= sizeof(cmsUInt32Number); 3290 3291 if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error; 3292 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; 3293 SizeOfTag -= sizeof(cmsUInt32Number); 3294 3295 if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error; 3296 if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error; 3297 SizeOfTag -= sizeof(cmsUInt64Number); 3298 3299 if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error; 3300 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; 3301 SizeOfTag -= sizeof(cmsUInt32Number); 3302 3303 if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error; 3304 if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error; 3305 } 3306 3307 *nItems = 1; 3308 return OutSeq; 3309 3310 Error: 3311 cmsFreeProfileSequenceDescription(OutSeq); 3312 return NULL; 3313 } 3314 3315 3316 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode 3317 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack 3318 static 3319 cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text) 3320 { 3321 if (self ->ICCVersion < 0x4000000) { 3322 3323 if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; 3324 return Type_Text_Description_Write(self, io, Text, 1); 3325 } 3326 else { 3327 if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE; 3328 return Type_MLU_Write(self, io, Text, 1); 3329 } 3330 } 3331 3332 3333 static 3334 cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3335 { 3336 cmsSEQ* Seq = (cmsSEQ*) Ptr; 3337 cmsUInt32Number i; 3338 3339 if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE; 3340 3341 for (i=0; i < Seq ->n; i++) { 3342 3343 cmsPSEQDESC* sec = &Seq -> seq[i]; 3344 3345 if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE; 3346 if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE; 3347 if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE; 3348 if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE; 3349 3350 if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; 3351 if (!SaveDescription(self, io, sec ->Model)) return FALSE; 3352 } 3353 3354 return TRUE; 3355 3356 cmsUNUSED_PARAMETER(nItems); 3357 } 3358 3359 3360 static 3361 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3362 { 3363 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); 3364 3365 cmsUNUSED_PARAMETER(n); 3366 cmsUNUSED_PARAMETER(self); 3367 } 3368 3369 static 3370 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr) 3371 { 3372 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); 3373 return; 3374 3375 cmsUNUSED_PARAMETER(self); 3376 } 3377 3378 3379 // ******************************************************************************** 3380 // Type cmsSigProfileSequenceIdType 3381 // ******************************************************************************** 3382 /* 3383 In certain workflows using ICC Device Link Profiles, it is necessary to identify the 3384 original profiles that were combined to create the Device Link Profile. 3385 This type is an array of structures, each of which contains information for 3386 identification of a profile used in a sequence 3387 */ 3388 3389 3390 static 3391 cmsBool ReadSeqID(struct _cms_typehandler_struct* self, 3392 cmsIOHANDLER* io, 3393 void* Cargo, 3394 cmsUInt32Number n, 3395 cmsUInt32Number SizeOfTag) 3396 { 3397 cmsSEQ* OutSeq = (cmsSEQ*) Cargo; 3398 cmsPSEQDESC* seq = &OutSeq ->seq[n]; 3399 3400 if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE; 3401 if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE; 3402 3403 return TRUE; 3404 } 3405 3406 3407 3408 static 3409 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3410 { 3411 cmsSEQ* OutSeq; 3412 cmsUInt32Number Count; 3413 cmsUInt32Number BaseOffset; 3414 3415 *nItems = 0; 3416 3417 // Get actual position as a basis for element offsets 3418 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 3419 3420 // Get table count 3421 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 3422 SizeOfTag -= sizeof(cmsUInt32Number); 3423 3424 // Allocate an empty structure 3425 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); 3426 if (OutSeq == NULL) return NULL; 3427 3428 3429 // Read the position table 3430 if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) { 3431 3432 cmsFreeProfileSequenceDescription(OutSeq); 3433 return NULL; 3434 } 3435 3436 // Success 3437 *nItems = 1; 3438 return OutSeq; 3439 3440 } 3441 3442 3443 static 3444 cmsBool WriteSeqID(struct _cms_typehandler_struct* self, 3445 cmsIOHANDLER* io, 3446 void* Cargo, 3447 cmsUInt32Number n, 3448 cmsUInt32Number SizeOfTag) 3449 { 3450 cmsSEQ* Seq = (cmsSEQ*) Cargo; 3451 3452 if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE; 3453 3454 // Store here the MLU 3455 if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE; 3456 3457 return TRUE; 3458 3459 cmsUNUSED_PARAMETER(SizeOfTag); 3460 } 3461 3462 static 3463 cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3464 { 3465 cmsSEQ* Seq = (cmsSEQ*) Ptr; 3466 cmsUInt32Number BaseOffset; 3467 3468 // Keep the base offset 3469 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 3470 3471 // This is the table count 3472 if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE; 3473 3474 // This is the position table and content 3475 if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE; 3476 3477 return TRUE; 3478 3479 cmsUNUSED_PARAMETER(nItems); 3480 } 3481 3482 static 3483 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) 3484 { 3485 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr); 3486 3487 cmsUNUSED_PARAMETER(n); 3488 cmsUNUSED_PARAMETER(self); 3489 } 3490 3491 static 3492 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr) 3493 { 3494 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr); 3495 return; 3496 3497 cmsUNUSED_PARAMETER(self); 3498 } 3499 3500 3501 // ******************************************************************************** 3502 // Type cmsSigUcrBgType 3503 // ******************************************************************************** 3504 /* 3505 This type contains curves representing the under color removal and black 3506 generation and a text string which is a general description of the method used 3507 for the ucr/bg. 3508 */ 3509 3510 static 3511 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3512 { 3513 cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); 3514 cmsUInt32Number CountUcr, CountBg; 3515 char* ASCIIString; 3516 3517 *nItems = 0; 3518 if (n == NULL) return NULL; 3519 3520 // First curve is Under color removal 3521 if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL; 3522 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3523 SizeOfTag -= sizeof(cmsUInt32Number); 3524 3525 n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL); 3526 if (n ->Ucr == NULL) return NULL; 3527 3528 if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL; 3529 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3530 SizeOfTag -= CountUcr * sizeof(cmsUInt16Number); 3531 3532 // Second curve is Black generation 3533 if (!_cmsReadUInt32Number(io, &CountBg)) return NULL; 3534 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; 3535 SizeOfTag -= sizeof(cmsUInt32Number); 3536 3537 n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL); 3538 if (n ->Bg == NULL) return NULL; 3539 if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL; 3540 if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL; 3541 SizeOfTag -= CountBg * sizeof(cmsUInt16Number); 3542 if (SizeOfTag == UINT_MAX) return NULL; 3543 3544 // Now comes the text. The length is specified by the tag size 3545 n ->Desc = cmsMLUalloc(self ->ContextID, 1); 3546 if (n ->Desc == NULL) return NULL; 3547 3548 ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); 3549 if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL; 3550 ASCIIString[SizeOfTag] = 0; 3551 cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString); 3552 _cmsFree(self ->ContextID, ASCIIString); 3553 3554 *nItems = 1; 3555 return (void*) n; 3556 } 3557 3558 static 3559 cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3560 { 3561 cmsUcrBg* Value = (cmsUcrBg*) Ptr; 3562 cmsUInt32Number TextSize; 3563 char* Text; 3564 3565 // First curve is Under color removal 3566 if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE; 3567 if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE; 3568 3569 // Then black generation 3570 if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE; 3571 if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE; 3572 3573 // Now comes the text. The length is specified by the tag size 3574 TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0); 3575 Text = (char*) _cmsMalloc(self ->ContextID, TextSize); 3576 if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE; 3577 3578 if (!io ->Write(io, TextSize, Text)) return FALSE; 3579 _cmsFree(self ->ContextID, Text); 3580 3581 return TRUE; 3582 3583 cmsUNUSED_PARAMETER(nItems); 3584 } 3585 3586 static 3587 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3588 { 3589 cmsUcrBg* Src = (cmsUcrBg*) Ptr; 3590 cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); 3591 3592 if (NewUcrBg == NULL) return NULL; 3593 3594 NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg); 3595 NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr); 3596 NewUcrBg ->Desc = cmsMLUdup(Src ->Desc); 3597 3598 return (void*) NewUcrBg; 3599 3600 cmsUNUSED_PARAMETER(n); 3601 } 3602 3603 static 3604 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr) 3605 { 3606 cmsUcrBg* Src = (cmsUcrBg*) Ptr; 3607 3608 if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr); 3609 if (Src ->Bg) cmsFreeToneCurve(Src ->Bg); 3610 if (Src ->Desc) cmsMLUfree(Src ->Desc); 3611 3612 _cmsFree(self ->ContextID, Ptr); 3613 } 3614 3615 // ******************************************************************************** 3616 // Type cmsSigCrdInfoType 3617 // ******************************************************************************** 3618 3619 /* 3620 This type contains the PostScript product name to which this profile corresponds 3621 and the names of the companion CRDs. Recall that a single profile can generate 3622 multiple CRDs. It is implemented as a MLU being the language code "PS" and then 3623 country varies for each element: 3624 3625 nm: PostScript product name 3626 #0: Rendering intent 0 CRD name 3627 #1: Rendering intent 1 CRD name 3628 #2: Rendering intent 2 CRD name 3629 #3: Rendering intent 3 CRD name 3630 */ 3631 3632 3633 3634 // Auxiliar, read an string specified as count + string 3635 static 3636 cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section) 3637 { 3638 cmsUInt32Number Count; 3639 char* Text; 3640 3641 if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE; 3642 3643 if (!_cmsReadUInt32Number(io, &Count)) return FALSE; 3644 3645 if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE; 3646 if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE; 3647 3648 Text = (char*) _cmsMalloc(self ->ContextID, Count+1); 3649 if (Text == NULL) return FALSE; 3650 3651 if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) { 3652 _cmsFree(self ->ContextID, Text); 3653 return FALSE; 3654 } 3655 3656 Text[Count] = 0; 3657 3658 cmsMLUsetASCII(mlu, "PS", Section, Text); 3659 _cmsFree(self ->ContextID, Text); 3660 3661 *SizeOfTag -= (Count + sizeof(cmsUInt32Number)); 3662 return TRUE; 3663 } 3664 3665 static 3666 cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section) 3667 { 3668 cmsUInt32Number TextSize; 3669 char* Text; 3670 3671 TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0); 3672 Text = (char*) _cmsMalloc(self ->ContextID, TextSize); 3673 3674 if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE; 3675 3676 if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE; 3677 3678 if (!io ->Write(io, TextSize, Text)) return FALSE; 3679 _cmsFree(self ->ContextID, Text); 3680 3681 return TRUE; 3682 } 3683 3684 static 3685 void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3686 { 3687 cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5); 3688 3689 *nItems = 0; 3690 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error; 3691 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error; 3692 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error; 3693 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error; 3694 if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error; 3695 3696 *nItems = 1; 3697 return (void*) mlu; 3698 3699 Error: 3700 cmsMLUfree(mlu); 3701 return NULL; 3702 3703 } 3704 3705 static 3706 cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3707 { 3708 3709 cmsMLU* mlu = (cmsMLU*) Ptr; 3710 3711 if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error; 3712 if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error; 3713 if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error; 3714 if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error; 3715 if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error; 3716 3717 return TRUE; 3718 3719 Error: 3720 return FALSE; 3721 3722 cmsUNUSED_PARAMETER(nItems); 3723 } 3724 3725 3726 static 3727 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3728 { 3729 return (void*) cmsMLUdup((cmsMLU*) Ptr); 3730 3731 cmsUNUSED_PARAMETER(n); 3732 cmsUNUSED_PARAMETER(self); 3733 } 3734 3735 static 3736 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr) 3737 { 3738 cmsMLUfree((cmsMLU*) Ptr); 3739 return; 3740 3741 cmsUNUSED_PARAMETER(self); 3742 } 3743 3744 // ******************************************************************************** 3745 // Type cmsSigScreeningType 3746 // ******************************************************************************** 3747 // 3748 //The screeningType describes various screening parameters including screen 3749 //frequency, screening angle, and spot shape. 3750 3751 static 3752 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3753 { 3754 cmsScreening* sc = NULL; 3755 cmsUInt32Number i; 3756 3757 sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening)); 3758 if (sc == NULL) return NULL; 3759 3760 *nItems = 0; 3761 3762 if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error; 3763 if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error; 3764 3765 if (sc ->nChannels > cmsMAXCHANNELS - 1) 3766 sc ->nChannels = cmsMAXCHANNELS - 1; 3767 3768 for (i=0; i < sc ->nChannels; i++) { 3769 3770 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error; 3771 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error; 3772 if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error; 3773 } 3774 3775 3776 *nItems = 1; 3777 3778 return (void*) sc; 3779 3780 Error: 3781 if (sc != NULL) 3782 _cmsFree(self ->ContextID, sc); 3783 3784 return NULL; 3785 3786 cmsUNUSED_PARAMETER(SizeOfTag); 3787 } 3788 3789 3790 static 3791 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3792 { 3793 cmsScreening* sc = (cmsScreening* ) Ptr; 3794 cmsUInt32Number i; 3795 3796 if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE; 3797 if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE; 3798 3799 for (i=0; i < sc ->nChannels; i++) { 3800 3801 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE; 3802 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE; 3803 if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE; 3804 } 3805 3806 return TRUE; 3807 3808 cmsUNUSED_PARAMETER(nItems); 3809 cmsUNUSED_PARAMETER(self); 3810 } 3811 3812 3813 static 3814 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3815 { 3816 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); 3817 3818 cmsUNUSED_PARAMETER(n); 3819 } 3820 3821 3822 static 3823 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr) 3824 { 3825 _cmsFree(self ->ContextID, Ptr); 3826 } 3827 3828 // ******************************************************************************** 3829 // Type cmsSigViewingConditionsType 3830 // ******************************************************************************** 3831 // 3832 //This type represents a set of viewing condition parameters including: 3833 //CIE absolute illuminant white point tristimulus values and CIE absolute 3834 //surround tristimulus values. 3835 3836 static 3837 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 3838 { 3839 cmsICCViewingConditions* vc = NULL; 3840 3841 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions)); 3842 if (vc == NULL) return NULL; 3843 3844 *nItems = 0; 3845 3846 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error; 3847 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error; 3848 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error; 3849 3850 *nItems = 1; 3851 3852 return (void*) vc; 3853 3854 Error: 3855 if (vc != NULL) 3856 _cmsFree(self ->ContextID, vc); 3857 3858 return NULL; 3859 3860 cmsUNUSED_PARAMETER(SizeOfTag); 3861 } 3862 3863 3864 static 3865 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 3866 { 3867 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr; 3868 3869 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE; 3870 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE; 3871 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE; 3872 3873 return TRUE; 3874 3875 cmsUNUSED_PARAMETER(nItems); 3876 cmsUNUSED_PARAMETER(self); 3877 } 3878 3879 3880 static 3881 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3882 { 3883 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening)); 3884 3885 cmsUNUSED_PARAMETER(n); 3886 } 3887 3888 3889 static 3890 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr) 3891 { 3892 _cmsFree(self ->ContextID, Ptr); 3893 } 3894 3895 3896 // ******************************************************************************** 3897 // Type cmsSigMultiProcessElementType 3898 // ******************************************************************************** 3899 3900 3901 static 3902 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 3903 { 3904 return (void*) cmsStageDup((cmsStage*) Ptr); 3905 3906 cmsUNUSED_PARAMETER(n); 3907 cmsUNUSED_PARAMETER(self); 3908 } 3909 3910 static 3911 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr) 3912 { 3913 cmsStageFree((cmsStage*) Ptr); 3914 return; 3915 3916 cmsUNUSED_PARAMETER(self); 3917 } 3918 3919 // Each curve is stored in one or more curve segments, with break-points specified between curve segments. 3920 // The first curve segment always starts at Infinity, and the last curve segment always ends at +Infinity. The 3921 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be 3922 // specified either in terms of a formula, or by a sampled curve. 3923 3924 3925 // Read an embedded segmented curve 3926 static 3927 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io) 3928 { 3929 cmsCurveSegSignature ElementSig; 3930 cmsUInt32Number i, j; 3931 cmsUInt16Number nSegments; 3932 cmsCurveSegment* Segments; 3933 cmsToneCurve* Curve; 3934 cmsFloat32Number PrevBreak = -1E22F; // - infinite 3935 3936 // Take signature and channels for each element. 3937 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL; 3938 3939 // That should be a segmented curve 3940 if (ElementSig != cmsSigSegmentedCurve) return NULL; 3941 3942 if (!_cmsReadUInt32Number(io, NULL)) return NULL; 3943 if (!_cmsReadUInt16Number(io, &nSegments)) return NULL; 3944 if (!_cmsReadUInt16Number(io, NULL)) return NULL; 3945 3946 if (nSegments < 1) return NULL; 3947 Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment)); 3948 if (Segments == NULL) return NULL; 3949 3950 // Read breakpoints 3951 for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) { 3952 3953 Segments[i].x0 = PrevBreak; 3954 if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error; 3955 PrevBreak = Segments[i].x1; 3956 } 3957 3958 Segments[nSegments-1].x0 = PrevBreak; 3959 Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number 3960 3961 // Read segments 3962 for (i=0; i < nSegments; i++) { 3963 3964 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error; 3965 if (!_cmsReadUInt32Number(io, NULL)) goto Error; 3966 3967 switch (ElementSig) { 3968 3969 case cmsSigFormulaCurveSeg: { 3970 3971 cmsUInt16Number Type; 3972 cmsUInt32Number ParamsByType[] = {4, 5, 5 }; 3973 3974 if (!_cmsReadUInt16Number(io, &Type)) goto Error; 3975 if (!_cmsReadUInt16Number(io, NULL)) goto Error; 3976 3977 Segments[i].Type = Type + 6; 3978 if (Type > 2) goto Error; 3979 3980 for (j=0; j < ParamsByType[Type]; j++) { 3981 3982 cmsFloat32Number f; 3983 if (!_cmsReadFloat32Number(io, &f)) goto Error; 3984 Segments[i].Params[j] = f; 3985 } 3986 } 3987 break; 3988 3989 3990 case cmsSigSampledCurveSeg: { 3991 cmsUInt32Number Count; 3992 3993 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 3994 3995 Segments[i].nGridPoints = Count; 3996 Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); 3997 if (Segments[i].SampledPoints == NULL) goto Error; 3998 3999 for (j=0; j < Count; j++) { 4000 if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error; 4001 } 4002 } 4003 break; 4004 4005 default: 4006 { 4007 char String[5]; 4008 4009 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); 4010 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String); 4011 } 4012 return NULL; 4013 4014 } 4015 } 4016 4017 Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments); 4018 4019 for (i=0; i < nSegments; i++) { 4020 if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); 4021 } 4022 _cmsFree(self ->ContextID, Segments); 4023 return Curve; 4024 4025 Error: 4026 if (Segments) _cmsFree(self ->ContextID, Segments); 4027 return NULL; 4028 } 4029 4030 4031 static 4032 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self, 4033 cmsIOHANDLER* io, 4034 void* Cargo, 4035 cmsUInt32Number n, 4036 cmsUInt32Number SizeOfTag) 4037 { 4038 cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo; 4039 4040 GammaTables[n] = ReadSegmentedCurve(self, io); 4041 return (GammaTables[n] != NULL); 4042 4043 cmsUNUSED_PARAMETER(SizeOfTag); 4044 } 4045 4046 static 4047 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4048 { 4049 cmsStage* mpe = NULL; 4050 cmsUInt16Number InputChans, OutputChans; 4051 cmsUInt32Number i, BaseOffset; 4052 cmsToneCurve** GammaTables; 4053 4054 *nItems = 0; 4055 4056 // Get actual position as a basis for element offsets 4057 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4058 4059 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4060 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4061 4062 if (InputChans != OutputChans) return NULL; 4063 4064 GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*)); 4065 if (GammaTables == NULL) return NULL; 4066 4067 if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) { 4068 4069 mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables); 4070 } 4071 else { 4072 mpe = NULL; 4073 } 4074 4075 for (i=0; i < InputChans; i++) { 4076 if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]); 4077 } 4078 4079 _cmsFree(self ->ContextID, GammaTables); 4080 *nItems = (mpe != NULL) ? 1 : 0; 4081 return mpe; 4082 4083 cmsUNUSED_PARAMETER(SizeOfTag); 4084 } 4085 4086 4087 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY 4088 static 4089 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) 4090 { 4091 cmsUInt32Number i, j; 4092 cmsCurveSegment* Segments = g ->Segments; 4093 cmsUInt32Number nSegments = g ->nSegments; 4094 4095 if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error; 4096 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4097 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error; 4098 if (!_cmsWriteUInt16Number(io, 0)) goto Error; 4099 4100 // Write the break-points 4101 for (i=0; i < nSegments - 1; i++) { 4102 if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error; 4103 } 4104 4105 // Write the segments 4106 for (i=0; i < g ->nSegments; i++) { 4107 4108 cmsCurveSegment* ActualSeg = Segments + i; 4109 4110 if (ActualSeg -> Type == 0) { 4111 4112 // This is a sampled curve 4113 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error; 4114 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4115 if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error; 4116 4117 for (j=0; j < g ->Segments[i].nGridPoints; j++) { 4118 if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error; 4119 } 4120 4121 } 4122 else { 4123 int Type; 4124 cmsUInt32Number ParamsByType[] = { 4, 5, 5 }; 4125 4126 // This is a formula-based 4127 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error; 4128 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4129 4130 // We only allow 1, 2 and 3 as types 4131 Type = ActualSeg ->Type - 6; 4132 if (Type > 2 || Type < 0) goto Error; 4133 4134 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error; 4135 if (!_cmsWriteUInt16Number(io, 0)) goto Error; 4136 4137 for (j=0; j < ParamsByType[Type]; j++) { 4138 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error; 4139 } 4140 } 4141 4142 // It seems there is no need to align. Code is here, and for safety commented out 4143 // if (!_cmsWriteAlignment(io)) goto Error; 4144 } 4145 4146 return TRUE; 4147 4148 Error: 4149 return FALSE; 4150 } 4151 4152 4153 static 4154 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self, 4155 cmsIOHANDLER* io, 4156 void* Cargo, 4157 cmsUInt32Number n, 4158 cmsUInt32Number SizeOfTag) 4159 { 4160 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo; 4161 4162 return WriteSegmentedCurve(io, Curves ->TheCurves[n]); 4163 4164 cmsUNUSED_PARAMETER(SizeOfTag); 4165 cmsUNUSED_PARAMETER(self); 4166 } 4167 4168 // Write a curve, checking first for validity 4169 static 4170 cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4171 { 4172 cmsUInt32Number BaseOffset; 4173 cmsStage* mpe = (cmsStage*) Ptr; 4174 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data; 4175 4176 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4177 4178 // Write the header. Since those are curves, input and output channels are same 4179 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4180 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4181 4182 if (!WritePositionTable(self, io, 0, 4183 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE; 4184 4185 4186 return TRUE; 4187 4188 cmsUNUSED_PARAMETER(nItems); 4189 } 4190 4191 4192 4193 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the 4194 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array 4195 // is organized as follows: 4196 // array = [e11, e12, , e1P, e21, e22, , e2P, , eQ1, eQ2, , eQP, e1, e2, , eQ] 4197 4198 static 4199 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4200 { 4201 cmsStage* mpe; 4202 cmsUInt16Number InputChans, OutputChans; 4203 cmsUInt32Number nElems, i; 4204 cmsFloat64Number* Matrix; 4205 cmsFloat64Number* Offsets; 4206 4207 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4208 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4209 4210 4211 nElems = InputChans * OutputChans; 4212 4213 // Input and output chans may be ANY (up to 0xffff) 4214 Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number)); 4215 if (Matrix == NULL) return NULL; 4216 4217 Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number)); 4218 if (Offsets == NULL) { 4219 4220 _cmsFree(self ->ContextID, Matrix); 4221 return NULL; 4222 } 4223 4224 for (i=0; i < nElems; i++) { 4225 4226 cmsFloat32Number v; 4227 4228 if (!_cmsReadFloat32Number(io, &v)) return NULL; 4229 Matrix[i] = v; 4230 } 4231 4232 4233 for (i=0; i < OutputChans; i++) { 4234 4235 cmsFloat32Number v; 4236 4237 if (!_cmsReadFloat32Number(io, &v)) return NULL; 4238 Offsets[i] = v; 4239 } 4240 4241 4242 mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets); 4243 _cmsFree(self ->ContextID, Matrix); 4244 _cmsFree(self ->ContextID, Offsets); 4245 4246 *nItems = 1; 4247 4248 return mpe; 4249 4250 cmsUNUSED_PARAMETER(SizeOfTag); 4251 } 4252 4253 static 4254 cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4255 { 4256 cmsUInt32Number i, nElems; 4257 cmsStage* mpe = (cmsStage*) Ptr; 4258 _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data; 4259 4260 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4261 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; 4262 4263 nElems = mpe ->InputChannels * mpe ->OutputChannels; 4264 4265 for (i=0; i < nElems; i++) { 4266 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE; 4267 } 4268 4269 4270 for (i=0; i < mpe ->OutputChannels; i++) { 4271 4272 if (Matrix ->Offset == NULL) { 4273 4274 if (!_cmsWriteFloat32Number(io, 0)) return FALSE; 4275 } 4276 else { 4277 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE; 4278 } 4279 } 4280 4281 return TRUE; 4282 4283 cmsUNUSED_PARAMETER(nItems); 4284 cmsUNUSED_PARAMETER(self); 4285 } 4286 4287 4288 4289 static 4290 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4291 { 4292 cmsStage* mpe = NULL; 4293 cmsUInt16Number InputChans, OutputChans; 4294 cmsUInt8Number Dimensions8[16]; 4295 cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS]; 4296 _cmsStageCLutData* clut; 4297 4298 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4299 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4300 4301 if (InputChans == 0) goto Error; 4302 if (OutputChans == 0) goto Error; 4303 4304 if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) 4305 goto Error; 4306 4307 // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number 4308 nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans; 4309 for (i=0; i < nMaxGrids; i++) { 4310 if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least 4311 GridPoints[i] = (cmsUInt32Number)Dimensions8[i]; 4312 } 4313 4314 // Allocate the true CLUT 4315 mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); 4316 if (mpe == NULL) goto Error; 4317 4318 // Read the data 4319 clut = (_cmsStageCLutData*) mpe ->Data; 4320 for (i=0; i < clut ->nEntries; i++) { 4321 4322 if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error; 4323 } 4324 4325 *nItems = 1; 4326 return mpe; 4327 4328 Error: 4329 *nItems = 0; 4330 if (mpe != NULL) cmsStageFree(mpe); 4331 return NULL; 4332 4333 cmsUNUSED_PARAMETER(SizeOfTag); 4334 } 4335 4336 // Write a CLUT in floating point 4337 static 4338 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4339 { 4340 cmsUInt8Number Dimensions8[16]; 4341 cmsUInt32Number i; 4342 cmsStage* mpe = (cmsStage*) Ptr; 4343 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data; 4344 4345 // Check for maximum number of channels 4346 if (mpe -> InputChannels > 15) return FALSE; 4347 4348 // Only floats are supported in MPE 4349 if (clut ->HasFloatValues == FALSE) return FALSE; 4350 4351 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE; 4352 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE; 4353 4354 memset(Dimensions8, 0, sizeof(Dimensions8)); 4355 4356 for (i=0; i < mpe ->InputChannels; i++) 4357 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i]; 4358 4359 if (!io ->Write(io, 16, Dimensions8)) return FALSE; 4360 4361 for (i=0; i < clut ->nEntries; i++) { 4362 4363 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE; 4364 } 4365 4366 return TRUE; 4367 4368 cmsUNUSED_PARAMETER(nItems); 4369 cmsUNUSED_PARAMETER(self); 4370 } 4371 4372 4373 4374 // This is the list of built-in MPE types 4375 static _cmsTagTypeLinkedList SupportedMPEtypes[] = { 4376 4377 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now 4378 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says) 4379 4380 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] }, 4381 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] }, 4382 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL }, 4383 }; 4384 4385 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL }; 4386 4387 static 4388 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self, 4389 cmsIOHANDLER* io, 4390 void* Cargo, 4391 cmsUInt32Number n, 4392 cmsUInt32Number SizeOfTag) 4393 { 4394 cmsStageSignature ElementSig; 4395 cmsTagTypeHandler* TypeHandler; 4396 cmsUInt32Number nItems; 4397 cmsPipeline *NewLUT = (cmsPipeline *) Cargo; 4398 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); 4399 4400 4401 // Take signature and channels for each element. 4402 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE; 4403 4404 // The reserved placeholder 4405 if (!_cmsReadUInt32Number(io, NULL)) return FALSE; 4406 4407 // Read diverse MPE types 4408 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes); 4409 if (TypeHandler == NULL) { 4410 4411 char String[5]; 4412 4413 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); 4414 4415 // An unknown element was found. 4416 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String); 4417 return FALSE; 4418 } 4419 4420 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType) 4421 // Read the MPE. No size is given 4422 if (TypeHandler ->ReadPtr != NULL) { 4423 4424 // This is a real element which should be read and processed 4425 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag))) 4426 return FALSE; 4427 } 4428 4429 return TRUE; 4430 4431 cmsUNUSED_PARAMETER(SizeOfTag); 4432 cmsUNUSED_PARAMETER(n); 4433 } 4434 4435 4436 // This is the main dispatcher for MPE 4437 static 4438 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 4439 { 4440 cmsUInt16Number InputChans, OutputChans; 4441 cmsUInt32Number ElementCount; 4442 cmsPipeline *NewLUT = NULL; 4443 cmsUInt32Number BaseOffset; 4444 4445 // Get actual position as a basis for element offsets 4446 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4447 4448 // Read channels and element count 4449 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; 4450 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; 4451 4452 // Allocates an empty LUT 4453 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans); 4454 if (NewLUT == NULL) return NULL; 4455 4456 if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error; 4457 if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error; 4458 4459 // Success 4460 *nItems = 1; 4461 return NewLUT; 4462 4463 // Error 4464 Error: 4465 if (NewLUT != NULL) cmsPipelineFree(NewLUT); 4466 *nItems = 0; 4467 return NULL; 4468 4469 cmsUNUSED_PARAMETER(SizeOfTag); 4470 } 4471 4472 4473 4474 // This one is a liitle bit more complex, so we don't use position tables this time. 4475 static 4476 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4477 { 4478 cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos; 4479 int inputChan, outputChan; 4480 cmsUInt32Number ElemCount; 4481 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before; 4482 cmsStageSignature ElementSig; 4483 cmsPipeline* Lut = (cmsPipeline*) Ptr; 4484 cmsStage* Elem = Lut ->Elements; 4485 cmsTagTypeHandler* TypeHandler; 4486 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin); 4487 4488 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 4489 4490 inputChan = cmsPipelineInputChannels(Lut); 4491 outputChan = cmsPipelineOutputChannels(Lut); 4492 ElemCount = cmsPipelineStageCount(Lut); 4493 4494 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); 4495 if (ElementOffsets == NULL) goto Error; 4496 4497 ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); 4498 if (ElementSizes == NULL) goto Error; 4499 4500 // Write the head 4501 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error; 4502 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error; 4503 if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error; 4504 4505 DirectoryPos = io ->Tell(io); 4506 4507 // Write a fake directory to be filled latter on 4508 for (i=0; i < ElemCount; i++) { 4509 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset 4510 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size 4511 } 4512 4513 // Write each single tag. Keep track of the size as well. 4514 for (i=0; i < ElemCount; i++) { 4515 4516 ElementOffsets[i] = io ->Tell(io) - BaseOffset; 4517 4518 ElementSig = Elem ->Type; 4519 4520 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes); 4521 if (TypeHandler == NULL) { 4522 4523 char String[5]; 4524 4525 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig); 4526 4527 // An unknow element was found. 4528 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String); 4529 goto Error; 4530 } 4531 4532 if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error; 4533 if (!_cmsWriteUInt32Number(io, 0)) goto Error; 4534 Before = io ->Tell(io); 4535 if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error; 4536 if (!_cmsWriteAlignment(io)) goto Error; 4537 4538 ElementSizes[i] = io ->Tell(io) - Before; 4539 4540 Elem = Elem ->Next; 4541 } 4542 4543 // Write the directory 4544 CurrentPos = io ->Tell(io); 4545 4546 if (!io ->Seek(io, DirectoryPos)) goto Error; 4547 4548 for (i=0; i < ElemCount; i++) { 4549 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error; 4550 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error; 4551 } 4552 4553 if (!io ->Seek(io, CurrentPos)) goto Error; 4554 4555 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); 4556 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); 4557 return TRUE; 4558 4559 Error: 4560 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets); 4561 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes); 4562 return FALSE; 4563 4564 cmsUNUSED_PARAMETER(nItems); 4565 } 4566 4567 4568 static 4569 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 4570 { 4571 return (void*) cmsPipelineDup((cmsPipeline*) Ptr); 4572 4573 cmsUNUSED_PARAMETER(n); 4574 cmsUNUSED_PARAMETER(self); 4575 } 4576 4577 static 4578 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr) 4579 { 4580 cmsPipelineFree((cmsPipeline*) Ptr); 4581 return; 4582 4583 cmsUNUSED_PARAMETER(self); 4584 } 4585 4586 4587 // ******************************************************************************** 4588 // Type cmsSigVcgtType 4589 // ******************************************************************************** 4590 4591 4592 #define cmsVideoCardGammaTableType 0 4593 #define cmsVideoCardGammaFormulaType 1 4594 4595 // Used internally 4596 typedef struct { 4597 double Gamma; 4598 double Min; 4599 double Max; 4600 } _cmsVCGTGAMMA; 4601 4602 4603 static 4604 void *Type_vcgt_Read(struct _cms_typehandler_struct* self, 4605 cmsIOHANDLER* io, 4606 cmsUInt32Number* nItems, 4607 cmsUInt32Number SizeOfTag) 4608 { 4609 cmsUInt32Number TagType, n, i; 4610 cmsToneCurve** Curves; 4611 4612 *nItems = 0; 4613 4614 // Read tag type 4615 if (!_cmsReadUInt32Number(io, &TagType)) return NULL; 4616 4617 // Allocate space for the array 4618 Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); 4619 if (Curves == NULL) return NULL; 4620 4621 // There are two possible flavors 4622 switch (TagType) { 4623 4624 // Gamma is stored as a table 4625 case cmsVideoCardGammaTableType: 4626 { 4627 cmsUInt16Number nChannels, nElems, nBytes; 4628 4629 // Check channel count, which should be 3 (we don't support monochrome this time) 4630 if (!_cmsReadUInt16Number(io, &nChannels)) goto Error; 4631 4632 if (nChannels != 3) { 4633 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels); 4634 goto Error; 4635 } 4636 4637 // Get Table element count and bytes per element 4638 if (!_cmsReadUInt16Number(io, &nElems)) goto Error; 4639 if (!_cmsReadUInt16Number(io, &nBytes)) goto Error; 4640 4641 // Adobe's quirk fixup. Fixing broken profiles... 4642 if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576) 4643 nBytes = 2; 4644 4645 4646 // Populate tone curves 4647 for (n=0; n < 3; n++) { 4648 4649 Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL); 4650 if (Curves[n] == NULL) goto Error; 4651 4652 // On depending on byte depth 4653 switch (nBytes) { 4654 4655 // One byte, 0..255 4656 case 1: 4657 for (i=0; i < nElems; i++) { 4658 4659 cmsUInt8Number v; 4660 4661 if (!_cmsReadUInt8Number(io, &v)) goto Error; 4662 Curves[n] ->Table16[i] = FROM_8_TO_16(v); 4663 } 4664 break; 4665 4666 // One word 0..65535 4667 case 2: 4668 if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error; 4669 break; 4670 4671 // Unsupported 4672 default: 4673 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8); 4674 goto Error; 4675 } 4676 } // For all 3 channels 4677 } 4678 break; 4679 4680 // In this case, gamma is stored as a formula 4681 case cmsVideoCardGammaFormulaType: 4682 { 4683 _cmsVCGTGAMMA Colorant[3]; 4684 4685 // Populate tone curves 4686 for (n=0; n < 3; n++) { 4687 4688 double Params[10]; 4689 4690 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error; 4691 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error; 4692 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error; 4693 4694 // Parametric curve type 5 is: 4695 // Y = (aX + b)^Gamma + e | X >= d 4696 // Y = cX + f | X < d 4697 4698 // vcgt formula is: 4699 // Y = (Max Min) * (X ^ Gamma) + Min 4700 4701 // So, the translation is 4702 // a = (Max Min) ^ ( 1 / Gamma) 4703 // e = Min 4704 // b=c=d=f=0 4705 4706 Params[0] = Colorant[n].Gamma; 4707 Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma)); 4708 Params[2] = 0; 4709 Params[3] = 0; 4710 Params[4] = 0; 4711 Params[5] = Colorant[n].Min; 4712 Params[6] = 0; 4713 4714 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params); 4715 if (Curves[n] == NULL) goto Error; 4716 } 4717 } 4718 break; 4719 4720 // Unsupported 4721 default: 4722 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType); 4723 goto Error; 4724 } 4725 4726 *nItems = 1; 4727 return (void*) Curves; 4728 4729 // Regret, free all resources 4730 Error: 4731 4732 cmsFreeToneCurveTriple(Curves); 4733 _cmsFree(self ->ContextID, Curves); 4734 return NULL; 4735 4736 cmsUNUSED_PARAMETER(SizeOfTag); 4737 } 4738 4739 4740 // We don't support all flavors, only 16bits tables and formula 4741 static 4742 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 4743 { 4744 cmsToneCurve** Curves = (cmsToneCurve**) Ptr; 4745 cmsUInt32Number i, j; 4746 4747 if (cmsGetToneCurveParametricType(Curves[0]) == 5 && 4748 cmsGetToneCurveParametricType(Curves[1]) == 5 && 4749 cmsGetToneCurveParametricType(Curves[2]) == 5) { 4750 4751 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; 4752 4753 // Save parameters 4754 for (i=0; i < 3; i++) { 4755 4756 _cmsVCGTGAMMA v; 4757 4758 v.Gamma = Curves[i] ->Segments[0].Params[0]; 4759 v.Min = Curves[i] ->Segments[0].Params[5]; 4760 v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min; 4761 4762 if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE; 4763 if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE; 4764 if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE; 4765 } 4766 } 4767 4768 else { 4769 4770 // Always store as a table of 256 words 4771 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE; 4772 if (!_cmsWriteUInt16Number(io, 3)) return FALSE; 4773 if (!_cmsWriteUInt16Number(io, 256)) return FALSE; 4774 if (!_cmsWriteUInt16Number(io, 2)) return FALSE; 4775 4776 for (i=0; i < 3; i++) { 4777 for (j=0; j < 256; j++) { 4778 4779 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0)); 4780 cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0); 4781 4782 if (!_cmsWriteUInt16Number(io, n)) return FALSE; 4783 } 4784 } 4785 } 4786 4787 return TRUE; 4788 4789 cmsUNUSED_PARAMETER(self); 4790 cmsUNUSED_PARAMETER(nItems); 4791 } 4792 4793 static 4794 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 4795 { 4796 cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr; 4797 cmsToneCurve** NewCurves; 4798 4799 NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*)); 4800 if (NewCurves == NULL) return NULL; 4801 4802 NewCurves[0] = cmsDupToneCurve(OldCurves[0]); 4803 NewCurves[1] = cmsDupToneCurve(OldCurves[1]); 4804 NewCurves[2] = cmsDupToneCurve(OldCurves[2]); 4805 4806 return (void*) NewCurves; 4807 4808 cmsUNUSED_PARAMETER(n); 4809 } 4810 4811 4812 static 4813 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr) 4814 { 4815 cmsFreeToneCurveTriple((cmsToneCurve**) Ptr); 4816 _cmsFree(self ->ContextID, Ptr); 4817 } 4818 4819 4820 // ******************************************************************************** 4821 // Type cmsSigDictType 4822 // ******************************************************************************** 4823 4824 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data 4825 typedef struct { 4826 cmsContext ContextID; 4827 cmsUInt32Number *Offsets; 4828 cmsUInt32Number *Sizes; 4829 } _cmsDICelem; 4830 4831 typedef struct { 4832 _cmsDICelem Name, Value, DisplayName, DisplayValue; 4833 4834 } _cmsDICarray; 4835 4836 // Allocate an empty array element 4837 static 4838 cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count) 4839 { 4840 e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); 4841 if (e->Offsets == NULL) return FALSE; 4842 4843 e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); 4844 if (e->Sizes == NULL) { 4845 4846 _cmsFree(ContextID, e -> Offsets); 4847 return FALSE; 4848 } 4849 4850 e ->ContextID = ContextID; 4851 return TRUE; 4852 } 4853 4854 // Free an array element 4855 static 4856 void FreeElem(_cmsDICelem* e) 4857 { 4858 if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets); 4859 if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes); 4860 e->Offsets = e ->Sizes = NULL; 4861 } 4862 4863 // Get rid of whole array 4864 static 4865 void FreeArray( _cmsDICarray* a) 4866 { 4867 if (a ->Name.Offsets != NULL) FreeElem(&a->Name); 4868 if (a ->Value.Offsets != NULL) FreeElem(&a ->Value); 4869 if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName); 4870 if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue); 4871 } 4872 4873 4874 // Allocate whole array 4875 static 4876 cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) 4877 { 4878 // Empty values 4879 memset(a, 0, sizeof(_cmsDICarray)); 4880 4881 // On depending on record size, create column arrays 4882 if (!AllocElem(ContextID, &a ->Name, Count)) goto Error; 4883 if (!AllocElem(ContextID, &a ->Value, Count)) goto Error; 4884 4885 if (Length > 16) { 4886 if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error; 4887 4888 } 4889 if (Length > 24) { 4890 if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error; 4891 } 4892 return TRUE; 4893 4894 Error: 4895 FreeArray(a); 4896 return FALSE; 4897 } 4898 4899 // Read one element 4900 static 4901 cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset) 4902 { 4903 if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE; 4904 if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE; 4905 4906 // An offset of zero has special meaning and shal be preserved 4907 if (e ->Offsets[i] > 0) 4908 e ->Offsets[i] += BaseOffset; 4909 return TRUE; 4910 } 4911 4912 4913 static 4914 cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset) 4915 { 4916 cmsUInt32Number i; 4917 4918 // Read column arrays 4919 for (i=0; i < Count; i++) { 4920 4921 if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE; 4922 if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE; 4923 4924 if (Length > 16) { 4925 4926 if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE; 4927 4928 } 4929 4930 if (Length > 24) { 4931 4932 if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE; 4933 } 4934 } 4935 return TRUE; 4936 } 4937 4938 4939 // Write one element 4940 static 4941 cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i) 4942 { 4943 if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE; 4944 if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE; 4945 4946 return TRUE; 4947 } 4948 4949 static 4950 cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length) 4951 { 4952 cmsUInt32Number i; 4953 4954 for (i=0; i < Count; i++) { 4955 4956 if (!WriteOneElem(io, &a -> Name, i)) return FALSE; 4957 if (!WriteOneElem(io, &a -> Value, i)) return FALSE; 4958 4959 if (Length > 16) { 4960 4961 if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE; 4962 } 4963 4964 if (Length > 24) { 4965 4966 if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE; 4967 } 4968 } 4969 4970 return TRUE; 4971 } 4972 4973 static 4974 cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr) 4975 { 4976 4977 cmsUInt32Number nChars; 4978 4979 // Special case for undefined strings (see ICC Votable 4980 // Proposal Submission, Dictionary Type and Metadata TAG Definition) 4981 if (e -> Offsets[i] == 0) { 4982 4983 *wcstr = NULL; 4984 return TRUE; 4985 } 4986 4987 if (!io -> Seek(io, e -> Offsets[i])) return FALSE; 4988 4989 nChars = e ->Sizes[i] / sizeof(cmsUInt16Number); 4990 4991 4992 *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t)); 4993 if (*wcstr == NULL) return FALSE; 4994 4995 if (!_cmsReadWCharArray(io, nChars, *wcstr)) { 4996 _cmsFree(e ->ContextID, *wcstr); 4997 return FALSE; 4998 } 4999 5000 // End of string marker 5001 (*wcstr)[nChars] = 0; 5002 return TRUE; 5003 } 5004 5005 static 5006 cmsUInt32Number mywcslen(const wchar_t *s) 5007 { 5008 const wchar_t *p; 5009 5010 p = s; 5011 while (*p) 5012 p++; 5013 5014 return (cmsUInt32Number)(p - s); 5015 } 5016 5017 static 5018 cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset) 5019 { 5020 cmsUInt32Number Before = io ->Tell(io); 5021 cmsUInt32Number n; 5022 5023 e ->Offsets[i] = Before - BaseOffset; 5024 5025 if (wcstr == NULL) { 5026 e ->Sizes[i] = 0; 5027 e ->Offsets[i] = 0; 5028 return TRUE; 5029 } 5030 5031 n = mywcslen(wcstr); 5032 if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE; 5033 5034 e ->Sizes[i] = io ->Tell(io) - Before; 5035 return TRUE; 5036 } 5037 5038 static 5039 cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu) 5040 { 5041 cmsUInt32Number nItems = 0; 5042 5043 // A way to get null MLUCs 5044 if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) { 5045 5046 *mlu = NULL; 5047 return TRUE; 5048 } 5049 5050 if (!io -> Seek(io, e -> Offsets[i])) return FALSE; 5051 5052 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]); 5053 return *mlu != NULL; 5054 } 5055 5056 static 5057 cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset) 5058 { 5059 cmsUInt32Number Before; 5060 5061 // Special case for undefined strings (see ICC Votable 5062 // Proposal Submission, Dictionary Type and Metadata TAG Definition) 5063 if (mlu == NULL) { 5064 e ->Sizes[i] = 0; 5065 e ->Offsets[i] = 0; 5066 return TRUE; 5067 } 5068 5069 Before = io ->Tell(io); 5070 e ->Offsets[i] = Before - BaseOffset; 5071 5072 if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE; 5073 5074 e ->Sizes[i] = io ->Tell(io) - Before; 5075 return TRUE; 5076 } 5077 5078 5079 static 5080 void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) 5081 { 5082 cmsHANDLE hDict; 5083 cmsUInt32Number i, Count, Length; 5084 cmsUInt32Number BaseOffset; 5085 _cmsDICarray a; 5086 wchar_t *NameWCS = NULL, *ValueWCS = NULL; 5087 cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL; 5088 cmsBool rc; 5089 5090 *nItems = 0; 5091 5092 // Get actual position as a basis for element offsets 5093 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 5094 5095 // Get name-value record count 5096 if (!_cmsReadUInt32Number(io, &Count)) return NULL; 5097 SizeOfTag -= sizeof(cmsUInt32Number); 5098 5099 // Get rec length 5100 if (!_cmsReadUInt32Number(io, &Length)) return NULL; 5101 SizeOfTag -= sizeof(cmsUInt32Number); 5102 5103 // Check for valid lengths 5104 if (Length != 16 && Length != 24 && Length != 32) { 5105 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length); 5106 return NULL; 5107 } 5108 5109 // Creates an empty dictionary 5110 hDict = cmsDictAlloc(self -> ContextID); 5111 if (hDict == NULL) return NULL; 5112 5113 // On depending on record size, create column arrays 5114 if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error; 5115 5116 // Read column arrays 5117 if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error; 5118 5119 // Seek to each element and read it 5120 for (i=0; i < Count; i++) { 5121 5122 if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error; 5123 if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error; 5124 5125 if (Length > 16) { 5126 if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error; 5127 } 5128 5129 if (Length > 24) { 5130 if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error; 5131 } 5132 5133 if (NameWCS == NULL || ValueWCS == NULL) { 5134 5135 cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value"); 5136 rc = FALSE; 5137 } 5138 else { 5139 5140 rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); 5141 } 5142 5143 if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); 5144 if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS); 5145 if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU); 5146 if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU); 5147 5148 if (!rc) goto Error; 5149 } 5150 5151 FreeArray(&a); 5152 *nItems = 1; 5153 return (void*) hDict; 5154 5155 Error: 5156 FreeArray(&a); 5157 cmsDictFree(hDict); 5158 return NULL; 5159 } 5160 5161 5162 static 5163 cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) 5164 { 5165 cmsHANDLE hDict = (cmsHANDLE) Ptr; 5166 const cmsDICTentry* p; 5167 cmsBool AnyName, AnyValue; 5168 cmsUInt32Number i, Count, Length; 5169 cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset; 5170 _cmsDICarray a; 5171 5172 if (hDict == NULL) return FALSE; 5173 5174 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); 5175 5176 // Let's inspect the dictionary 5177 Count = 0; AnyName = FALSE; AnyValue = FALSE; 5178 for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) { 5179 5180 if (p ->DisplayName != NULL) AnyName = TRUE; 5181 if (p ->DisplayValue != NULL) AnyValue = TRUE; 5182 Count++; 5183 } 5184 5185 Length = 16; 5186 if (AnyName) Length += 8; 5187 if (AnyValue) Length += 8; 5188 5189 if (!_cmsWriteUInt32Number(io, Count)) return FALSE; 5190 if (!_cmsWriteUInt32Number(io, Length)) return FALSE; 5191 5192 // Keep starting position of offsets table 5193 DirectoryPos = io ->Tell(io); 5194 5195 // Allocate offsets array 5196 if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error; 5197 5198 // Write a fake directory to be filled latter on 5199 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; 5200 5201 // Write each element. Keep track of the size as well. 5202 p = cmsDictGetEntryList(hDict); 5203 for (i=0; i < Count; i++) { 5204 5205 if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error; 5206 if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error; 5207 5208 if (p ->DisplayName != NULL) { 5209 if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error; 5210 } 5211 5212 if (p ->DisplayValue != NULL) { 5213 if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error; 5214 } 5215 5216 p = cmsDictNextEntry(p); 5217 } 5218 5219 // Write the directory 5220 CurrentPos = io ->Tell(io); 5221 if (!io ->Seek(io, DirectoryPos)) goto Error; 5222 5223 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error; 5224 5225 if (!io ->Seek(io, CurrentPos)) goto Error; 5226 5227 FreeArray(&a); 5228 return TRUE; 5229 5230 Error: 5231 FreeArray(&a); 5232 return FALSE; 5233 5234 cmsUNUSED_PARAMETER(nItems); 5235 } 5236 5237 5238 static 5239 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) 5240 { 5241 return (void*) cmsDictDup((cmsHANDLE) Ptr); 5242 5243 cmsUNUSED_PARAMETER(n); 5244 cmsUNUSED_PARAMETER(self); 5245 } 5246 5247 5248 static 5249 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr) 5250 { 5251 cmsDictFree((cmsHANDLE) Ptr); 5252 cmsUNUSED_PARAMETER(self); 5253 } 5254 5255 5256 // ******************************************************************************** 5257 // Type support main routines 5258 // ******************************************************************************** 5259 5260 5261 // This is the list of built-in types 5262 static _cmsTagTypeLinkedList SupportedTagTypes[] = { 5263 5264 {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] }, 5265 {TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] }, 5266 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] }, 5267 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] }, 5268 {TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] }, 5269 {TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] }, 5270 {TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] }, 5271 {TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] }, 5272 {TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] }, 5273 {TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] }, 5274 {TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] }, 5275 {TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] }, 5276 {TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] }, 5277 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] }, 5278 {TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] }, 5279 {TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] }, 5280 {TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] }, 5281 {TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] }, 5282 {TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] }, 5283 {TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] }, 5284 {TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] }, 5285 {TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] }, 5286 {TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] }, 5287 {TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] }, 5288 {TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] }, 5289 {TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] }, 5290 {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] }, 5291 {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] }, 5292 {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] }, 5293 {TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] }, 5294 {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } 5295 }; 5296 5297 5298 _cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL }; 5299 5300 5301 5302 // Duplicates the zone of memory used by the plug-in in the new context 5303 static 5304 void DupTagTypeList(struct _cmsContext_struct* ctx, 5305 const struct _cmsContext_struct* src, 5306 int loc) 5307 { 5308 _cmsTagTypePluginChunkType newHead = { NULL }; 5309 _cmsTagTypeLinkedList* entry; 5310 _cmsTagTypeLinkedList* Anterior = NULL; 5311 _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc]; 5312 5313 // Walk the list copying all nodes 5314 for (entry = head->TagTypes; 5315 entry != NULL; 5316 entry = entry ->Next) { 5317 5318 _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList)); 5319 5320 if (newEntry == NULL) 5321 return; 5322 5323 // We want to keep the linked list order, so this is a little bit tricky 5324 newEntry -> Next = NULL; 5325 if (Anterior) 5326 Anterior -> Next = newEntry; 5327 5328 Anterior = newEntry; 5329 5330 if (newHead.TagTypes == NULL) 5331 newHead.TagTypes = newEntry; 5332 } 5333 5334 ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType)); 5335 } 5336 5337 5338 void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx, 5339 const struct _cmsContext_struct* src) 5340 { 5341 if (src != NULL) { 5342 5343 // Duplicate the LIST 5344 DupTagTypeList(ctx, src, TagTypePlugin); 5345 } 5346 else { 5347 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; 5348 ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); 5349 } 5350 } 5351 5352 void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx, 5353 const struct _cmsContext_struct* src) 5354 { 5355 if (src != NULL) { 5356 5357 // Duplicate the LIST 5358 DupTagTypeList(ctx, src, MPEPlugin); 5359 } 5360 else { 5361 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL }; 5362 ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType)); 5363 } 5364 5365 } 5366 5367 5368 // Both kind of plug-ins share same structure 5369 cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) 5370 { 5371 return RegisterTypesPlugin(id, Data, TagTypePlugin); 5372 } 5373 5374 cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) 5375 { 5376 return RegisterTypesPlugin(id, Data,MPEPlugin); 5377 } 5378 5379 5380 // Wrapper for tag types 5381 cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig) 5382 { 5383 _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin); 5384 5385 return GetHandler(sig, ctx->TagTypes, SupportedTagTypes); 5386 } 5387 5388 // ******************************************************************************** 5389 // Tag support main routines 5390 // ******************************************************************************** 5391 5392 typedef struct _cmsTagLinkedList_st { 5393 5394 cmsTagSignature Signature; 5395 cmsTagDescriptor Descriptor; 5396 struct _cmsTagLinkedList_st* Next; 5397 5398 } _cmsTagLinkedList; 5399 5400 // This is the list of built-in tags 5401 static _cmsTagLinkedList SupportedTags[] = { 5402 5403 { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]}, 5404 { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]}, 5405 { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]}, 5406 { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]}, 5407 { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]}, 5408 { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]}, 5409 5410 // Allow corbis and its broken XYZ type 5411 { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]}, 5412 { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]}, 5413 { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]}, 5414 5415 { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]}, 5416 { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]}, 5417 { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]}, 5418 5419 { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]}, 5420 { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]}, 5421 5422 { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]}, 5423 { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]}, 5424 { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]}, 5425 { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]}, 5426 { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]}, 5427 5428 { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]}, 5429 { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]}, 5430 5431 { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]}, 5432 { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]}, 5433 5434 { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]}, 5435 5436 { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]}, 5437 { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]}, 5438 5439 { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]}, 5440 { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]}, 5441 5442 { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]}, 5443 5444 { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]}, 5445 { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]}, 5446 { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]}, 5447 5448 { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]}, 5449 { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]}, 5450 { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]}, 5451 5452 { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]}, 5453 { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]}, 5454 { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]}, 5455 5456 { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]}, 5457 5458 { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]}, 5459 { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]}, 5460 { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]}, 5461 { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]}, 5462 { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]}, 5463 { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]}, 5464 5465 { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]}, 5466 5467 { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]}, 5468 { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]}, 5469 5470 { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]}, 5471 { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]}, 5472 { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]}, 5473 { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]}, 5474 { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]}, 5475 { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]}, 5476 { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]}, 5477 { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]}, 5478 5479 { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]}, 5480 { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]}, 5481 5482 { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, 5483 { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, 5484 { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]}, 5485 { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, 5486 { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL} 5487 5488 5489 }; 5490 5491 /* 5492 Not supported Why 5493 ======================= ========================================= 5494 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT! 5495 cmsSigNamedColorTag ==> Deprecated 5496 cmsSigDataTag ==> Ancient, unused 5497 cmsSigDeviceSettingsTag ==> Deprecated, useless 5498 */ 5499 5500 5501 _cmsTagPluginChunkType _cmsTagPluginChunk = { NULL }; 5502 5503 5504 // Duplicates the zone of memory used by the plug-in in the new context 5505 static 5506 void DupTagList(struct _cmsContext_struct* ctx, 5507 const struct _cmsContext_struct* src) 5508 { 5509 _cmsTagPluginChunkType newHead = { NULL }; 5510 _cmsTagLinkedList* entry; 5511 _cmsTagLinkedList* Anterior = NULL; 5512 _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin]; 5513 5514 // Walk the list copying all nodes 5515 for (entry = head->Tag; 5516 entry != NULL; 5517 entry = entry ->Next) { 5518 5519 _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList)); 5520 5521 if (newEntry == NULL) 5522 return; 5523 5524 // We want to keep the linked list order, so this is a little bit tricky 5525 newEntry -> Next = NULL; 5526 if (Anterior) 5527 Anterior -> Next = newEntry; 5528 5529 Anterior = newEntry; 5530 5531 if (newHead.Tag == NULL) 5532 newHead.Tag = newEntry; 5533 } 5534 5535 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType)); 5536 } 5537 5538 void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx, 5539 const struct _cmsContext_struct* src) 5540 { 5541 if (src != NULL) { 5542 5543 DupTagList(ctx, src); 5544 } 5545 else { 5546 static _cmsTagPluginChunkType TagPluginChunk = { NULL }; 5547 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType)); 5548 } 5549 5550 } 5551 5552 cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) 5553 { 5554 cmsPluginTag* Plugin = (cmsPluginTag*) Data; 5555 _cmsTagLinkedList *pt; 5556 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin); 5557 5558 if (Data == NULL) { 5559 5560 TagPluginChunk->Tag = NULL; 5561 return TRUE; 5562 } 5563 5564 pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); 5565 if (pt == NULL) return FALSE; 5566 5567 pt ->Signature = Plugin ->Signature; 5568 pt ->Descriptor = Plugin ->Descriptor; 5569 pt ->Next = TagPluginChunk ->Tag; 5570 5571 TagPluginChunk ->Tag = pt; 5572 5573 return TRUE; 5574 } 5575 5576 // Return a descriptor for a given tag or NULL 5577 cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig) 5578 { 5579 _cmsTagLinkedList* pt; 5580 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin); 5581 5582 for (pt = TagPluginChunk->Tag; 5583 pt != NULL; 5584 pt = pt ->Next) { 5585 5586 if (sig == pt -> Signature) return &pt ->Descriptor; 5587 } 5588 5589 for (pt = SupportedTags; 5590 pt != NULL; 5591 pt = pt ->Next) { 5592 5593 if (sig == pt -> Signature) return &pt ->Descriptor; 5594 } 5595 5596 return NULL; 5597 } 5598