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