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