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