dmime: Implement band track IDirectMusicTrack_Play.
[wine.git] / libs / lcms2 / src / cmstypes.c
blob68bdd4becc8aaa686b67f4bf95fed0e11e8141e3
1 //---------------------------------------------------------------------------------
2 //
3 // Little Color Management System
4 // Copyright (c) 1998-2023 Marti Maria Saguer
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
29 // Tag Serialization -----------------------------------------------------------------------------
30 // This file implements every single tag and tag type as described in the ICC spec. Some types
31 // have been deprecated, like ncl and Data. There is no implementation for those types as there
32 // are no profiles holding them. The programmer can also extend this list by defining his own types
33 // by using the appropriate plug-in. There are three types of plug ins regarding that. First type
34 // allows to define new tags using any existing type. Next plug-in type allows to define new types
35 // and the third one is very specific: allows to extend the number of elements in the multiprocessing
36 // elements special type.
37 //--------------------------------------------------------------------------------------------------
39 // Some broken types
40 #define cmsCorbisBrokenXYZtype ((cmsTagTypeSignature) 0x17A505B8)
41 #define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00)
43 // This is the linked list that keeps track of the defined types
44 typedef struct _cmsTagTypeLinkedList_st {
46 cmsTagTypeHandler Handler;
47 struct _cmsTagTypeLinkedList_st* Next;
49 } _cmsTagTypeLinkedList;
51 // Some macros to define callbacks.
52 #define READ_FN(x) Type_##x##_Read
53 #define WRITE_FN(x) Type_##x##_Write
54 #define FREE_FN(x) Type_##x##_Free
55 #define DUP_FN(x) Type_##x##_Dup
57 // Helper macro to define a handler. Callbacks do have a fixed naming convention.
58 #define TYPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), DUP_FN(x), FREE_FN(x), NULL, 0 }
60 // Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
61 #define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
63 // Infinites
64 #define MINUS_INF (-1E22F)
65 #define PLUS_INF (+1E22F)
68 // Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head
69 static
70 cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos)
72 cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
73 _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos);
74 _cmsTagTypeLinkedList *pt;
76 // Calling the function with NULL as plug-in would unregister the plug in.
77 if (Data == NULL) {
79 // There is no need to set free the memory, as pool is destroyed as a whole.
80 ctx ->TagTypes = NULL;
81 return TRUE;
84 // Registering happens in plug-in memory pool.
85 pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
86 if (pt == NULL) return FALSE;
88 pt ->Handler = Plugin ->Handler;
89 pt ->Next = ctx ->TagTypes;
91 ctx ->TagTypes = pt;
93 return TRUE;
96 // Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons
97 // made by plug-ins and then the built-in defaults.
98 static
99 cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList)
101 _cmsTagTypeLinkedList* pt;
103 for (pt = PluginLinkedList;
104 pt != NULL;
105 pt = pt ->Next) {
107 if (sig == pt -> Handler.Signature) return &pt ->Handler;
110 for (pt = DefaultLinkedList;
111 pt != NULL;
112 pt = pt ->Next) {
114 if (sig == pt -> Handler.Signature) return &pt ->Handler;
117 return NULL;
121 // Auxiliary to convert UTF-32 to UTF-16 in some cases
122 static
123 cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
125 cmsUInt32Number i;
127 _cmsAssert(io != NULL);
128 _cmsAssert(!(Array == NULL && n > 0));
130 for (i=0; i < n; i++) {
131 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
134 return TRUE;
137 // Try to promote correctly to wchar_t when 32 bits
138 cmsINLINE cmsBool is_surrogate(cmsUInt32Number uc) { return (uc - 0xd800u) < 2048u; }
139 cmsINLINE cmsBool is_high_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xd800; }
140 cmsINLINE cmsBool is_low_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xdc00; }
142 cmsINLINE cmsUInt32Number surrogate_to_utf32(cmsUInt32Number high, cmsUInt32Number low)
144 return (high << 10) + low - 0x35fdc00;
147 cmsINLINE cmsBool convert_utf16_to_utf32(cmsIOHANDLER* io, cmsInt32Number n, wchar_t* output)
149 cmsUInt16Number uc;
151 while (n > 0)
153 if (!_cmsReadUInt16Number(io, &uc)) return FALSE;
154 n--;
156 if (!is_surrogate(uc))
158 *output++ = (wchar_t)uc;
160 else {
162 cmsUInt16Number low;
164 if (!_cmsReadUInt16Number(io, &low)) return FALSE;
165 n--;
167 if (is_high_surrogate(uc) && is_low_surrogate(low))
168 *output++ = (wchar_t)surrogate_to_utf32(uc, low);
169 else
170 return FALSE; // Corrupted string, just ignore
174 return TRUE;
178 // Auxiliary to read an array of wchar_t
179 static
180 cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
182 cmsUInt32Number i;
183 cmsUInt16Number tmp;
184 cmsBool is32 = sizeof(wchar_t) > sizeof(cmsUInt16Number);
186 _cmsAssert(io != NULL);
188 if (is32 && Array != NULL)
190 return convert_utf16_to_utf32(io, n, Array);
193 for (i=0; i < n; i++) {
195 if (Array != NULL) {
197 if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
198 Array[i] = (wchar_t) tmp;
200 else {
201 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
205 return TRUE;
208 // To deal with position tables
209 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
210 cmsIOHANDLER* io,
211 void* Cargo,
212 cmsUInt32Number n,
213 cmsUInt32Number SizeOfTag);
215 // Helper function to deal with position tables as described in ICC spec 4.3
216 // A table of n elements is read, where first comes n records containing offsets and sizes and
217 // then a block containing the data itself. This allows to reuse same data in more than one entry
218 static
219 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
220 cmsIOHANDLER* io,
221 cmsUInt32Number Count,
222 cmsUInt32Number BaseOffset,
223 void *Cargo,
224 PositionTableEntryFn ElementFn)
226 cmsUInt32Number i;
227 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
228 cmsUInt32Number currentPosition;
230 currentPosition = io->Tell(io);
232 // Verify there is enough space left to read at least two cmsUInt32Number items for Count items.
233 if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count)
234 return FALSE;
236 // Let's take the offsets to each element
237 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
238 if (ElementOffsets == NULL) goto Error;
240 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
241 if (ElementSizes == NULL) goto Error;
243 for (i=0; i < Count; i++) {
245 if (!_cmsReadUInt32Number(io, &ElementOffsets[i])) goto Error;
246 if (!_cmsReadUInt32Number(io, &ElementSizes[i])) goto Error;
248 ElementOffsets[i] += BaseOffset;
251 // Seek to each element and read it
252 for (i=0; i < Count; i++) {
254 if (!io -> Seek(io, ElementOffsets[i])) goto Error;
256 // This is the reader callback
257 if (!ElementFn(self, io, Cargo, i, ElementSizes[i])) goto Error;
260 // Success
261 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
262 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
263 return TRUE;
265 Error:
266 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
267 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
268 return FALSE;
271 // Same as anterior, but for write position tables
272 static
273 cmsBool WritePositionTable(struct _cms_typehandler_struct* self,
274 cmsIOHANDLER* io,
275 cmsUInt32Number SizeOfTag,
276 cmsUInt32Number Count,
277 cmsUInt32Number BaseOffset,
278 void *Cargo,
279 PositionTableEntryFn ElementFn)
281 cmsUInt32Number i;
282 cmsUInt32Number DirectoryPos, CurrentPos, Before;
283 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
285 // Create table
286 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
287 if (ElementOffsets == NULL) goto Error;
289 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
290 if (ElementSizes == NULL) goto Error;
292 // Keep starting position of curve offsets
293 DirectoryPos = io ->Tell(io);
295 // Write a fake directory to be filled latter on
296 for (i=0; i < Count; i++) {
298 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
299 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
302 // Write each element. Keep track of the size as well.
303 for (i=0; i < Count; i++) {
305 Before = io ->Tell(io);
306 ElementOffsets[i] = Before - BaseOffset;
308 // Callback to write...
309 if (!ElementFn(self, io, Cargo, i, SizeOfTag)) goto Error;
311 // Now the size
312 ElementSizes[i] = io ->Tell(io) - Before;
315 // Write the directory
316 CurrentPos = io ->Tell(io);
317 if (!io ->Seek(io, DirectoryPos)) goto Error;
319 for (i=0; i < Count; i++) {
320 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
321 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
324 if (!io ->Seek(io, CurrentPos)) goto Error;
326 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
327 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
328 return TRUE;
330 Error:
331 if (ElementOffsets != NULL) _cmsFree(io ->ContextID, ElementOffsets);
332 if (ElementSizes != NULL) _cmsFree(io ->ContextID, ElementSizes);
333 return FALSE;
337 // ********************************************************************************
338 // Type XYZ. Only one value is allowed
339 // ********************************************************************************
341 //The XYZType contains an array of three encoded values for the XYZ tristimulus
342 //values. Tristimulus values must be non-negative. The signed encoding allows for
343 //implementation optimizations by minimizing the number of fixed formats.
346 static
347 void *Type_XYZ_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
349 cmsCIEXYZ* xyz;
351 *nItems = 0;
352 xyz = (cmsCIEXYZ*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIEXYZ));
353 if (xyz == NULL) return NULL;
355 if (!_cmsReadXYZNumber(io, xyz)) {
356 _cmsFree(self ->ContextID, xyz);
357 return NULL;
360 *nItems = 1;
361 return (void*) xyz;
363 cmsUNUSED_PARAMETER(SizeOfTag);
366 static
367 cmsBool Type_XYZ_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
369 return _cmsWriteXYZNumber(io, (cmsCIEXYZ*) Ptr);
371 cmsUNUSED_PARAMETER(nItems);
372 cmsUNUSED_PARAMETER(self);
375 static
376 void* Type_XYZ_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
378 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIEXYZ));
380 cmsUNUSED_PARAMETER(n);
383 static
384 void Type_XYZ_Free(struct _cms_typehandler_struct* self, void *Ptr)
386 _cmsFree(self ->ContextID, Ptr);
390 static
391 cmsTagTypeSignature DecideXYZtype(cmsFloat64Number ICCVersion, const void *Data)
393 return cmsSigXYZType;
395 cmsUNUSED_PARAMETER(ICCVersion);
396 cmsUNUSED_PARAMETER(Data);
400 // ********************************************************************************
401 // Type chromaticity. Only one value is allowed
402 // ********************************************************************************
403 // The chromaticity tag type provides basic chromaticity data and type of
404 // phosphors or colorants of a monitor to applications and utilities.
406 static
407 void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
409 cmsCIExyYTRIPLE* chrm;
410 cmsUInt16Number nChans, Table;
412 *nItems = 0;
413 chrm = (cmsCIExyYTRIPLE*) _cmsMallocZero(self ->ContextID, sizeof(cmsCIExyYTRIPLE));
414 if (chrm == NULL) return NULL;
416 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
418 // Let's recover from a bug introduced in early versions of lcms1
419 if (nChans == 0 && SizeOfTag == 32) {
421 if (!_cmsReadUInt16Number(io, NULL)) goto Error;
422 if (!_cmsReadUInt16Number(io, &nChans)) goto Error;
425 if (nChans != 3) goto Error;
427 if (!_cmsReadUInt16Number(io, &Table)) goto Error;
429 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.x)) goto Error;
430 if (!_cmsRead15Fixed16Number(io, &chrm ->Red.y)) goto Error;
432 chrm ->Red.Y = 1.0;
434 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.x)) goto Error;
435 if (!_cmsRead15Fixed16Number(io, &chrm ->Green.y)) goto Error;
437 chrm ->Green.Y = 1.0;
439 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.x)) goto Error;
440 if (!_cmsRead15Fixed16Number(io, &chrm ->Blue.y)) goto Error;
442 chrm ->Blue.Y = 1.0;
444 *nItems = 1;
445 return (void*) chrm;
447 Error:
448 _cmsFree(self ->ContextID, (void*) chrm);
449 return NULL;
451 cmsUNUSED_PARAMETER(SizeOfTag);
454 static
455 cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
457 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) _cmsDoubleTo15Fixed16(x))) return FALSE;
458 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) _cmsDoubleTo15Fixed16(y))) return FALSE;
460 return TRUE;
463 static
464 cmsBool Type_Chromaticity_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
466 cmsCIExyYTRIPLE* chrm = (cmsCIExyYTRIPLE*) Ptr;
468 if (!_cmsWriteUInt16Number(io, 3)) return FALSE; // nChannels
469 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Table
471 if (!SaveOneChromaticity(chrm -> Red.x, chrm -> Red.y, io)) return FALSE;
472 if (!SaveOneChromaticity(chrm -> Green.x, chrm -> Green.y, io)) return FALSE;
473 if (!SaveOneChromaticity(chrm -> Blue.x, chrm -> Blue.y, io)) return FALSE;
475 return TRUE;
477 cmsUNUSED_PARAMETER(nItems);
478 cmsUNUSED_PARAMETER(self);
481 static
482 void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
484 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE));
486 cmsUNUSED_PARAMETER(n);
489 static
490 void Type_Chromaticity_Free(struct _cms_typehandler_struct* self, void* Ptr)
492 _cmsFree(self ->ContextID, Ptr);
496 // ********************************************************************************
497 // Type cmsSigColorantOrderType
498 // ********************************************************************************
500 // This is an optional tag which specifies the laydown order in which colorants will
501 // be printed on an n-colorant device. The laydown order may be the same as the
502 // channel generation order listed in the colorantTableTag or the channel order of a
503 // colour space such as CMYK, in which case this tag is not needed. When this is not
504 // the case (for example, ink-towers sometimes use the order KCMY), this tag may be
505 // used to specify the laydown order of the colorants.
508 static
509 void *Type_ColorantOrderType_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
511 cmsUInt8Number* ColorantOrder;
512 cmsUInt32Number Count;
514 *nItems = 0;
515 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
516 if (Count > cmsMAXCHANNELS) return NULL;
518 ColorantOrder = (cmsUInt8Number*) _cmsCalloc(self ->ContextID, cmsMAXCHANNELS, sizeof(cmsUInt8Number));
519 if (ColorantOrder == NULL) return NULL;
521 // We use FF as end marker
522 memset(ColorantOrder, 0xFF, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
524 if (io ->Read(io, ColorantOrder, sizeof(cmsUInt8Number), Count) != Count) {
526 _cmsFree(self ->ContextID, (void*) ColorantOrder);
527 return NULL;
530 *nItems = 1;
531 return (void*) ColorantOrder;
533 cmsUNUSED_PARAMETER(SizeOfTag);
536 static
537 cmsBool Type_ColorantOrderType_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
539 cmsUInt8Number* ColorantOrder = (cmsUInt8Number*) Ptr;
540 cmsUInt32Number i, sz, Count;
542 // Get the length
543 for (Count=i=0; i < cmsMAXCHANNELS; i++) {
544 if (ColorantOrder[i] != 0xFF) Count++;
547 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
549 sz = Count * sizeof(cmsUInt8Number);
550 if (!io -> Write(io, sz, ColorantOrder)) return FALSE;
552 return TRUE;
554 cmsUNUSED_PARAMETER(nItems);
555 cmsUNUSED_PARAMETER(self);
558 static
559 void* Type_ColorantOrderType_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
561 return _cmsDupMem(self ->ContextID, Ptr, cmsMAXCHANNELS * sizeof(cmsUInt8Number));
563 cmsUNUSED_PARAMETER(n);
567 static
568 void Type_ColorantOrderType_Free(struct _cms_typehandler_struct* self, void* Ptr)
570 _cmsFree(self ->ContextID, Ptr);
573 // ********************************************************************************
574 // Type cmsSigS15Fixed16ArrayType
575 // ********************************************************************************
576 // This type represents an array of generic 4-byte/32-bit fixed point quantity.
577 // The number of values is determined from the size of the tag.
579 static
580 void *Type_S15Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
582 cmsFloat64Number* array_double;
583 cmsUInt32Number i, n;
585 *nItems = 0;
586 n = SizeOfTag / sizeof(cmsUInt32Number);
587 array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
588 if (array_double == NULL) return NULL;
590 for (i=0; i < n; i++) {
592 if (!_cmsRead15Fixed16Number(io, &array_double[i])) {
594 _cmsFree(self ->ContextID, array_double);
595 return NULL;
599 *nItems = n;
600 return (void*) array_double;
603 static
604 cmsBool Type_S15Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
606 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
607 cmsUInt32Number i;
609 for (i=0; i < nItems; i++) {
611 if (!_cmsWrite15Fixed16Number(io, Value[i])) return FALSE;
614 return TRUE;
616 cmsUNUSED_PARAMETER(self);
619 static
620 void* Type_S15Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
622 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
626 static
627 void Type_S15Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
629 _cmsFree(self ->ContextID, Ptr);
632 // ********************************************************************************
633 // Type cmsSigU16Fixed16ArrayType
634 // ********************************************************************************
635 // This type represents an array of generic 4-byte/32-bit quantity.
636 // The number of values is determined from the size of the tag.
639 static
640 void *Type_U16Fixed16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
642 cmsFloat64Number* array_double;
643 cmsUInt32Number v;
644 cmsUInt32Number i, n;
646 *nItems = 0;
647 n = SizeOfTag / sizeof(cmsUInt32Number);
648 array_double = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, n, sizeof(cmsFloat64Number));
649 if (array_double == NULL) return NULL;
651 for (i=0; i < n; i++) {
653 if (!_cmsReadUInt32Number(io, &v)) {
654 _cmsFree(self ->ContextID, (void*) array_double);
655 return NULL;
658 // Convert to cmsFloat64Number
659 array_double[i] = (cmsFloat64Number) (v / 65536.0);
662 *nItems = n;
663 return (void*) array_double;
666 static
667 cmsBool Type_U16Fixed16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
669 cmsFloat64Number* Value = (cmsFloat64Number*) Ptr;
670 cmsUInt32Number i;
672 for (i=0; i < nItems; i++) {
674 cmsUInt32Number v = (cmsUInt32Number) floor(Value[i]*65536.0 + 0.5);
676 if (!_cmsWriteUInt32Number(io, v)) return FALSE;
679 return TRUE;
681 cmsUNUSED_PARAMETER(self);
685 static
686 void* Type_U16Fixed16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
688 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsFloat64Number));
691 static
692 void Type_U16Fixed16_Free(struct _cms_typehandler_struct* self, void* Ptr)
694 _cmsFree(self ->ContextID, Ptr);
697 // ********************************************************************************
698 // Type cmsSigSignatureType
699 // ********************************************************************************
701 // The signatureType contains a four-byte sequence, Sequences of less than four
702 // characters are padded at the end with spaces, 20h.
703 // Typically this type is used for registered tags that can be displayed on many
704 // development systems as a sequence of four characters.
706 static
707 void *Type_Signature_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
709 cmsSignature* SigPtr = (cmsSignature*) _cmsMalloc(self ->ContextID, sizeof(cmsSignature));
710 if (SigPtr == NULL) return NULL;
712 if (!_cmsReadUInt32Number(io, SigPtr)) return NULL;
713 *nItems = 1;
715 return SigPtr;
717 cmsUNUSED_PARAMETER(SizeOfTag);
720 static
721 cmsBool Type_Signature_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
723 cmsSignature* SigPtr = (cmsSignature*) Ptr;
725 return _cmsWriteUInt32Number(io, *SigPtr);
727 cmsUNUSED_PARAMETER(nItems);
728 cmsUNUSED_PARAMETER(self);
731 static
732 void* Type_Signature_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
734 return _cmsDupMem(self ->ContextID, Ptr, n * sizeof(cmsSignature));
737 static
738 void Type_Signature_Free(struct _cms_typehandler_struct* self, void* Ptr)
740 _cmsFree(self ->ContextID, Ptr);
744 // ********************************************************************************
745 // Type cmsSigTextType
746 // ********************************************************************************
748 // The textType is a simple text structure that contains a 7-bit ASCII text string.
749 // The length of the string is obtained by subtracting 8 from the element size portion
750 // of the tag itself. This string must be terminated with a 00h byte.
752 static
753 void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
755 char* Text = NULL;
756 cmsMLU* mlu = NULL;
758 // Create a container
759 mlu = cmsMLUalloc(self ->ContextID, 1);
760 if (mlu == NULL) return NULL;
762 *nItems = 0;
764 // We need to store the "\0" at the end, so +1
765 if (SizeOfTag == UINT_MAX) goto Error;
767 Text = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1);
768 if (Text == NULL) goto Error;
770 if (io -> Read(io, Text, sizeof(char), SizeOfTag) != SizeOfTag) goto Error;
772 // Make sure text is properly ended
773 Text[SizeOfTag] = 0;
774 *nItems = 1;
776 // Keep the result
777 if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
779 _cmsFree(self ->ContextID, Text);
780 return (void*) mlu;
782 Error:
783 if (mlu != NULL)
784 cmsMLUfree(mlu);
785 if (Text != NULL)
786 _cmsFree(self ->ContextID, Text);
788 return NULL;
791 // The conversion implies to choose a language. So, we choose the actual language.
792 static
793 cmsBool Type_Text_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
795 cmsMLU* mlu = (cmsMLU*) Ptr;
796 cmsUInt32Number size;
797 cmsBool rc;
798 char* Text;
800 // Get the size of the string. Note there is an extra "\0" at the end
801 size = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
802 if (size == 0) return FALSE; // Cannot be zero!
804 // Create memory
805 Text = (char*) _cmsMalloc(self ->ContextID, size);
806 if (Text == NULL) return FALSE;
808 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
810 // Write it, including separator
811 rc = io ->Write(io, size, Text);
813 _cmsFree(self ->ContextID, Text);
814 return rc;
816 cmsUNUSED_PARAMETER(nItems);
819 static
820 void* Type_Text_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
822 return (void*) cmsMLUdup((cmsMLU*) Ptr);
824 cmsUNUSED_PARAMETER(n);
825 cmsUNUSED_PARAMETER(self);
829 static
830 void Type_Text_Free(struct _cms_typehandler_struct* self, void* Ptr)
832 cmsMLU* mlu = (cmsMLU*) Ptr;
833 cmsMLUfree(mlu);
834 return;
836 cmsUNUSED_PARAMETER(self);
839 static
840 cmsTagTypeSignature DecideTextType(cmsFloat64Number ICCVersion, const void *Data)
842 if (ICCVersion >= 4.0)
843 return cmsSigMultiLocalizedUnicodeType;
845 return cmsSigTextType;
847 cmsUNUSED_PARAMETER(Data);
851 // ********************************************************************************
852 // Type cmsSigDataType
853 // ********************************************************************************
855 // General purpose data type
856 static
857 void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
859 cmsICCData* BinData;
860 cmsUInt32Number LenOfData;
862 *nItems = 0;
864 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
866 LenOfData = SizeOfTag - sizeof(cmsUInt32Number);
867 if (LenOfData > INT_MAX) return NULL;
869 BinData = (cmsICCData*) _cmsMalloc(self ->ContextID, sizeof(cmsICCData) + LenOfData - 1);
870 if (BinData == NULL) return NULL;
872 BinData ->len = LenOfData;
873 if (!_cmsReadUInt32Number(io, &BinData->flag)) {
874 _cmsFree(self ->ContextID, BinData);
875 return NULL;
878 if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) {
880 _cmsFree(self ->ContextID, BinData);
881 return NULL;
884 *nItems = 1;
886 return (void*) BinData;
890 static
891 cmsBool Type_Data_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
893 cmsICCData* BinData = (cmsICCData*) Ptr;
895 if (!_cmsWriteUInt32Number(io, BinData ->flag)) return FALSE;
897 return io ->Write(io, BinData ->len, BinData ->data);
899 cmsUNUSED_PARAMETER(nItems);
900 cmsUNUSED_PARAMETER(self);
904 static
905 void* Type_Data_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
907 cmsICCData* BinData = (cmsICCData*) Ptr;
909 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCData) + BinData ->len - 1);
911 cmsUNUSED_PARAMETER(n);
914 static
915 void Type_Data_Free(struct _cms_typehandler_struct* self, void* Ptr)
917 _cmsFree(self ->ContextID, Ptr);
920 // ********************************************************************************
921 // Type cmsSigTextDescriptionType
922 // ********************************************************************************
924 static
925 void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
927 char* Text = NULL;
928 cmsMLU* mlu = NULL;
929 cmsUInt32Number AsciiCount;
930 cmsUInt32Number i, UnicodeCode, UnicodeCount;
931 cmsUInt16Number ScriptCodeCode, Dummy;
932 cmsUInt8Number ScriptCodeCount;
934 *nItems = 0;
936 // One dword should be there
937 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
939 // Read len of ASCII
940 if (!_cmsReadUInt32Number(io, &AsciiCount)) return NULL;
941 SizeOfTag -= sizeof(cmsUInt32Number);
943 // Check for size
944 if (SizeOfTag < AsciiCount) return NULL;
946 // All seems Ok, allocate the container
947 mlu = cmsMLUalloc(self ->ContextID, 1);
948 if (mlu == NULL) return NULL;
950 // As many memory as size of tag
951 Text = (char*) _cmsMalloc(self ->ContextID, AsciiCount + 1);
952 if (Text == NULL) goto Error;
954 // Read it
955 if (io ->Read(io, Text, sizeof(char), AsciiCount) != AsciiCount) goto Error;
956 SizeOfTag -= AsciiCount;
958 // Make sure there is a terminator
959 Text[AsciiCount] = 0;
961 // Set the MLU entry. From here we can be tolerant to wrong types
962 if (!cmsMLUsetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text)) goto Error;
963 _cmsFree(self ->ContextID, (void*) Text);
964 Text = NULL;
966 // Skip Unicode code
967 if (SizeOfTag < 2* sizeof(cmsUInt32Number)) goto Done;
968 if (!_cmsReadUInt32Number(io, &UnicodeCode)) goto Done;
969 if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
970 SizeOfTag -= 2* sizeof(cmsUInt32Number);
972 if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
974 for (i=0; i < UnicodeCount; i++) {
975 if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
977 SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
979 // Skip ScriptCode code if present. Some buggy profiles does have less
980 // data that stricttly required. We need to skip it as this type may come
981 // embedded in other types.
983 if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
985 if (!_cmsReadUInt16Number(io, &ScriptCodeCode)) goto Done;
986 if (!_cmsReadUInt8Number(io, &ScriptCodeCount)) goto Done;
988 // Skip rest of tag
989 for (i=0; i < 67; i++) {
990 if (!io ->Read(io, &Dummy, sizeof(cmsUInt8Number), 1)) goto Error;
994 Done:
996 *nItems = 1;
997 return mlu;
999 Error:
1000 if (Text) _cmsFree(self ->ContextID, (void*) Text);
1001 if (mlu) cmsMLUfree(mlu);
1002 return NULL;
1006 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
1007 static
1008 cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1010 cmsMLU* mlu = (cmsMLU*) Ptr;
1011 char *Text = NULL;
1012 wchar_t *Wide = NULL;
1013 cmsUInt32Number len, len_text, len_tag_requirement, len_aligned;
1014 cmsBool rc = FALSE;
1015 char Filler[68];
1017 // Used below for writing zeroes
1018 memset(Filler, 0, sizeof(Filler));
1020 // Get the len of string
1021 len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
1023 // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data
1024 //(see clause 4.1 for the definition of 'aligned'). Because the Unicode language
1025 // code and Unicode count immediately follow the ASCII description, their
1026 // alignment is not correct if the ASCII count is not a multiple of four. The
1027 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
1028 // writing software must be written carefully in order to handle these alignment
1029 // problems.
1031 // The above last sentence suggest to handle alignment issues in the
1032 // parser. The provided example (Table 69 on Page 60) makes this clear.
1033 // The padding only in the ASCII count is not sufficient for a aligned tag
1034 // size, with the same text size in ASCII and Unicode.
1036 // Null strings
1037 if (len <= 0) {
1039 Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
1040 Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
1042 else {
1043 // Create independent buffers
1044 Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
1045 if (Text == NULL) goto Error;
1047 Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t));
1048 if (Wide == NULL) goto Error;
1050 // Get both representations.
1051 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char));
1052 cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t));
1055 // Tell the real text len including the null terminator and padding
1056 len_text = (cmsUInt32Number) strlen(Text) + 1;
1057 // Compute an total tag size requirement
1058 len_tag_requirement = (8+4+len_text+4+4+2*len_text+2+1+67);
1059 len_aligned = _cmsALIGNLONG(len_tag_requirement);
1061 // * cmsUInt32Number count; * Description length
1062 // * cmsInt8Number desc[count] * NULL terminated ascii string
1063 // * cmsUInt32Number ucLangCode; * UniCode language code
1064 // * cmsUInt32Number ucCount; * UniCode description length
1065 // * cmsInt16Number ucDesc[ucCount];* The UniCode description
1066 // * cmsUInt16Number scCode; * ScriptCode code
1067 // * cmsUInt8Number scCount; * ScriptCode count
1068 // * cmsInt8Number scDesc[67]; * ScriptCode Description
1070 if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1071 if (!io ->Write(io, len_text, Text)) goto Error;
1073 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode
1075 if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1076 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1077 if (!_cmsWriteWCharArray(io, len_text, Wide)) goto Error;
1079 // ScriptCode Code & count (unused)
1080 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
1081 if (!_cmsWriteUInt8Number(io, 0)) goto Error;
1083 if (!io ->Write(io, 67, Filler)) goto Error;
1085 // possibly add pad at the end of tag
1086 if(len_aligned - len_tag_requirement > 0)
1087 if (!io ->Write(io, len_aligned - len_tag_requirement, Filler)) goto Error;
1089 rc = TRUE;
1091 Error:
1092 if (Text) _cmsFree(self ->ContextID, Text);
1093 if (Wide) _cmsFree(self ->ContextID, Wide);
1095 return rc;
1097 cmsUNUSED_PARAMETER(nItems);
1101 static
1102 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1104 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1106 cmsUNUSED_PARAMETER(n);
1107 cmsUNUSED_PARAMETER(self);
1110 static
1111 void Type_Text_Description_Free(struct _cms_typehandler_struct* self, void* Ptr)
1113 cmsMLU* mlu = (cmsMLU*) Ptr;
1115 cmsMLUfree(mlu);
1116 return;
1118 cmsUNUSED_PARAMETER(self);
1122 static
1123 cmsTagTypeSignature DecideTextDescType(cmsFloat64Number ICCVersion, const void *Data)
1125 if (ICCVersion >= 4.0)
1126 return cmsSigMultiLocalizedUnicodeType;
1128 return cmsSigTextDescriptionType;
1130 cmsUNUSED_PARAMETER(Data);
1134 // ********************************************************************************
1135 // Type cmsSigCurveType
1136 // ********************************************************************************
1138 static
1139 void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1141 cmsUInt32Number Count;
1142 cmsToneCurve* NewGamma;
1144 *nItems = 0;
1145 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1147 switch (Count) {
1149 case 0: // Linear.
1151 cmsFloat64Number SingleGamma = 1.0;
1153 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1154 if (!NewGamma) return NULL;
1155 *nItems = 1;
1156 return NewGamma;
1159 case 1: // Specified as the exponent of gamma function
1161 cmsUInt16Number SingleGammaFixed;
1162 cmsFloat64Number SingleGamma;
1164 if (!_cmsReadUInt16Number(io, &SingleGammaFixed)) return NULL;
1165 SingleGamma = _cms8Fixed8toDouble(SingleGammaFixed);
1167 *nItems = 1;
1168 return cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma);
1171 default: // Curve
1173 if (Count > 0x7FFF)
1174 return NULL; // This is to prevent bad guys for doing bad things
1176 NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
1177 if (!NewGamma) return NULL;
1179 if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) {
1180 cmsFreeToneCurve(NewGamma);
1181 return NULL;
1184 *nItems = 1;
1185 return NewGamma;
1188 cmsUNUSED_PARAMETER(SizeOfTag);
1192 static
1193 cmsBool Type_Curve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1195 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1197 if (Curve ->nSegments == 1 && Curve ->Segments[0].Type == 1) {
1199 // Single gamma, preserve number
1200 cmsUInt16Number SingleGammaFixed = _cmsDoubleTo8Fixed8(Curve ->Segments[0].Params[0]);
1202 if (!_cmsWriteUInt32Number(io, 1)) return FALSE;
1203 if (!_cmsWriteUInt16Number(io, SingleGammaFixed)) return FALSE;
1204 return TRUE;
1208 if (!_cmsWriteUInt32Number(io, Curve ->nEntries)) return FALSE;
1209 return _cmsWriteUInt16Array(io, Curve ->nEntries, Curve ->Table16);
1211 cmsUNUSED_PARAMETER(nItems);
1212 cmsUNUSED_PARAMETER(self);
1216 static
1217 void* Type_Curve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1219 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1221 cmsUNUSED_PARAMETER(n);
1222 cmsUNUSED_PARAMETER(self);
1225 static
1226 void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1228 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1230 cmsFreeToneCurve(gamma);
1231 return;
1233 cmsUNUSED_PARAMETER(self);
1237 // ********************************************************************************
1238 // Type cmsSigParametricCurveType
1239 // ********************************************************************************
1242 // Decide which curve type to use on writing
1243 static
1244 cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
1246 cmsToneCurve* Curve = (cmsToneCurve*) Data;
1248 if (ICCVersion < 4.0) return cmsSigCurveType;
1249 if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric
1250 if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves
1251 if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves
1253 return cmsSigParametricCurveType;
1256 static
1257 void *Type_ParametricCurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1259 static const int ParamsByType[] = { 1, 3, 4, 5, 7 };
1260 cmsFloat64Number Params[10];
1261 cmsUInt16Number Type;
1262 int i, n;
1263 cmsToneCurve* NewGamma;
1265 if (!_cmsReadUInt16Number(io, &Type)) return NULL;
1266 if (!_cmsReadUInt16Number(io, NULL)) return NULL; // Reserved
1268 if (Type > 4) {
1270 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown parametric curve type '%d'", Type);
1271 return NULL;
1274 memset(Params, 0, sizeof(Params));
1275 n = ParamsByType[Type];
1277 for (i=0; i < n; i++) {
1279 if (!_cmsRead15Fixed16Number(io, &Params[i])) return NULL;
1282 NewGamma = cmsBuildParametricToneCurve(self ->ContextID, Type+1, Params);
1284 *nItems = 1;
1285 return NewGamma;
1287 cmsUNUSED_PARAMETER(SizeOfTag);
1291 static
1292 cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1294 cmsToneCurve* Curve = (cmsToneCurve*) Ptr;
1295 int i, nParams, typen;
1296 static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 };
1298 typen = Curve -> Segments[0].Type;
1300 if (Curve ->nSegments > 1 || typen < 1) {
1302 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written");
1303 return FALSE;
1306 if (typen > 5) {
1307 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported parametric curve");
1308 return FALSE;
1311 nParams = ParamsByType[typen];
1313 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) (Curve ->Segments[0].Type - 1))) return FALSE;
1314 if (!_cmsWriteUInt16Number(io, 0)) return FALSE; // Reserved
1316 for (i=0; i < nParams; i++) {
1318 if (!_cmsWrite15Fixed16Number(io, Curve -> Segments[0].Params[i])) return FALSE;
1321 return TRUE;
1323 cmsUNUSED_PARAMETER(nItems);
1326 static
1327 void* Type_ParametricCurve_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1329 return (void*) cmsDupToneCurve((cmsToneCurve*) Ptr);
1331 cmsUNUSED_PARAMETER(n);
1332 cmsUNUSED_PARAMETER(self);
1335 static
1336 void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr)
1338 cmsToneCurve* gamma = (cmsToneCurve*) Ptr;
1340 cmsFreeToneCurve(gamma);
1341 return;
1343 cmsUNUSED_PARAMETER(self);
1347 // ********************************************************************************
1348 // Type cmsSigDateTimeType
1349 // ********************************************************************************
1351 // A 12-byte value representation of the time and date, where the byte usage is assigned
1352 // as specified in table 1. The actual values are encoded as 16-bit unsigned integers
1353 // (uInt16Number - see 5.1.6).
1355 // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time
1356 // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local
1357 // time to UTC when setting these values. Programs that display these values may show
1358 // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or
1359 // display both UTC and local versions of the dateTimeNumber.
1361 static
1362 void *Type_DateTime_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1364 cmsDateTimeNumber timestamp;
1365 struct tm * NewDateTime;
1367 *nItems = 0;
1368 NewDateTime = (struct tm*) _cmsMalloc(self ->ContextID, sizeof(struct tm));
1369 if (NewDateTime == NULL) return NULL;
1371 if (io->Read(io, &timestamp, sizeof(cmsDateTimeNumber), 1) != 1) return NULL;
1373 _cmsDecodeDateTimeNumber(&timestamp, NewDateTime);
1375 *nItems = 1;
1376 return NewDateTime;
1378 cmsUNUSED_PARAMETER(SizeOfTag);
1382 static
1383 cmsBool Type_DateTime_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1385 struct tm * DateTime = (struct tm*) Ptr;
1386 cmsDateTimeNumber timestamp;
1388 _cmsEncodeDateTimeNumber(&timestamp, DateTime);
1389 if (!io ->Write(io, sizeof(cmsDateTimeNumber), &timestamp)) return FALSE;
1391 return TRUE;
1393 cmsUNUSED_PARAMETER(nItems);
1394 cmsUNUSED_PARAMETER(self);
1397 static
1398 void* Type_DateTime_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1400 return _cmsDupMem(self ->ContextID, Ptr, sizeof(struct tm));
1402 cmsUNUSED_PARAMETER(n);
1405 static
1406 void Type_DateTime_Free(struct _cms_typehandler_struct* self, void* Ptr)
1408 _cmsFree(self ->ContextID, Ptr);
1413 // ********************************************************************************
1414 // Type icMeasurementType
1415 // ********************************************************************************
1418 The measurementType information refers only to the internal profile data and is
1419 meant to provide profile makers an alternative to the default measurement
1420 specifications.
1423 static
1424 void *Type_Measurement_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1426 cmsICCMeasurementConditions mc;
1429 memset(&mc, 0, sizeof(mc));
1431 if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
1432 if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
1433 if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
1434 if (!_cmsRead15Fixed16Number(io, &mc.Flare)) return NULL;
1435 if (!_cmsReadUInt32Number(io, &mc.IlluminantType)) return NULL;
1437 *nItems = 1;
1438 return _cmsDupMem(self ->ContextID, &mc, sizeof(cmsICCMeasurementConditions));
1440 cmsUNUSED_PARAMETER(SizeOfTag);
1444 static
1445 cmsBool Type_Measurement_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1447 cmsICCMeasurementConditions* mc =(cmsICCMeasurementConditions*) Ptr;
1449 if (!_cmsWriteUInt32Number(io, mc->Observer)) return FALSE;
1450 if (!_cmsWriteXYZNumber(io, &mc->Backing)) return FALSE;
1451 if (!_cmsWriteUInt32Number(io, mc->Geometry)) return FALSE;
1452 if (!_cmsWrite15Fixed16Number(io, mc->Flare)) return FALSE;
1453 if (!_cmsWriteUInt32Number(io, mc->IlluminantType)) return FALSE;
1455 return TRUE;
1457 cmsUNUSED_PARAMETER(nItems);
1458 cmsUNUSED_PARAMETER(self);
1461 static
1462 void* Type_Measurement_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1464 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsICCMeasurementConditions));
1466 cmsUNUSED_PARAMETER(n);
1469 static
1470 void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* Ptr)
1472 _cmsFree(self ->ContextID, Ptr);
1476 // ********************************************************************************
1477 // Type cmsSigMultiLocalizedUnicodeType
1478 // ********************************************************************************
1480 // Do NOT trust SizeOfTag as there is an issue on the definition of profileSequenceDescTag. See the TechNote from
1481 // Max Derhak and Rohit Patil about this: basically the size of the string table should be guessed and cannot be
1482 // taken from the size of tag if this tag is embedded as part of bigger structures (profileSequenceDescTag, for instance)
1485 static
1486 void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1488 cmsMLU* mlu;
1489 cmsUInt32Number Count, RecLen, NumOfWchar;
1490 cmsUInt32Number SizeOfHeader;
1491 cmsUInt32Number Len, Offset;
1492 cmsUInt32Number i;
1493 wchar_t* Block;
1494 cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition;
1496 *nItems = 0;
1497 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
1498 if (!_cmsReadUInt32Number(io, &RecLen)) return NULL;
1500 if (RecLen != 12) {
1502 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "multiLocalizedUnicodeType of len != 12 is not supported.");
1503 return NULL;
1506 mlu = cmsMLUalloc(self ->ContextID, Count);
1507 if (mlu == NULL) return NULL;
1509 mlu ->UsedEntries = Count;
1511 SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
1512 LargestPosition = 0;
1514 for (i=0; i < Count; i++) {
1516 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
1517 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error;
1519 // Now deal with Len and offset.
1520 if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1521 if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1523 // Offset MUST be even because it indexes a block of utf16 chars.
1524 // Tricky profiles that uses odd positions will not work anyway
1525 // because the whole utf16 block is previously converted to wchar_t
1526 // and sizeof this type may be of 4 bytes. On Linux systems, for example.
1527 if (Offset & 1) goto Error;
1529 // Check for overflow
1530 if (Offset < (SizeOfHeader + 8)) goto Error;
1531 if (((Offset + Len) < Len) || ((Offset + Len) > SizeOfTag + 8)) goto Error;
1533 // True begin of the string
1534 BeginOfThisString = Offset - SizeOfHeader - 8;
1536 // Adjust to wchar_t elements
1537 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1538 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1540 // To guess maximum size, add offset + len
1541 EndOfThisString = BeginOfThisString + Len;
1542 if (EndOfThisString > LargestPosition)
1543 LargestPosition = EndOfThisString;
1546 // Now read the remaining of tag and fill all strings. Subtract the directory
1547 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1548 if (SizeOfTag == 0)
1550 Block = NULL;
1551 NumOfWchar = 0;
1554 else
1556 // Make sure this is an even utf16 size.
1557 if (SizeOfTag & 1) goto Error;
1559 Block = (wchar_t*) _cmsCalloc(self ->ContextID, 1, SizeOfTag);
1560 if (Block == NULL) goto Error;
1562 NumOfWchar = SizeOfTag / sizeof(wchar_t);
1563 if (!_cmsReadWCharArray(io, NumOfWchar, Block)) {
1564 _cmsFree(self->ContextID, Block);
1565 goto Error;
1569 mlu ->MemPool = Block;
1570 mlu ->PoolSize = SizeOfTag;
1571 mlu ->PoolUsed = SizeOfTag;
1573 *nItems = 1;
1574 return (void*) mlu;
1576 Error:
1577 if (mlu) cmsMLUfree(mlu);
1578 return NULL;
1581 static
1582 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1584 cmsMLU* mlu =(cmsMLU*) Ptr;
1585 cmsUInt32Number HeaderSize;
1586 cmsUInt32Number Len, Offset;
1587 cmsUInt32Number i;
1589 if (Ptr == NULL) {
1591 // Empty placeholder
1592 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1593 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1594 return TRUE;
1597 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1598 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1600 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1602 for (i=0; i < mlu ->UsedEntries; i++) {
1604 Len = mlu ->Entries[i].Len;
1605 Offset = mlu ->Entries[i].StrW;
1607 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
1608 Offset = (Offset * sizeof(cmsUInt16Number)) / sizeof(wchar_t) + HeaderSize + 8;
1610 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Language)) return FALSE;
1611 if (!_cmsWriteUInt16Number(io, mlu ->Entries[i].Country)) return FALSE;
1612 if (!_cmsWriteUInt32Number(io, Len)) return FALSE;
1613 if (!_cmsWriteUInt32Number(io, Offset)) return FALSE;
1616 if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE;
1618 return TRUE;
1620 cmsUNUSED_PARAMETER(nItems);
1621 cmsUNUSED_PARAMETER(self);
1625 static
1626 void* Type_MLU_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1628 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1630 cmsUNUSED_PARAMETER(n);
1631 cmsUNUSED_PARAMETER(self);
1634 static
1635 void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
1637 cmsMLUfree((cmsMLU*) Ptr);
1638 return;
1640 cmsUNUSED_PARAMETER(self);
1644 // ********************************************************************************
1645 // Type cmsSigLut8Type
1646 // ********************************************************************************
1648 // Decide which LUT type to use on writing
1649 static
1650 cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
1652 cmsPipeline* Lut = (cmsPipeline*) Data;
1654 if (ICCVersion < 4.0) {
1655 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1656 return cmsSigLut16Type;
1658 else {
1659 return cmsSigLutAtoBType;
1663 static
1664 cmsTagTypeSignature DecideLUTtypeB2A(cmsFloat64Number ICCVersion, const void *Data)
1666 cmsPipeline* Lut = (cmsPipeline*) Data;
1668 if (ICCVersion < 4.0) {
1669 if (Lut ->SaveAs8Bits) return cmsSigLut8Type;
1670 return cmsSigLut16Type;
1672 else {
1673 return cmsSigLutBtoAType;
1678 This structure represents a colour transform using tables of 8-bit precision.
1679 This type contains four processing elements: a 3 by 3 matrix (which shall be
1680 the identity matrix unless the input colour space is XYZ), a set of one dimensional
1681 input tables, a multidimensional lookup table, and a set of one dimensional output
1682 tables. Data is processed using these elements via the following sequence:
1683 (matrix) -> (1d input tables) -> (multidimensional lookup table - CLUT) -> (1d output tables)
1685 Byte Position Field Length (bytes) Content Encoded as...
1686 8 1 Number of Input Channels (i) uInt8Number
1687 9 1 Number of Output Channels (o) uInt8Number
1688 10 1 Number of CLUT grid points (identical for each side) (g) uInt8Number
1689 11 1 Reserved for padding (fill with 00h)
1691 12..15 4 Encoded e00 parameter s15Fixed16Number
1695 // Read 8 bit tables as gamma functions
1696 static
1697 cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, cmsUInt32Number nChannels)
1699 cmsUInt8Number* Temp = NULL;
1700 cmsUInt32Number i, j;
1701 cmsToneCurve* Tables[cmsMAXCHANNELS];
1703 if (nChannels > cmsMAXCHANNELS) return FALSE;
1704 if (nChannels <= 0) return FALSE;
1706 memset(Tables, 0, sizeof(Tables));
1708 Temp = (cmsUInt8Number*) _cmsMalloc(ContextID, 256);
1709 if (Temp == NULL) return FALSE;
1711 for (i=0; i < nChannels; i++) {
1712 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
1713 if (Tables[i] == NULL) goto Error;
1716 for (i=0; i < nChannels; i++) {
1718 if (io ->Read(io, Temp, 256, 1) != 1) goto Error;
1720 for (j=0; j < 256; j++)
1721 Tables[i]->Table16[j] = (cmsUInt16Number) FROM_8_TO_16(Temp[j]);
1724 _cmsFree(ContextID, Temp);
1725 Temp = NULL;
1727 if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
1728 goto Error;
1730 for (i=0; i < nChannels; i++)
1731 cmsFreeToneCurve(Tables[i]);
1733 return TRUE;
1735 Error:
1736 for (i=0; i < nChannels; i++) {
1737 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
1740 if (Temp) _cmsFree(ContextID, Temp);
1741 return FALSE;
1745 static
1746 cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number n, _cmsStageToneCurvesData* Tables)
1748 int j;
1749 cmsUInt32Number i;
1750 cmsUInt8Number val;
1752 for (i=0; i < n; i++) {
1754 if (Tables) {
1756 // Usual case of identity curves
1757 if ((Tables ->TheCurves[i]->nEntries == 2) &&
1758 (Tables->TheCurves[i]->Table16[0] == 0) &&
1759 (Tables->TheCurves[i]->Table16[1] == 65535)) {
1761 for (j=0; j < 256; j++) {
1762 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE;
1765 else
1766 if (Tables ->TheCurves[i]->nEntries != 256) {
1767 cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization");
1768 return FALSE;
1770 else
1771 for (j=0; j < 256; j++) {
1773 val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]);
1775 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
1779 return TRUE;
1783 // Check overflow
1784 static
1785 cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b)
1787 cmsUInt32Number rv = 1, rc;
1789 if (a == 0) return 0;
1790 if (n == 0) return 0;
1792 for (; b > 0; b--) {
1794 rv *= a;
1796 // Check for overflow
1797 if (rv > UINT_MAX / a) return (cmsUInt32Number) -1;
1801 rc = rv * n;
1803 if (rv != rc / n) return (cmsUInt32Number) -1;
1804 return rc;
1808 // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables.
1809 // 8 bit lut may be scaled easily to v4 PCS, but we need also to properly adjust
1810 // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction.
1812 static
1813 void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
1815 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
1816 cmsUInt8Number* Temp = NULL;
1817 cmsPipeline* NewLUT = NULL;
1818 cmsUInt32Number nTabSize, i;
1819 cmsFloat64Number Matrix[3*3];
1821 *nItems = 0;
1823 if (!_cmsReadUInt8Number(io, &InputChannels)) goto Error;
1824 if (!_cmsReadUInt8Number(io, &OutputChannels)) goto Error;
1825 if (!_cmsReadUInt8Number(io, &CLUTpoints)) goto Error;
1827 if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
1829 // Padding
1830 if (!_cmsReadUInt8Number(io, NULL)) goto Error;
1832 // Do some checking
1833 if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error;
1834 if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
1836 // Allocates an empty Pipeline
1837 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
1838 if (NewLUT == NULL) goto Error;
1840 // Read the Matrix
1841 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
1842 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
1843 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
1844 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
1845 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
1846 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
1847 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
1848 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
1849 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
1852 // Only operates if not identity...
1853 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
1855 if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
1856 goto Error;
1859 // Get input tables
1860 if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error;
1862 // Get 3D CLUT. Check the overflow....
1863 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
1864 if (nTabSize == (cmsUInt32Number) -1) goto Error;
1865 if (nTabSize > 0) {
1867 cmsUInt16Number *PtrW, *T;
1869 PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
1870 if (T == NULL) goto Error;
1872 Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
1873 if (Temp == NULL) {
1874 _cmsFree(self ->ContextID, T);
1875 goto Error;
1878 if (io ->Read(io, Temp, nTabSize, 1) != 1) {
1879 _cmsFree(self ->ContextID, T);
1880 _cmsFree(self ->ContextID, Temp);
1881 goto Error;
1884 for (i = 0; i < nTabSize; i++) {
1886 *PtrW++ = FROM_8_TO_16(Temp[i]);
1888 _cmsFree(self ->ContextID, Temp);
1889 Temp = NULL;
1891 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
1892 _cmsFree(self ->ContextID, T);
1893 goto Error;
1895 _cmsFree(self ->ContextID, T);
1899 // Get output tables
1900 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
1902 *nItems = 1;
1903 return NewLUT;
1905 Error:
1906 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1907 return NULL;
1909 cmsUNUSED_PARAMETER(SizeOfTag);
1912 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1913 static
1914 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1916 cmsUInt32Number j, nTabSize, i;
1917 cmsUInt8Number val;
1918 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1919 cmsStage* mpe;
1920 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1921 _cmsStageMatrixData* MatMPE = NULL;
1922 _cmsStageCLutData* clut = NULL;
1923 cmsUInt32Number clutPoints;
1925 // Disassemble the LUT into components.
1926 mpe = NewLUT -> Elements;
1927 if (mpe ->Type == cmsSigMatrixElemType) {
1929 if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE;
1930 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1931 mpe = mpe -> Next;
1934 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1935 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1936 mpe = mpe -> Next;
1939 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
1940 clut = (_cmsStageCLutData*) mpe -> Data;
1941 mpe = mpe ->Next;
1944 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1945 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1946 mpe = mpe -> Next;
1949 // That should be all
1950 if (mpe != NULL) {
1951 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
1952 return FALSE;
1955 if (clut == NULL)
1956 clutPoints = 0;
1957 else {
1958 // Lut8 only allows same CLUT points in all dimensions
1959 clutPoints = clut->Params->nSamples[0];
1960 for (i = 1; i < cmsPipelineInputChannels(NewLUT); i++) {
1961 if (clut->Params->nSamples[i] != clutPoints) {
1962 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT with different samples per dimension not suitable to be saved as LUT16");
1963 return FALSE;
1968 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number)cmsPipelineInputChannels(NewLUT))) return FALSE;
1969 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number)cmsPipelineOutputChannels(NewLUT))) return FALSE;
1970 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
1971 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
1973 if (MatMPE != NULL) {
1975 for (i = 0; i < 9; i++)
1977 if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
1980 else {
1982 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1983 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1984 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1985 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1986 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1987 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1988 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1989 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1990 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1993 // The prelinearization table
1994 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1996 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1997 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
1998 if (nTabSize > 0) {
2000 // The 3D CLUT.
2001 if (clut != NULL) {
2003 for (j=0; j < nTabSize; j++) {
2005 val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]);
2006 if (!_cmsWriteUInt8Number(io, val)) return FALSE;
2011 // The postlinearization table
2012 if (!Write8bitTables(self ->ContextID, io, NewLUT ->OutputChannels, PostMPE)) return FALSE;
2014 return TRUE;
2016 cmsUNUSED_PARAMETER(nItems);
2020 static
2021 void* Type_LUT8_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2023 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2025 cmsUNUSED_PARAMETER(n);
2026 cmsUNUSED_PARAMETER(self);
2029 static
2030 void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
2032 cmsPipelineFree((cmsPipeline*) Ptr);
2033 return;
2035 cmsUNUSED_PARAMETER(self);
2038 // ********************************************************************************
2039 // Type cmsSigLut16Type
2040 // ********************************************************************************
2042 // Read 16 bit tables as gamma functions
2043 static
2044 cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut,
2045 cmsUInt32Number nChannels, cmsUInt32Number nEntries)
2047 cmsUInt32Number i;
2048 cmsToneCurve* Tables[cmsMAXCHANNELS];
2050 // Maybe an empty table? (this is a lcms extension)
2051 if (nEntries <= 0) return TRUE;
2053 // Check for malicious profiles
2054 if (nEntries < 2) return FALSE;
2055 if (nChannels > cmsMAXCHANNELS) return FALSE;
2057 // Init table to zero
2058 memset(Tables, 0, sizeof(Tables));
2060 for (i=0; i < nChannels; i++) {
2062 Tables[i] = cmsBuildTabulatedToneCurve16(ContextID, nEntries, NULL);
2063 if (Tables[i] == NULL) goto Error;
2065 if (!_cmsReadUInt16Array(io, nEntries, Tables[i]->Table16)) goto Error;
2069 // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code)
2070 if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables)))
2071 goto Error;
2073 for (i=0; i < nChannels; i++)
2074 cmsFreeToneCurve(Tables[i]);
2076 return TRUE;
2078 Error:
2079 for (i=0; i < nChannels; i++) {
2080 if (Tables[i]) cmsFreeToneCurve(Tables[i]);
2083 return FALSE;
2086 static
2087 cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
2089 cmsUInt32Number j;
2090 cmsUInt32Number i;
2091 cmsUInt16Number val;
2092 cmsUInt32Number nEntries;
2094 _cmsAssert(Tables != NULL);
2096 for (i=0; i < Tables ->nCurves; i++) {
2098 nEntries = Tables->TheCurves[i]->nEntries;
2100 for (j=0; j < nEntries; j++) {
2102 val = Tables->TheCurves[i]->Table16[j];
2103 if (!_cmsWriteUInt16Number(io, val)) return FALSE;
2106 return TRUE;
2108 cmsUNUSED_PARAMETER(ContextID);
2111 static
2112 void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2114 cmsUInt8Number InputChannels, OutputChannels, CLUTpoints;
2115 cmsPipeline* NewLUT = NULL;
2116 cmsUInt32Number nTabSize;
2117 cmsFloat64Number Matrix[3*3];
2118 cmsUInt16Number InputEntries, OutputEntries;
2120 *nItems = 0;
2122 if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL;
2123 if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL;
2124 if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum
2126 // Padding
2127 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2129 // Do some checking
2130 if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error;
2131 if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
2133 // Allocates an empty LUT
2134 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
2135 if (NewLUT == NULL) goto Error;
2137 // Read the Matrix
2138 if (!_cmsRead15Fixed16Number(io, &Matrix[0])) goto Error;
2139 if (!_cmsRead15Fixed16Number(io, &Matrix[1])) goto Error;
2140 if (!_cmsRead15Fixed16Number(io, &Matrix[2])) goto Error;
2141 if (!_cmsRead15Fixed16Number(io, &Matrix[3])) goto Error;
2142 if (!_cmsRead15Fixed16Number(io, &Matrix[4])) goto Error;
2143 if (!_cmsRead15Fixed16Number(io, &Matrix[5])) goto Error;
2144 if (!_cmsRead15Fixed16Number(io, &Matrix[6])) goto Error;
2145 if (!_cmsRead15Fixed16Number(io, &Matrix[7])) goto Error;
2146 if (!_cmsRead15Fixed16Number(io, &Matrix[8])) goto Error;
2149 // Only operates on 3 channels
2150 if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) {
2152 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL)))
2153 goto Error;
2156 if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error;
2157 if (!_cmsReadUInt16Number(io, &OutputEntries)) goto Error;
2159 if (InputEntries > 0x7FFF || OutputEntries > 0x7FFF) goto Error;
2160 if (CLUTpoints == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
2162 // Get input tables
2163 if (!Read16bitTables(self ->ContextID, io, NewLUT, InputChannels, InputEntries)) goto Error;
2165 // Get 3D CLUT
2166 nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels);
2167 if (nTabSize == (cmsUInt32Number) -1) goto Error;
2168 if (nTabSize > 0) {
2170 cmsUInt16Number *T;
2172 T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number));
2173 if (T == NULL) goto Error;
2175 if (!_cmsReadUInt16Array(io, nTabSize, T)) {
2176 _cmsFree(self ->ContextID, T);
2177 goto Error;
2180 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
2181 _cmsFree(self ->ContextID, T);
2182 goto Error;
2184 _cmsFree(self ->ContextID, T);
2188 // Get output tables
2189 if (!Read16bitTables(self ->ContextID, io, NewLUT, OutputChannels, OutputEntries)) goto Error;
2191 *nItems = 1;
2192 return NewLUT;
2194 Error:
2195 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
2196 return NULL;
2198 cmsUNUSED_PARAMETER(SizeOfTag);
2201 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2202 // Some empty defaults are created for missing parts
2204 static
2205 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2207 cmsUInt32Number nTabSize;
2208 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2209 cmsStage* mpe;
2210 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2211 _cmsStageMatrixData* MatMPE = NULL;
2212 _cmsStageCLutData* clut = NULL;
2213 cmsUInt32Number i, InputChannels, OutputChannels, clutPoints;
2215 // Disassemble the LUT into components.
2216 mpe = NewLUT -> Elements;
2217 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2219 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
2220 if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE;
2221 mpe = mpe -> Next;
2225 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2226 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2227 mpe = mpe -> Next;
2230 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
2231 clut = (_cmsStageCLutData*) mpe -> Data;
2232 mpe = mpe ->Next;
2235 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2236 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2237 mpe = mpe -> Next;
2240 // That should be all
2241 if (mpe != NULL) {
2242 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
2243 return FALSE;
2246 InputChannels = cmsPipelineInputChannels(NewLUT);
2247 OutputChannels = cmsPipelineOutputChannels(NewLUT);
2249 if (clut == NULL)
2250 clutPoints = 0;
2251 else {
2252 // Lut16 only allows same CLUT points in all dimensions
2253 clutPoints = clut->Params->nSamples[0];
2254 for (i = 1; i < InputChannels; i++) {
2255 if (clut->Params->nSamples[i] != clutPoints) {
2256 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT with different samples per dimension not suitable to be saved as LUT16");
2257 return FALSE;
2262 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
2263 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
2264 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
2265 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
2267 if (MatMPE != NULL) {
2269 for (i = 0; i < 9; i++)
2271 if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
2275 else {
2277 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2278 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2279 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2280 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2281 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2282 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2283 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2284 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2285 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2289 if (PreMPE != NULL) {
2290 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
2291 } else {
2292 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2295 if (PostMPE != NULL) {
2296 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE;
2297 } else {
2298 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2302 // The prelinearization table
2304 if (PreMPE != NULL) {
2305 if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE;
2307 else {
2308 for (i=0; i < InputChannels; i++) {
2310 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2311 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2315 nTabSize = uipow(OutputChannels, clutPoints, InputChannels);
2316 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
2317 if (nTabSize > 0) {
2318 // The 3D CLUT.
2319 if (clut != NULL) {
2320 if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE;
2324 // The postlinearization table
2325 if (PostMPE != NULL) {
2326 if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE;
2328 else {
2329 for (i=0; i < OutputChannels; i++) {
2331 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2332 if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE;
2336 return TRUE;
2338 cmsUNUSED_PARAMETER(nItems);
2341 static
2342 void* Type_LUT16_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2344 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2346 cmsUNUSED_PARAMETER(n);
2347 cmsUNUSED_PARAMETER(self);
2350 static
2351 void Type_LUT16_Free(struct _cms_typehandler_struct* self, void* Ptr)
2353 cmsPipelineFree((cmsPipeline*) Ptr);
2354 return;
2356 cmsUNUSED_PARAMETER(self);
2360 // ********************************************************************************
2361 // Type cmsSigLutAToBType
2362 // ********************************************************************************
2365 // V4 stuff. Read matrix for LutAtoB and LutBtoA
2367 static
2368 cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset)
2370 cmsFloat64Number dMat[3*3];
2371 cmsFloat64Number dOff[3];
2372 cmsStage* Mat;
2374 // Go to address
2375 if (!io -> Seek(io, Offset)) return NULL;
2377 // Read the Matrix
2378 if (!_cmsRead15Fixed16Number(io, &dMat[0])) return NULL;
2379 if (!_cmsRead15Fixed16Number(io, &dMat[1])) return NULL;
2380 if (!_cmsRead15Fixed16Number(io, &dMat[2])) return NULL;
2381 if (!_cmsRead15Fixed16Number(io, &dMat[3])) return NULL;
2382 if (!_cmsRead15Fixed16Number(io, &dMat[4])) return NULL;
2383 if (!_cmsRead15Fixed16Number(io, &dMat[5])) return NULL;
2384 if (!_cmsRead15Fixed16Number(io, &dMat[6])) return NULL;
2385 if (!_cmsRead15Fixed16Number(io, &dMat[7])) return NULL;
2386 if (!_cmsRead15Fixed16Number(io, &dMat[8])) return NULL;
2388 if (!_cmsRead15Fixed16Number(io, &dOff[0])) return NULL;
2389 if (!_cmsRead15Fixed16Number(io, &dOff[1])) return NULL;
2390 if (!_cmsRead15Fixed16Number(io, &dOff[2])) return NULL;
2392 Mat = cmsStageAllocMatrix(self ->ContextID, 3, 3, dMat, dOff);
2394 return Mat;
2400 // V4 stuff. Read CLUT part for LutAtoB and LutBtoA
2402 static
2403 cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
2404 cmsUInt32Number Offset, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels)
2406 cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2407 cmsUInt32Number GridPoints[cmsMAXCHANNELS], i;
2408 cmsUInt8Number Precision;
2409 cmsStage* CLUT;
2410 _cmsStageCLutData* Data;
2412 if (!io -> Seek(io, Offset)) return NULL;
2413 if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL;
2416 for (i=0; i < cmsMAXCHANNELS; i++) {
2418 if (gridPoints8[i] == 1) return NULL; // Impossible value, 0 for no CLUT and then 2 at least
2419 GridPoints[i] = gridPoints8[i];
2422 if (!_cmsReadUInt8Number(io, &Precision)) return NULL;
2424 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2425 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2426 if (!_cmsReadUInt8Number(io, NULL)) return NULL;
2428 CLUT = cmsStageAllocCLut16bitGranular(self ->ContextID, GridPoints, InputChannels, OutputChannels, NULL);
2429 if (CLUT == NULL) return NULL;
2431 Data = (_cmsStageCLutData*) CLUT ->Data;
2433 // Precision can be 1 or 2 bytes
2434 if (Precision == 1) {
2436 cmsUInt8Number v;
2438 for (i=0; i < Data ->nEntries; i++) {
2440 if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) {
2441 cmsStageFree(CLUT);
2442 return NULL;
2444 Data ->Tab.T[i] = FROM_8_TO_16(v);
2448 else
2449 if (Precision == 2) {
2451 if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) {
2452 cmsStageFree(CLUT);
2453 return NULL;
2456 else {
2457 cmsStageFree(CLUT);
2458 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2459 return NULL;
2462 return CLUT;
2465 static
2466 cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
2468 cmsTagTypeSignature BaseType;
2469 cmsUInt32Number nItems;
2471 BaseType = _cmsReadTypeBase(io);
2472 switch (BaseType) {
2474 case cmsSigCurveType:
2475 return (cmsToneCurve*) Type_Curve_Read(self, io, &nItems, 0);
2477 case cmsSigParametricCurveType:
2478 return (cmsToneCurve*) Type_ParametricCurve_Read(self, io, &nItems, 0);
2480 default:
2482 char String[5];
2484 _cmsTagSignature2String(String, (cmsTagSignature) BaseType);
2485 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2487 return NULL;
2492 // Read a set of curves from specific offset
2493 static
2494 cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves)
2496 cmsToneCurve* Curves[cmsMAXCHANNELS];
2497 cmsUInt32Number i;
2498 cmsStage* Lin = NULL;
2500 if (nCurves > cmsMAXCHANNELS) return FALSE;
2502 if (!io -> Seek(io, Offset)) return FALSE;
2504 for (i=0; i < nCurves; i++)
2505 Curves[i] = NULL;
2507 for (i=0; i < nCurves; i++) {
2509 Curves[i] = ReadEmbeddedCurve(self, io);
2510 if (Curves[i] == NULL) goto Error;
2511 if (!_cmsReadAlignment(io)) goto Error;
2515 Lin = cmsStageAllocToneCurves(self ->ContextID, nCurves, Curves);
2517 Error:
2518 for (i=0; i < nCurves; i++)
2519 cmsFreeToneCurve(Curves[i]);
2521 return Lin;
2525 // LutAtoB type
2527 // This structure represents a colour transform. The type contains up to five processing
2528 // elements which are stored in the AtoBTag tag in the following order: a set of one
2529 // dimensional curves, a 3 by 3 matrix with offset terms, a set of one dimensional curves,
2530 // a multidimensional lookup table, and a set of one dimensional output curves.
2531 // Data are processed using these elements via the following sequence:
2533 //("A" curves) -> (multidimensional lookup table - CLUT) -> ("M" curves) -> (matrix) -> ("B" curves).
2536 It is possible to use any or all of these processing elements. At least one processing element
2537 must be included.Only the following combinations are allowed:
2540 M - Matrix - B
2541 A - CLUT - B
2542 A - CLUT - M - Matrix - B
2546 static
2547 void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2549 cmsUInt32Number BaseOffset;
2550 cmsUInt8Number inputChan; // Number of input channels
2551 cmsUInt8Number outputChan; // Number of output channels
2552 cmsUInt32Number offsetB; // Offset to first "B" curve
2553 cmsUInt32Number offsetMat; // Offset to matrix
2554 cmsUInt32Number offsetM; // Offset to first "M" curve
2555 cmsUInt32Number offsetC; // Offset to CLUT
2556 cmsUInt32Number offsetA; // Offset to first "A" curve
2557 cmsPipeline* NewLUT = NULL;
2560 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2562 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2563 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2565 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2567 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2568 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2569 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2570 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2571 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2573 if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
2574 if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
2576 // Allocates an empty LUT
2577 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2578 if (NewLUT == NULL) return NULL;
2580 if (offsetA!= 0) {
2581 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan)))
2582 goto Error;
2585 if (offsetC != 0) {
2586 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2587 goto Error;
2590 if (offsetM != 0) {
2591 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan)))
2592 goto Error;
2595 if (offsetMat != 0) {
2596 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2597 goto Error;
2600 if (offsetB != 0) {
2601 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
2602 goto Error;
2605 *nItems = 1;
2606 return NewLUT;
2607 Error:
2608 cmsPipelineFree(NewLUT);
2609 return NULL;
2611 cmsUNUSED_PARAMETER(SizeOfTag);
2614 // Write a set of curves
2615 static
2616 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2618 cmsUInt32Number i, n;
2620 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2622 n = mpe->InputChannels * mpe->OutputChannels;
2624 // Write the Matrix
2625 for (i = 0; i < n; i++)
2627 if (!_cmsWrite15Fixed16Number(io, m->Double[i])) return FALSE;
2630 if (m->Offset != NULL) {
2632 for (i = 0; i < mpe->OutputChannels; i++)
2634 if (!_cmsWrite15Fixed16Number(io, m->Offset[i])) return FALSE;
2637 else {
2638 for (i = 0; i < mpe->OutputChannels; i++)
2640 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2645 return TRUE;
2647 cmsUNUSED_PARAMETER(self);
2651 // Write a set of curves
2652 static
2653 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2655 cmsUInt32Number i, n;
2656 cmsTagTypeSignature CurrentType;
2657 cmsToneCurve** Curves;
2660 n = cmsStageOutputChannels(mpe);
2661 Curves = _cmsStageGetPtrToCurveSet(mpe);
2663 for (i=0; i < n; i++) {
2665 // If this is a table-based curve, use curve type even on V4
2666 CurrentType = Type;
2668 if ((Curves[i] ->nSegments == 0)||
2669 ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) )
2670 CurrentType = cmsSigCurveType;
2671 else
2672 if (Curves[i] ->Segments[0].Type < 0)
2673 CurrentType = cmsSigCurveType;
2675 if (!_cmsWriteTypeBase(io, CurrentType)) return FALSE;
2677 switch (CurrentType) {
2679 case cmsSigCurveType:
2680 if (!Type_Curve_Write(self, io, Curves[i], 1)) return FALSE;
2681 break;
2683 case cmsSigParametricCurveType:
2684 if (!Type_ParametricCurve_Write(self, io, Curves[i], 1)) return FALSE;
2685 break;
2687 default:
2689 char String[5];
2691 _cmsTagSignature2String(String, (cmsTagSignature) Type);
2692 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String);
2694 return FALSE;
2697 if (!_cmsWriteAlignment(io)) return FALSE;
2701 return TRUE;
2705 static
2706 cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt8Number Precision, cmsStage* mpe)
2708 cmsUInt8Number gridPoints[cmsMAXCHANNELS]; // Number of grid points in each dimension.
2709 cmsUInt32Number i;
2710 _cmsStageCLutData* CLUT = ( _cmsStageCLutData*) mpe -> Data;
2712 if (CLUT ->HasFloatValues) {
2713 cmsSignalError(self ->ContextID, cmsERROR_NOT_SUITABLE, "Cannot save floating point data, CLUT are 8 or 16 bit only");
2714 return FALSE;
2717 memset(gridPoints, 0, sizeof(gridPoints));
2718 for (i=0; i < (cmsUInt32Number) CLUT ->Params ->nInputs; i++)
2719 gridPoints[i] = (cmsUInt8Number) CLUT ->Params ->nSamples[i];
2721 if (!io -> Write(io, cmsMAXCHANNELS*sizeof(cmsUInt8Number), gridPoints)) return FALSE;
2723 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) Precision)) return FALSE;
2724 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2725 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2726 if (!_cmsWriteUInt8Number(io, 0)) return FALSE;
2728 // Precision can be 1 or 2 bytes
2729 if (Precision == 1) {
2731 for (i=0; i < CLUT->nEntries; i++) {
2733 if (!_cmsWriteUInt8Number(io, FROM_16_TO_8(CLUT->Tab.T[i]))) return FALSE;
2736 else
2737 if (Precision == 2) {
2739 if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE;
2741 else {
2742 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
2743 return FALSE;
2746 if (!_cmsWriteAlignment(io)) return FALSE;
2748 return TRUE;
2754 static
2755 cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2757 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2758 cmsUInt32Number inputChan, outputChan;
2759 cmsStage *A = NULL, *B = NULL, *M = NULL;
2760 cmsStage * Matrix = NULL;
2761 cmsStage * CLUT = NULL;
2762 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2763 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2765 // Get the base for all offsets
2766 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2768 if (Lut ->Elements != NULL)
2769 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2770 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &M, &Matrix, &B))
2771 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &A, &CLUT, &B))
2772 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType,
2773 cmsSigMatrixElemType, cmsSigCurveSetElemType, &A, &CLUT, &M, &Matrix, &B)) {
2775 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutAToB");
2776 return FALSE;
2779 // Get input, output channels
2780 inputChan = cmsPipelineInputChannels(Lut);
2781 outputChan = cmsPipelineOutputChannels(Lut);
2783 // Write channel count
2784 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2785 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2786 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2788 // Keep directory to be filled latter
2789 DirectoryPos = io ->Tell(io);
2791 // Write the directory
2792 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2793 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2794 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2795 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2796 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2798 if (A != NULL) {
2800 offsetA = io ->Tell(io) - BaseOffset;
2801 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2804 if (CLUT != NULL) {
2805 offsetC = io ->Tell(io) - BaseOffset;
2806 if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE;
2809 if (M != NULL) {
2811 offsetM = io ->Tell(io) - BaseOffset;
2812 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2815 if (Matrix != NULL) {
2816 offsetMat = io ->Tell(io) - BaseOffset;
2817 if (!WriteMatrix(self, io, Matrix)) return FALSE;
2820 if (B != NULL) {
2822 offsetB = io ->Tell(io) - BaseOffset;
2823 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
2826 CurrentPos = io ->Tell(io);
2828 if (!io ->Seek(io, DirectoryPos)) return FALSE;
2830 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
2831 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
2832 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
2833 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
2834 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
2836 if (!io ->Seek(io, CurrentPos)) return FALSE;
2838 return TRUE;
2840 cmsUNUSED_PARAMETER(nItems);
2844 static
2845 void* Type_LUTA2B_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
2847 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
2849 cmsUNUSED_PARAMETER(n);
2850 cmsUNUSED_PARAMETER(self);
2853 static
2854 void Type_LUTA2B_Free(struct _cms_typehandler_struct* self, void* Ptr)
2856 cmsPipelineFree((cmsPipeline*) Ptr);
2857 return;
2859 cmsUNUSED_PARAMETER(self);
2863 // LutBToA type
2865 static
2866 void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
2868 cmsUInt8Number inputChan; // Number of input channels
2869 cmsUInt8Number outputChan; // Number of output channels
2870 cmsUInt32Number BaseOffset; // Actual position in file
2871 cmsUInt32Number offsetB; // Offset to first "B" curve
2872 cmsUInt32Number offsetMat; // Offset to matrix
2873 cmsUInt32Number offsetM; // Offset to first "M" curve
2874 cmsUInt32Number offsetC; // Offset to CLUT
2875 cmsUInt32Number offsetA; // Offset to first "A" curve
2876 cmsPipeline* NewLUT = NULL;
2879 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2881 if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
2882 if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
2884 if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
2885 if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
2887 // Padding
2888 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
2890 if (!_cmsReadUInt32Number(io, &offsetB)) return NULL;
2891 if (!_cmsReadUInt32Number(io, &offsetMat)) return NULL;
2892 if (!_cmsReadUInt32Number(io, &offsetM)) return NULL;
2893 if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
2894 if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
2896 // Allocates an empty LUT
2897 NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
2898 if (NewLUT == NULL) return NULL;
2900 if (offsetB != 0) {
2901 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan)))
2902 goto Error;
2905 if (offsetMat != 0) {
2906 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat)))
2907 goto Error;
2910 if (offsetM != 0) {
2911 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan)))
2912 goto Error;
2915 if (offsetC != 0) {
2916 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan)))
2917 goto Error;
2920 if (offsetA!= 0) {
2921 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan)))
2922 goto Error;
2925 *nItems = 1;
2926 return NewLUT;
2927 Error:
2928 cmsPipelineFree(NewLUT);
2929 return NULL;
2931 cmsUNUSED_PARAMETER(SizeOfTag);
2937 B - Matrix - M
2938 B - CLUT - A
2939 B - Matrix - M - CLUT - A
2942 static
2943 cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2945 cmsPipeline* Lut = (cmsPipeline*) Ptr;
2946 cmsUInt32Number inputChan, outputChan;
2947 cmsStage *A = NULL, *B = NULL, *M = NULL;
2948 cmsStage *Matrix = NULL;
2949 cmsStage *CLUT = NULL;
2950 cmsUInt32Number offsetB = 0, offsetMat = 0, offsetM = 0, offsetC = 0, offsetA = 0;
2951 cmsUInt32Number BaseOffset, DirectoryPos, CurrentPos;
2954 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
2956 if (!cmsPipelineCheckAndRetreiveStages(Lut, 1, cmsSigCurveSetElemType, &B))
2957 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, &B, &Matrix, &M))
2958 if (!cmsPipelineCheckAndRetreiveStages(Lut, 3, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &CLUT, &A))
2959 if (!cmsPipelineCheckAndRetreiveStages(Lut, 5, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
2960 cmsSigCLutElemType, cmsSigCurveSetElemType, &B, &Matrix, &M, &CLUT, &A)) {
2961 cmsSignalError(self->ContextID, cmsERROR_NOT_SUITABLE, "LUT is not suitable to be saved as LutBToA");
2962 return FALSE;
2965 inputChan = cmsPipelineInputChannels(Lut);
2966 outputChan = cmsPipelineOutputChannels(Lut);
2968 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) inputChan)) return FALSE;
2969 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) outputChan)) return FALSE;
2970 if (!_cmsWriteUInt16Number(io, 0)) return FALSE;
2972 DirectoryPos = io ->Tell(io);
2974 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2975 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2976 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2977 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2978 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
2980 if (A != NULL) {
2982 offsetA = io ->Tell(io) - BaseOffset;
2983 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, A)) return FALSE;
2986 if (CLUT != NULL) {
2987 offsetC = io ->Tell(io) - BaseOffset;
2988 if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE;
2991 if (M != NULL) {
2993 offsetM = io ->Tell(io) - BaseOffset;
2994 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, M)) return FALSE;
2997 if (Matrix != NULL) {
2998 offsetMat = io ->Tell(io) - BaseOffset;
2999 if (!WriteMatrix(self, io, Matrix)) return FALSE;
3002 if (B != NULL) {
3004 offsetB = io ->Tell(io) - BaseOffset;
3005 if (!WriteSetOfCurves(self, io, cmsSigParametricCurveType, B)) return FALSE;
3008 CurrentPos = io ->Tell(io);
3010 if (!io ->Seek(io, DirectoryPos)) return FALSE;
3012 if (!_cmsWriteUInt32Number(io, offsetB)) return FALSE;
3013 if (!_cmsWriteUInt32Number(io, offsetMat)) return FALSE;
3014 if (!_cmsWriteUInt32Number(io, offsetM)) return FALSE;
3015 if (!_cmsWriteUInt32Number(io, offsetC)) return FALSE;
3016 if (!_cmsWriteUInt32Number(io, offsetA)) return FALSE;
3018 if (!io ->Seek(io, CurrentPos)) return FALSE;
3020 return TRUE;
3022 cmsUNUSED_PARAMETER(nItems);
3027 static
3028 void* Type_LUTB2A_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3030 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
3032 cmsUNUSED_PARAMETER(n);
3033 cmsUNUSED_PARAMETER(self);
3036 static
3037 void Type_LUTB2A_Free(struct _cms_typehandler_struct* self, void* Ptr)
3039 cmsPipelineFree((cmsPipeline*) Ptr);
3040 return;
3042 cmsUNUSED_PARAMETER(self);
3047 // ********************************************************************************
3048 // Type cmsSigColorantTableType
3049 // ********************************************************************************
3051 The purpose of this tag is to identify the colorants used in the profile by a
3052 unique name and set of XYZ or L*a*b* values to give the colorant an unambiguous
3053 value. The first colorant listed is the colorant of the first device channel of
3054 a lut tag. The second colorant listed is the colorant of the second device channel
3055 of a lut tag, and so on.
3058 static
3059 void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3061 cmsUInt32Number i, Count;
3062 cmsNAMEDCOLORLIST* List;
3063 char Name[34];
3064 cmsUInt16Number PCS[3];
3067 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3069 if (Count > cmsMAXCHANNELS) {
3070 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many colorants '%d'", Count);
3071 return NULL;
3074 List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
3075 if (List == NULL)
3076 return NULL;
3078 for (i=0; i < Count; i++) {
3080 if (io ->Read(io, Name, 32, 1) != 1) goto Error;
3081 Name[32] = 0;
3083 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3085 if (!cmsAppendNamedColor(List, Name, PCS, NULL)) goto Error;
3089 *nItems = 1;
3090 return List;
3092 Error:
3093 *nItems = 0;
3094 cmsFreeNamedColorList(List);
3095 return NULL;
3097 cmsUNUSED_PARAMETER(SizeOfTag);
3102 // Saves a colorant table. It is using the named color structure for simplicity sake
3103 static
3104 cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3106 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3107 cmsUInt32Number i, nColors;
3109 nColors = cmsNamedColorCount(NamedColorList);
3111 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3113 for (i=0; i < nColors; i++) {
3115 char root[cmsMAX_PATH];
3116 cmsUInt16Number PCS[3];
3118 memset(root, 0, sizeof(root));
3120 if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
3121 root[32] = 0;
3123 if (!io ->Write(io, 32, root)) return FALSE;
3124 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3127 return TRUE;
3129 cmsUNUSED_PARAMETER(nItems);
3130 cmsUNUSED_PARAMETER(self);
3134 static
3135 void* Type_ColorantTable_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3137 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3138 return (void*) cmsDupNamedColorList(nc);
3140 cmsUNUSED_PARAMETER(n);
3141 cmsUNUSED_PARAMETER(self);
3145 static
3146 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3148 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3149 return;
3151 cmsUNUSED_PARAMETER(self);
3155 // ********************************************************************************
3156 // Type cmsSigNamedColor2Type
3157 // ********************************************************************************
3159 //The namedColor2Type is a count value and array of structures that provide color
3160 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3161 //device representation of the color are given. Both representations are 16-bit values.
3162 //The device representation corresponds to the header's 'color space of data' field.
3163 //This representation should be consistent with the 'number of device components'
3164 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3165 //The PCS representation corresponds to the header's PCS field. The PCS representation
3166 //is always provided. Color names are fixed-length, 32-byte fields including null
3167 //termination. In order to maintain maximum portability, it is strongly recommended
3168 //that special characters of the 7-bit ASCII set not be used.
3170 static
3171 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3173 cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
3174 cmsUInt32Number count; // Count of named colors
3175 cmsUInt32Number nDeviceCoords; // Num of device coordinates
3176 char prefix[32]; // Prefix for each color name
3177 char suffix[32]; // Suffix for each color name
3178 cmsNAMEDCOLORLIST* v;
3179 cmsUInt32Number i;
3182 *nItems = 0;
3183 if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
3184 if (!_cmsReadUInt32Number(io, &count)) return NULL;
3185 if (!_cmsReadUInt32Number(io, &nDeviceCoords)) return NULL;
3187 if (io -> Read(io, prefix, 32, 1) != 1) return NULL;
3188 if (io -> Read(io, suffix, 32, 1) != 1) return NULL;
3190 prefix[31] = suffix[31] = 0;
3192 v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
3193 if (v == NULL) {
3194 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
3195 return NULL;
3198 if (nDeviceCoords > cmsMAXCHANNELS) {
3199 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
3200 goto Error;
3202 for (i=0; i < count; i++) {
3204 cmsUInt16Number PCS[3];
3205 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3206 char Root[33];
3208 memset(Colorant, 0, sizeof(Colorant));
3209 if (io -> Read(io, Root, 32, 1) != 1) goto Error;
3210 Root[32] = 0; // To prevent exploits
3212 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3213 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3215 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3218 *nItems = 1;
3219 return (void*) v ;
3221 Error:
3222 cmsFreeNamedColorList(v);
3223 return NULL;
3225 cmsUNUSED_PARAMETER(SizeOfTag);
3229 // Saves a named color list into a named color profile
3230 static
3231 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3233 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3234 char prefix[33]; // Prefix for each color name
3235 char suffix[33]; // Suffix for each color name
3236 cmsUInt32Number i, nColors;
3238 nColors = cmsNamedColorCount(NamedColorList);
3240 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3241 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3242 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3244 memcpy(prefix, (const char*) NamedColorList->Prefix, sizeof(prefix));
3245 memcpy(suffix, (const char*) NamedColorList->Suffix, sizeof(suffix));
3247 suffix[32] = prefix[32] = 0;
3249 if (!io ->Write(io, 32, prefix)) return FALSE;
3250 if (!io ->Write(io, 32, suffix)) return FALSE;
3252 for (i=0; i < nColors; i++) {
3254 cmsUInt16Number PCS[3];
3255 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3256 char Root[cmsMAX_PATH];
3258 memset(Root, 0, sizeof(Root));
3259 memset(PCS, 0, sizeof(PCS));
3260 memset(Colorant, 0, sizeof(Colorant));
3262 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3263 Root[32] = 0;
3264 if (!io ->Write(io, 32 , Root)) return FALSE;
3265 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3266 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3269 return TRUE;
3271 cmsUNUSED_PARAMETER(nItems);
3272 cmsUNUSED_PARAMETER(self);
3275 static
3276 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3278 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3280 return (void*) cmsDupNamedColorList(nc);
3282 cmsUNUSED_PARAMETER(n);
3283 cmsUNUSED_PARAMETER(self);
3287 static
3288 void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr)
3290 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3291 return;
3293 cmsUNUSED_PARAMETER(self);
3297 // ********************************************************************************
3298 // Type cmsSigProfileSequenceDescType
3299 // ********************************************************************************
3301 // This type is an array of structures, each of which contains information from the
3302 // header fields and tags from the original profiles which were combined to create
3303 // the final profile. The order of the structures is the order in which the profiles
3304 // were combined and includes a structure for the final profile. This provides a
3305 // description of the profile sequence from source to destination,
3306 // typically used with the DeviceLink profile.
3308 static
3309 cmsBool ReadEmbeddedText(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU** mlu, cmsUInt32Number SizeOfTag)
3311 cmsTagTypeSignature BaseType;
3312 cmsUInt32Number nItems;
3314 BaseType = _cmsReadTypeBase(io);
3316 switch (BaseType) {
3318 case cmsSigTextType:
3319 if (*mlu) cmsMLUfree(*mlu);
3320 *mlu = (cmsMLU*)Type_Text_Read(self, io, &nItems, SizeOfTag);
3321 return (*mlu != NULL);
3323 case cmsSigTextDescriptionType:
3324 if (*mlu) cmsMLUfree(*mlu);
3325 *mlu = (cmsMLU*) Type_Text_Description_Read(self, io, &nItems, SizeOfTag);
3326 return (*mlu != NULL);
3329 TBD: Size is needed for MLU, and we have no idea on which is the available size
3332 case cmsSigMultiLocalizedUnicodeType:
3333 if (*mlu) cmsMLUfree(*mlu);
3334 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, SizeOfTag);
3335 return (*mlu != NULL);
3337 default: return FALSE;
3342 static
3343 void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3345 cmsSEQ* OutSeq;
3346 cmsUInt32Number i, Count;
3348 *nItems = 0;
3350 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3352 if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL;
3353 SizeOfTag -= sizeof(cmsUInt32Number);
3356 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3357 if (OutSeq == NULL) return NULL;
3359 OutSeq ->n = Count;
3361 // Get structures as well
3363 for (i=0; i < Count; i++) {
3365 cmsPSEQDESC* sec = &OutSeq -> seq[i];
3367 if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error;
3368 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3369 SizeOfTag -= sizeof(cmsUInt32Number);
3371 if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error;
3372 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3373 SizeOfTag -= sizeof(cmsUInt32Number);
3375 if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error;
3376 if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error;
3377 SizeOfTag -= sizeof(cmsUInt64Number);
3379 if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error;
3380 if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error;
3381 SizeOfTag -= sizeof(cmsUInt32Number);
3383 if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) goto Error;
3384 if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) goto Error;
3387 *nItems = 1;
3388 return OutSeq;
3390 Error:
3391 cmsFreeProfileSequenceDescription(OutSeq);
3392 return NULL;
3396 // Aux--Embed a text description type. It can be of type text description or multilocalized unicode
3397 // and it depends of the version number passed on cmsTagDescriptor structure instead of stack
3398 static
3399 cmsBool SaveDescription(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* Text)
3401 if (self ->ICCVersion < 0x4000000) {
3403 if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE;
3404 return Type_Text_Description_Write(self, io, Text, 1);
3406 else {
3407 if (!_cmsWriteTypeBase(io, cmsSigMultiLocalizedUnicodeType)) return FALSE;
3408 return Type_MLU_Write(self, io, Text, 1);
3413 static
3414 cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3416 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3417 cmsUInt32Number i;
3419 if (!_cmsWriteUInt32Number(io, Seq->n)) return FALSE;
3421 for (i=0; i < Seq ->n; i++) {
3423 cmsPSEQDESC* sec = &Seq -> seq[i];
3425 if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE;
3426 if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE;
3427 if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE;
3428 if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE;
3430 if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE;
3431 if (!SaveDescription(self, io, sec ->Model)) return FALSE;
3434 return TRUE;
3436 cmsUNUSED_PARAMETER(nItems);
3440 static
3441 void* Type_ProfileSequenceDesc_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3443 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3445 cmsUNUSED_PARAMETER(n);
3446 cmsUNUSED_PARAMETER(self);
3449 static
3450 void Type_ProfileSequenceDesc_Free(struct _cms_typehandler_struct* self, void* Ptr)
3452 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3453 return;
3455 cmsUNUSED_PARAMETER(self);
3459 // ********************************************************************************
3460 // Type cmsSigProfileSequenceIdType
3461 // ********************************************************************************
3463 In certain workflows using ICC Device Link Profiles, it is necessary to identify the
3464 original profiles that were combined to create the Device Link Profile.
3465 This type is an array of structures, each of which contains information for
3466 identification of a profile used in a sequence
3470 static
3471 cmsBool ReadSeqID(struct _cms_typehandler_struct* self,
3472 cmsIOHANDLER* io,
3473 void* Cargo,
3474 cmsUInt32Number n,
3475 cmsUInt32Number SizeOfTag)
3477 cmsSEQ* OutSeq = (cmsSEQ*) Cargo;
3478 cmsPSEQDESC* seq = &OutSeq ->seq[n];
3480 if (io -> Read(io, seq ->ProfileID.ID8, 16, 1) != 1) return FALSE;
3481 if (!ReadEmbeddedText(self, io, &seq ->Description, SizeOfTag)) return FALSE;
3483 return TRUE;
3488 static
3489 void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3491 cmsSEQ* OutSeq;
3492 cmsUInt32Number Count;
3493 cmsUInt32Number BaseOffset;
3495 *nItems = 0;
3497 // Get actual position as a basis for element offsets
3498 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3500 // Get table count
3501 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
3503 // Allocate an empty structure
3504 OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
3505 if (OutSeq == NULL) return NULL;
3508 // Read the position table
3509 if (!ReadPositionTable(self, io, Count, BaseOffset, OutSeq, ReadSeqID)) {
3511 cmsFreeProfileSequenceDescription(OutSeq);
3512 return NULL;
3515 // Success
3516 *nItems = 1;
3517 return OutSeq;
3519 cmsUNUSED_PARAMETER(SizeOfTag);
3523 static
3524 cmsBool WriteSeqID(struct _cms_typehandler_struct* self,
3525 cmsIOHANDLER* io,
3526 void* Cargo,
3527 cmsUInt32Number n,
3528 cmsUInt32Number SizeOfTag)
3530 cmsSEQ* Seq = (cmsSEQ*) Cargo;
3532 if (!io ->Write(io, 16, Seq ->seq[n].ProfileID.ID8)) return FALSE;
3534 // Store here the MLU
3535 if (!SaveDescription(self, io, Seq ->seq[n].Description)) return FALSE;
3537 return TRUE;
3539 cmsUNUSED_PARAMETER(SizeOfTag);
3542 static
3543 cmsBool Type_ProfileSequenceId_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3545 cmsSEQ* Seq = (cmsSEQ*) Ptr;
3546 cmsUInt32Number BaseOffset;
3548 // Keep the base offset
3549 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
3551 // This is the table count
3552 if (!_cmsWriteUInt32Number(io, Seq ->n)) return FALSE;
3554 // This is the position table and content
3555 if (!WritePositionTable(self, io, 0, Seq ->n, BaseOffset, Seq, WriteSeqID)) return FALSE;
3557 return TRUE;
3559 cmsUNUSED_PARAMETER(nItems);
3562 static
3563 void* Type_ProfileSequenceId_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3565 return (void*) cmsDupProfileSequenceDescription((cmsSEQ*) Ptr);
3567 cmsUNUSED_PARAMETER(n);
3568 cmsUNUSED_PARAMETER(self);
3571 static
3572 void Type_ProfileSequenceId_Free(struct _cms_typehandler_struct* self, void* Ptr)
3574 cmsFreeProfileSequenceDescription((cmsSEQ*) Ptr);
3575 return;
3577 cmsUNUSED_PARAMETER(self);
3581 // ********************************************************************************
3582 // Type cmsSigUcrBgType
3583 // ********************************************************************************
3585 This type contains curves representing the under color removal and black
3586 generation and a text string which is a general description of the method used
3587 for the ucr/bg.
3590 static
3591 void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3593 cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3594 cmsUInt32Number CountUcr, CountBg;
3595 cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
3596 char* ASCIIString;
3598 *nItems = 0;
3599 if (n == NULL) return NULL;
3601 // First curve is Under color removal
3603 if (SignedSizeOfTag < (cmsInt32Number) sizeof(cmsUInt32Number)) return NULL;
3604 if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL;
3605 SignedSizeOfTag -= sizeof(cmsUInt32Number);
3607 n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL);
3608 if (n ->Ucr == NULL) goto error;
3610 if (SignedSizeOfTag < (cmsInt32Number)(CountUcr * sizeof(cmsUInt16Number))) goto error;
3611 if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) goto error;
3613 SignedSizeOfTag -= CountUcr * sizeof(cmsUInt16Number);
3615 // Second curve is Black generation
3617 if (SignedSizeOfTag < (cmsInt32Number)sizeof(cmsUInt32Number)) goto error;
3618 if (!_cmsReadUInt32Number(io, &CountBg)) goto error;
3619 SignedSizeOfTag -= sizeof(cmsUInt32Number);
3621 n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL);
3622 if (n ->Bg == NULL) goto error;
3624 if (SignedSizeOfTag < (cmsInt32Number) (CountBg * sizeof(cmsUInt16Number))) goto error;
3625 if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) goto error;
3626 SignedSizeOfTag -= CountBg * sizeof(cmsUInt16Number);
3628 if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) goto error;
3630 // Now comes the text. The length is specified by the tag size
3631 n ->Desc = cmsMLUalloc(self ->ContextID, 1);
3632 if (n ->Desc == NULL) goto error;
3634 ASCIIString = (char*) _cmsMalloc(self ->ContextID, SignedSizeOfTag + 1);
3635 if (io->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number)SignedSizeOfTag)
3637 _cmsFree(self->ContextID, ASCIIString);
3638 goto error;
3641 ASCIIString[SignedSizeOfTag] = 0;
3642 cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString);
3643 _cmsFree(self ->ContextID, ASCIIString);
3645 *nItems = 1;
3646 return (void*) n;
3648 error:
3650 if (n->Ucr) cmsFreeToneCurve(n->Ucr);
3651 if (n->Bg) cmsFreeToneCurve(n->Bg);
3652 if (n->Desc) cmsMLUfree(n->Desc);
3653 _cmsFree(self->ContextID, n);
3654 *nItems = 0;
3655 return NULL;
3659 static
3660 cmsBool Type_UcrBg_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3662 cmsUcrBg* Value = (cmsUcrBg*) Ptr;
3663 cmsUInt32Number TextSize;
3664 char* Text;
3666 // First curve is Under color removal
3667 if (!_cmsWriteUInt32Number(io, Value ->Ucr ->nEntries)) return FALSE;
3668 if (!_cmsWriteUInt16Array(io, Value ->Ucr ->nEntries, Value ->Ucr ->Table16)) return FALSE;
3670 // Then black generation
3671 if (!_cmsWriteUInt32Number(io, Value ->Bg ->nEntries)) return FALSE;
3672 if (!_cmsWriteUInt16Array(io, Value ->Bg ->nEntries, Value ->Bg ->Table16)) return FALSE;
3674 // Now comes the text. The length is specified by the tag size
3675 TextSize = cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, NULL, 0);
3676 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3677 if (cmsMLUgetASCII(Value ->Desc, cmsNoLanguage, cmsNoCountry, Text, TextSize) != TextSize) return FALSE;
3679 if (!io ->Write(io, TextSize, Text)) return FALSE;
3680 _cmsFree(self ->ContextID, Text);
3682 return TRUE;
3684 cmsUNUSED_PARAMETER(nItems);
3687 static
3688 void* Type_UcrBg_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3690 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3691 cmsUcrBg* NewUcrBg = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg));
3693 if (NewUcrBg == NULL) return NULL;
3695 NewUcrBg ->Bg = cmsDupToneCurve(Src ->Bg);
3696 NewUcrBg ->Ucr = cmsDupToneCurve(Src ->Ucr);
3697 NewUcrBg ->Desc = cmsMLUdup(Src ->Desc);
3699 return (void*) NewUcrBg;
3701 cmsUNUSED_PARAMETER(n);
3704 static
3705 void Type_UcrBg_Free(struct _cms_typehandler_struct* self, void *Ptr)
3707 cmsUcrBg* Src = (cmsUcrBg*) Ptr;
3709 if (Src ->Ucr) cmsFreeToneCurve(Src ->Ucr);
3710 if (Src ->Bg) cmsFreeToneCurve(Src ->Bg);
3711 if (Src ->Desc) cmsMLUfree(Src ->Desc);
3713 _cmsFree(self ->ContextID, Ptr);
3716 // ********************************************************************************
3717 // Type cmsSigCrdInfoType
3718 // ********************************************************************************
3721 This type contains the PostScript product name to which this profile corresponds
3722 and the names of the companion CRDs. Recall that a single profile can generate
3723 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3724 country varies for each element:
3726 nm: PostScript product name
3727 #0: Rendering intent 0 CRD name
3728 #1: Rendering intent 1 CRD name
3729 #2: Rendering intent 2 CRD name
3730 #3: Rendering intent 3 CRD name
3735 // Auxiliary, read an string specified as count + string
3736 static
3737 cmsBool ReadCountAndString(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
3739 cmsUInt32Number Count;
3740 char* Text;
3742 if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
3744 if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
3746 if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
3747 if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
3749 Text = (char*) _cmsMalloc(self ->ContextID, Count+1);
3750 if (Text == NULL) return FALSE;
3752 if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
3753 _cmsFree(self ->ContextID, Text);
3754 return FALSE;
3757 Text[Count] = 0;
3759 cmsMLUsetASCII(mlu, "PS", Section, Text);
3760 _cmsFree(self ->ContextID, Text);
3762 *SizeOfTag -= (Count + sizeof(cmsUInt32Number));
3763 return TRUE;
3766 static
3767 cmsBool WriteCountAndString(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
3769 cmsUInt32Number TextSize;
3770 char* Text;
3772 TextSize = cmsMLUgetASCII(mlu, "PS", Section, NULL, 0);
3773 Text = (char*) _cmsMalloc(self ->ContextID, TextSize);
3775 if (!_cmsWriteUInt32Number(io, TextSize)) return FALSE;
3777 if (cmsMLUgetASCII(mlu, "PS", Section, Text, TextSize) == 0) return FALSE;
3779 if (!io ->Write(io, TextSize, Text)) return FALSE;
3780 _cmsFree(self ->ContextID, Text);
3782 return TRUE;
3785 static
3786 void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3788 cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5);
3790 *nItems = 0;
3791 if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "nm")) goto Error;
3792 if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#0")) goto Error;
3793 if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#1")) goto Error;
3794 if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#2")) goto Error;
3795 if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#3")) goto Error;
3797 *nItems = 1;
3798 return (void*) mlu;
3800 Error:
3801 cmsMLUfree(mlu);
3802 return NULL;
3806 static
3807 cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3810 cmsMLU* mlu = (cmsMLU*) Ptr;
3812 if (!WriteCountAndString(self, io, mlu, "nm")) goto Error;
3813 if (!WriteCountAndString(self, io, mlu, "#0")) goto Error;
3814 if (!WriteCountAndString(self, io, mlu, "#1")) goto Error;
3815 if (!WriteCountAndString(self, io, mlu, "#2")) goto Error;
3816 if (!WriteCountAndString(self, io, mlu, "#3")) goto Error;
3818 return TRUE;
3820 Error:
3821 return FALSE;
3823 cmsUNUSED_PARAMETER(nItems);
3827 static
3828 void* Type_CrdInfo_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3830 return (void*) cmsMLUdup((cmsMLU*) Ptr);
3832 cmsUNUSED_PARAMETER(n);
3833 cmsUNUSED_PARAMETER(self);
3836 static
3837 void Type_CrdInfo_Free(struct _cms_typehandler_struct* self, void *Ptr)
3839 cmsMLUfree((cmsMLU*) Ptr);
3840 return;
3842 cmsUNUSED_PARAMETER(self);
3845 // ********************************************************************************
3846 // Type cmsSigScreeningType
3847 // ********************************************************************************
3849 //The screeningType describes various screening parameters including screen
3850 //frequency, screening angle, and spot shape.
3852 static
3853 void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3855 cmsScreening* sc = NULL;
3856 cmsUInt32Number i;
3858 sc = (cmsScreening*) _cmsMallocZero(self ->ContextID, sizeof(cmsScreening));
3859 if (sc == NULL) return NULL;
3861 *nItems = 0;
3863 if (!_cmsReadUInt32Number(io, &sc ->Flag)) goto Error;
3864 if (!_cmsReadUInt32Number(io, &sc ->nChannels)) goto Error;
3866 if (sc ->nChannels > cmsMAXCHANNELS - 1)
3867 sc ->nChannels = cmsMAXCHANNELS - 1;
3869 for (i=0; i < sc ->nChannels; i++) {
3871 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].Frequency)) goto Error;
3872 if (!_cmsRead15Fixed16Number(io, &sc ->Channels[i].ScreenAngle)) goto Error;
3873 if (!_cmsReadUInt32Number(io, &sc ->Channels[i].SpotShape)) goto Error;
3877 *nItems = 1;
3879 return (void*) sc;
3881 Error:
3882 if (sc != NULL)
3883 _cmsFree(self ->ContextID, sc);
3885 return NULL;
3887 cmsUNUSED_PARAMETER(SizeOfTag);
3891 static
3892 cmsBool Type_Screening_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3894 cmsScreening* sc = (cmsScreening* ) Ptr;
3895 cmsUInt32Number i;
3897 if (!_cmsWriteUInt32Number(io, sc ->Flag)) return FALSE;
3898 if (!_cmsWriteUInt32Number(io, sc ->nChannels)) return FALSE;
3900 for (i=0; i < sc ->nChannels; i++) {
3902 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].Frequency)) return FALSE;
3903 if (!_cmsWrite15Fixed16Number(io, sc ->Channels[i].ScreenAngle)) return FALSE;
3904 if (!_cmsWriteUInt32Number(io, sc ->Channels[i].SpotShape)) return FALSE;
3907 return TRUE;
3909 cmsUNUSED_PARAMETER(nItems);
3910 cmsUNUSED_PARAMETER(self);
3914 static
3915 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3917 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3919 cmsUNUSED_PARAMETER(n);
3923 static
3924 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3926 _cmsFree(self ->ContextID, Ptr);
3929 // ********************************************************************************
3930 // Type cmsSigViewingConditionsType
3931 // ********************************************************************************
3933 //This type represents a set of viewing condition parameters including:
3934 //CIE 'absolute' illuminant white point tristimulus values and CIE 'absolute'
3935 //surround tristimulus values.
3937 static
3938 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3940 cmsICCViewingConditions* vc = NULL;
3942 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3943 if (vc == NULL) return NULL;
3945 *nItems = 0;
3947 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3948 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3949 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3951 *nItems = 1;
3953 return (void*) vc;
3955 Error:
3956 if (vc != NULL)
3957 _cmsFree(self ->ContextID, vc);
3959 return NULL;
3961 cmsUNUSED_PARAMETER(SizeOfTag);
3965 static
3966 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3968 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3970 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3971 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3972 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3974 return TRUE;
3976 cmsUNUSED_PARAMETER(nItems);
3977 cmsUNUSED_PARAMETER(self);
3981 static
3982 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3984 return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsICCViewingConditions));
3986 cmsUNUSED_PARAMETER(n);
3990 static
3991 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3993 _cmsFree(self ->ContextID, Ptr);
3997 // ********************************************************************************
3998 // Type cmsSigMultiProcessElementType
3999 // ********************************************************************************
4002 static
4003 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4005 return (void*) cmsStageDup((cmsStage*) Ptr);
4007 cmsUNUSED_PARAMETER(n);
4008 cmsUNUSED_PARAMETER(self);
4011 static
4012 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
4014 cmsStageFree((cmsStage*) Ptr);
4015 return;
4017 cmsUNUSED_PARAMETER(self);
4020 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
4021 // The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The
4022 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
4023 // specified either in terms of a formula, or by a sampled curve.
4026 // Read an embedded segmented curve
4027 static
4028 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
4030 cmsCurveSegSignature ElementSig;
4031 cmsUInt32Number i, j;
4032 cmsUInt16Number nSegments;
4033 cmsCurveSegment* Segments;
4034 cmsToneCurve* Curve;
4035 cmsFloat32Number PrevBreak = MINUS_INF; // - infinite
4037 // Take signature and channels for each element.
4038 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
4040 // That should be a segmented curve
4041 if (ElementSig != cmsSigSegmentedCurve) return NULL;
4043 if (!_cmsReadUInt32Number(io, NULL)) return NULL;
4044 if (!_cmsReadUInt16Number(io, &nSegments)) return NULL;
4045 if (!_cmsReadUInt16Number(io, NULL)) return NULL;
4047 if (nSegments < 1) return NULL;
4048 Segments = (cmsCurveSegment*) _cmsCalloc(self ->ContextID, nSegments, sizeof(cmsCurveSegment));
4049 if (Segments == NULL) return NULL;
4051 // Read breakpoints
4052 for (i=0; i < (cmsUInt32Number) nSegments - 1; i++) {
4054 Segments[i].x0 = PrevBreak;
4055 if (!_cmsReadFloat32Number(io, &Segments[i].x1)) goto Error;
4056 PrevBreak = Segments[i].x1;
4059 Segments[nSegments-1].x0 = PrevBreak;
4060 Segments[nSegments-1].x1 = PLUS_INF; // A big cmsFloat32Number number
4062 // Read segments
4063 for (i=0; i < nSegments; i++) {
4065 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) goto Error;
4066 if (!_cmsReadUInt32Number(io, NULL)) goto Error;
4068 switch (ElementSig) {
4070 case cmsSigFormulaCurveSeg: {
4072 cmsUInt16Number Type;
4073 cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
4075 if (!_cmsReadUInt16Number(io, &Type)) goto Error;
4076 if (!_cmsReadUInt16Number(io, NULL)) goto Error;
4078 Segments[i].Type = Type + 6;
4079 if (Type > 2) goto Error;
4081 for (j = 0; j < ParamsByType[Type]; j++) {
4083 cmsFloat32Number f;
4084 if (!_cmsReadFloat32Number(io, &f)) goto Error;
4085 Segments[i].Params[j] = f;
4088 break;
4091 case cmsSigSampledCurveSeg: {
4092 cmsUInt32Number Count;
4094 if (!_cmsReadUInt32Number(io, &Count)) goto Error;
4096 // The first point is implicit in the last stage, we allocate an extra note to be populated latter on
4097 Count++;
4098 Segments[i].nGridPoints = Count;
4099 Segments[i].SampledPoints = (cmsFloat32Number*)_cmsCalloc(self->ContextID, Count, sizeof(cmsFloat32Number));
4100 if (Segments[i].SampledPoints == NULL) goto Error;
4102 Segments[i].SampledPoints[0] = 0;
4103 for (j = 1; j < Count; j++) {
4104 if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error;
4107 break;
4109 default:
4111 char String[5];
4113 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4114 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String);
4116 goto Error;
4121 Curve = cmsBuildSegmentedToneCurve(self ->ContextID, nSegments, Segments);
4123 for (i=0; i < nSegments; i++) {
4124 if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
4126 _cmsFree(self ->ContextID, Segments);
4128 // Explore for missing implicit points
4129 for (i = 0; i < nSegments; i++) {
4131 // If sampled curve, fix it
4132 if (Curve->Segments[i].Type == 0) {
4134 Curve->Segments[i].SampledPoints[0] = cmsEvalToneCurveFloat(Curve, Curve->Segments[i].x0);
4138 return Curve;
4140 Error:
4141 if (Segments) {
4142 for (i=0; i < nSegments; i++) {
4143 if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
4145 _cmsFree(self ->ContextID, Segments);
4147 return NULL;
4151 static
4152 cmsBool ReadMPECurve(struct _cms_typehandler_struct* self,
4153 cmsIOHANDLER* io,
4154 void* Cargo,
4155 cmsUInt32Number n,
4156 cmsUInt32Number SizeOfTag)
4158 cmsToneCurve** GammaTables = ( cmsToneCurve**) Cargo;
4160 GammaTables[n] = ReadSegmentedCurve(self, io);
4161 return (GammaTables[n] != NULL);
4163 cmsUNUSED_PARAMETER(SizeOfTag);
4166 static
4167 void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4169 cmsStage* mpe = NULL;
4170 cmsUInt16Number InputChans, OutputChans;
4171 cmsUInt32Number i, BaseOffset;
4172 cmsToneCurve** GammaTables;
4174 *nItems = 0;
4176 // Get actual position as a basis for element offsets
4177 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4179 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4180 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4182 if (InputChans != OutputChans) return NULL;
4184 GammaTables = (cmsToneCurve**) _cmsCalloc(self ->ContextID, InputChans, sizeof(cmsToneCurve*));
4185 if (GammaTables == NULL) return NULL;
4187 if (ReadPositionTable(self, io, InputChans, BaseOffset, GammaTables, ReadMPECurve)) {
4189 mpe = cmsStageAllocToneCurves(self ->ContextID, InputChans, GammaTables);
4191 else {
4192 mpe = NULL;
4195 for (i=0; i < InputChans; i++) {
4196 if (GammaTables[i]) cmsFreeToneCurve(GammaTables[i]);
4199 _cmsFree(self ->ContextID, GammaTables);
4200 *nItems = (mpe != NULL) ? 1U : 0;
4201 return mpe;
4203 cmsUNUSED_PARAMETER(SizeOfTag);
4207 // Write a single segmented curve. NO CHECK IS PERFORMED ON VALIDITY
4208 static
4209 cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g)
4211 cmsUInt32Number i, j;
4212 cmsCurveSegment* Segments = g ->Segments;
4213 cmsUInt32Number nSegments = g ->nSegments;
4215 if (!_cmsWriteUInt32Number(io, cmsSigSegmentedCurve)) goto Error;
4216 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4217 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) nSegments)) goto Error;
4218 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4220 // Write the break-points
4221 for (i=0; i < nSegments - 1; i++) {
4222 if (!_cmsWriteFloat32Number(io, Segments[i].x1)) goto Error;
4225 // Write the segments
4226 for (i=0; i < g ->nSegments; i++) {
4228 cmsCurveSegment* ActualSeg = Segments + i;
4230 if (ActualSeg -> Type == 0) {
4232 // This is a sampled curve. First point is implicit in the ICC format, but not in our representation
4233 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error;
4234 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4235 if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints - 1)) goto Error;
4237 for (j=1; j < g ->Segments[i].nGridPoints; j++) {
4238 if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error;
4242 else {
4243 int Type;
4244 cmsUInt32Number ParamsByType[] = { 4, 5, 5 };
4246 // This is a formula-based
4247 if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigFormulaCurveSeg)) goto Error;
4248 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4250 // We only allow 1, 2 and 3 as types
4251 Type = ActualSeg ->Type - 6;
4252 if (Type > 2 || Type < 0) goto Error;
4254 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Type)) goto Error;
4255 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
4257 for (j=0; j < ParamsByType[Type]; j++) {
4258 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) ActualSeg ->Params[j])) goto Error;
4262 // It seems there is no need to align. Code is here, and for safety commented out
4263 // if (!_cmsWriteAlignment(io)) goto Error;
4266 return TRUE;
4268 Error:
4269 return FALSE;
4273 static
4274 cmsBool WriteMPECurve(struct _cms_typehandler_struct* self,
4275 cmsIOHANDLER* io,
4276 void* Cargo,
4277 cmsUInt32Number n,
4278 cmsUInt32Number SizeOfTag)
4280 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) Cargo;
4282 return WriteSegmentedCurve(io, Curves ->TheCurves[n]);
4284 cmsUNUSED_PARAMETER(SizeOfTag);
4285 cmsUNUSED_PARAMETER(self);
4288 // Write a curve, checking first for validity
4289 static
4290 cmsBool Type_MPEcurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4292 cmsUInt32Number BaseOffset;
4293 cmsStage* mpe = (cmsStage*) Ptr;
4294 _cmsStageToneCurvesData* Curves = (_cmsStageToneCurvesData*) mpe ->Data;
4296 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4298 // Write the header. Since those are curves, input and output channels are same
4299 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4300 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4302 if (!WritePositionTable(self, io, 0,
4303 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4306 return TRUE;
4308 cmsUNUSED_PARAMETER(nItems);
4313 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4314 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4315 // is organized as follows:
4316 // array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ]
4318 static
4319 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4321 cmsStage* mpe;
4322 cmsUInt16Number InputChans, OutputChans;
4323 cmsUInt32Number nElems, i;
4324 cmsFloat64Number* Matrix;
4325 cmsFloat64Number* Offsets;
4327 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4328 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4331 // Input and output chans may be ANY (up to 0xffff),
4332 // but we choose to limit to 16 channels for now
4333 if (InputChans >= cmsMAXCHANNELS) return NULL;
4334 if (OutputChans >= cmsMAXCHANNELS) return NULL;
4336 nElems = (cmsUInt32Number) InputChans * OutputChans;
4338 Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
4339 if (Matrix == NULL) return NULL;
4341 Offsets = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, OutputChans, sizeof(cmsFloat64Number));
4342 if (Offsets == NULL) {
4344 _cmsFree(self ->ContextID, Matrix);
4345 return NULL;
4348 for (i=0; i < nElems; i++) {
4350 cmsFloat32Number v;
4352 if (!_cmsReadFloat32Number(io, &v)) {
4353 _cmsFree(self ->ContextID, Matrix);
4354 _cmsFree(self ->ContextID, Offsets);
4355 return NULL;
4357 Matrix[i] = v;
4361 for (i=0; i < OutputChans; i++) {
4363 cmsFloat32Number v;
4365 if (!_cmsReadFloat32Number(io, &v)) {
4366 _cmsFree(self ->ContextID, Matrix);
4367 _cmsFree(self ->ContextID, Offsets);
4368 return NULL;
4370 Offsets[i] = v;
4374 mpe = cmsStageAllocMatrix(self ->ContextID, OutputChans, InputChans, Matrix, Offsets);
4375 _cmsFree(self ->ContextID, Matrix);
4376 _cmsFree(self ->ContextID, Offsets);
4378 *nItems = 1;
4380 return mpe;
4382 cmsUNUSED_PARAMETER(SizeOfTag);
4385 static
4386 cmsBool Type_MPEmatrix_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4388 cmsUInt32Number i, nElems;
4389 cmsStage* mpe = (cmsStage*) Ptr;
4390 _cmsStageMatrixData* Matrix = (_cmsStageMatrixData*) mpe ->Data;
4392 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4393 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4395 nElems = mpe ->InputChannels * mpe ->OutputChannels;
4397 for (i=0; i < nElems; i++) {
4398 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Double[i])) return FALSE;
4402 for (i=0; i < mpe ->OutputChannels; i++) {
4404 if (Matrix ->Offset == NULL) {
4406 if (!_cmsWriteFloat32Number(io, 0)) return FALSE;
4408 else {
4409 if (!_cmsWriteFloat32Number(io, (cmsFloat32Number) Matrix->Offset[i])) return FALSE;
4413 return TRUE;
4415 cmsUNUSED_PARAMETER(nItems);
4416 cmsUNUSED_PARAMETER(self);
4421 static
4422 void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4424 cmsStage* mpe = NULL;
4425 cmsUInt16Number InputChans, OutputChans;
4426 cmsUInt8Number Dimensions8[16];
4427 cmsUInt32Number i, nMaxGrids, GridPoints[MAX_INPUT_DIMENSIONS];
4428 _cmsStageCLutData* clut;
4430 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4431 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4433 if (InputChans == 0) goto Error;
4434 if (OutputChans == 0) goto Error;
4436 if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
4437 goto Error;
4439 // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
4440 nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? (cmsUInt32Number) MAX_INPUT_DIMENSIONS : InputChans;
4442 for (i = 0; i < nMaxGrids; i++) {
4443 if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
4444 GridPoints[i] = (cmsUInt32Number)Dimensions8[i];
4447 // Allocate the true CLUT
4448 mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
4449 if (mpe == NULL) goto Error;
4451 // Read and sanitize the data
4452 clut = (_cmsStageCLutData*) mpe ->Data;
4453 for (i=0; i < clut ->nEntries; i++) {
4455 if (!_cmsReadFloat32Number(io, &clut->Tab.TFloat[i])) goto Error;
4458 *nItems = 1;
4459 return mpe;
4461 Error:
4462 *nItems = 0;
4463 if (mpe != NULL) cmsStageFree(mpe);
4464 return NULL;
4466 cmsUNUSED_PARAMETER(SizeOfTag);
4469 // Write a CLUT in floating point
4470 static
4471 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4473 cmsUInt8Number Dimensions8[16]; // 16 because the spec says 16 and not max number of channels
4474 cmsUInt32Number i;
4475 cmsStage* mpe = (cmsStage*) Ptr;
4476 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4478 // Check for maximum number of channels supported by lcms
4479 if (mpe -> InputChannels > MAX_INPUT_DIMENSIONS) return FALSE;
4481 // Only floats are supported in MPE
4482 if (clut ->HasFloatValues == FALSE) return FALSE;
4484 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4485 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4487 memset(Dimensions8, 0, sizeof(Dimensions8));
4489 for (i=0; i < mpe ->InputChannels; i++)
4490 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4492 if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4494 for (i=0; i < clut ->nEntries; i++) {
4496 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4499 return TRUE;
4501 cmsUNUSED_PARAMETER(nItems);
4502 cmsUNUSED_PARAMETER(self);
4507 // This is the list of built-in MPE types
4508 static _cmsTagTypeLinkedList SupportedMPEtypes[] = {
4510 {{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[1] }, // Ignore those elements for now
4511 {{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL, NULL, 0 }, &SupportedMPEtypes[2] }, // (That's what the spec says)
4513 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCurveSetElemType, MPEcurve), &SupportedMPEtypes[3] },
4514 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigMatrixElemType, MPEmatrix), &SupportedMPEtypes[4] },
4515 {TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
4518 _cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL };
4520 static
4521 cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
4522 cmsIOHANDLER* io,
4523 void* Cargo,
4524 cmsUInt32Number n,
4525 cmsUInt32Number SizeOfTag)
4527 cmsStageSignature ElementSig;
4528 cmsTagTypeHandler* TypeHandler;
4529 cmsUInt32Number nItems;
4530 cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
4531 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4534 // Take signature and channels for each element.
4535 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
4537 // The reserved placeholder
4538 if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
4540 // Read diverse MPE types
4541 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes);
4542 if (TypeHandler == NULL) {
4544 char String[5];
4546 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4548 // An unknown element was found.
4549 cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown MPE type '%s' found.", String);
4550 return FALSE;
4553 // If no read method, just ignore the element (valid for cmsSigBAcsElemType and cmsSigEAcsElemType)
4554 // Read the MPE. No size is given
4555 if (TypeHandler ->ReadPtr != NULL) {
4557 // This is a real element which should be read and processed
4558 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag)))
4559 return FALSE;
4562 return TRUE;
4564 cmsUNUSED_PARAMETER(SizeOfTag);
4565 cmsUNUSED_PARAMETER(n);
4569 // This is the main dispatcher for MPE
4570 static
4571 void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4573 cmsUInt16Number InputChans, OutputChans;
4574 cmsUInt32Number ElementCount;
4575 cmsPipeline *NewLUT = NULL;
4576 cmsUInt32Number BaseOffset;
4578 // Get actual position as a basis for element offsets
4579 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4581 // Read channels and element count
4582 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4583 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4585 if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL;
4586 if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL;
4588 // Allocates an empty LUT
4589 NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
4590 if (NewLUT == NULL) return NULL;
4592 if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error;
4593 if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error;
4595 // Check channel count
4596 if (InputChans != NewLUT->InputChannels ||
4597 OutputChans != NewLUT->OutputChannels) goto Error;
4599 // Success
4600 *nItems = 1;
4601 return NewLUT;
4603 // Error
4604 Error:
4605 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
4606 *nItems = 0;
4607 return NULL;
4609 cmsUNUSED_PARAMETER(SizeOfTag);
4614 // This one is a little bit more complex, so we don't use position tables this time.
4615 static
4616 cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4618 cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
4619 cmsUInt32Number inputChan, outputChan;
4620 cmsUInt32Number ElemCount;
4621 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
4622 cmsStageSignature ElementSig;
4623 cmsPipeline* Lut = (cmsPipeline*) Ptr;
4624 cmsStage* Elem = Lut ->Elements;
4625 cmsTagTypeHandler* TypeHandler;
4626 _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
4628 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4630 inputChan = cmsPipelineInputChannels(Lut);
4631 outputChan = cmsPipelineOutputChannels(Lut);
4632 ElemCount = cmsPipelineStageCount(Lut);
4634 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
4635 if (ElementOffsets == NULL) goto Error;
4637 ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number));
4638 if (ElementSizes == NULL) goto Error;
4640 // Write the head
4641 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) inputChan)) goto Error;
4642 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) outputChan)) goto Error;
4643 if (!_cmsWriteUInt32Number(io, (cmsUInt16Number) ElemCount)) goto Error;
4645 DirectoryPos = io ->Tell(io);
4647 // Write a fake directory to be filled latter on
4648 for (i=0; i < ElemCount; i++) {
4649 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // Offset
4650 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // size
4653 // Write each single tag. Keep track of the size as well.
4654 for (i=0; i < ElemCount; i++) {
4656 ElementOffsets[i] = io ->Tell(io) - BaseOffset;
4658 ElementSig = Elem ->Type;
4660 TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes);
4661 if (TypeHandler == NULL) {
4663 char String[5];
4665 _cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
4667 // An unknown element was found.
4668 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String);
4669 goto Error;
4672 if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error;
4673 if (!_cmsWriteUInt32Number(io, 0)) goto Error;
4674 Before = io ->Tell(io);
4675 if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error;
4676 if (!_cmsWriteAlignment(io)) goto Error;
4678 ElementSizes[i] = io ->Tell(io) - Before;
4680 Elem = Elem ->Next;
4683 // Write the directory
4684 CurrentPos = io ->Tell(io);
4686 if (!io ->Seek(io, DirectoryPos)) goto Error;
4688 for (i=0; i < ElemCount; i++) {
4689 if (!_cmsWriteUInt32Number(io, ElementOffsets[i])) goto Error;
4690 if (!_cmsWriteUInt32Number(io, ElementSizes[i])) goto Error;
4693 if (!io ->Seek(io, CurrentPos)) goto Error;
4695 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4696 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4697 return TRUE;
4699 Error:
4700 if (ElementOffsets != NULL) _cmsFree(self ->ContextID, ElementOffsets);
4701 if (ElementSizes != NULL) _cmsFree(self ->ContextID, ElementSizes);
4702 return FALSE;
4704 cmsUNUSED_PARAMETER(nItems);
4708 static
4709 void* Type_MPE_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4711 return (void*) cmsPipelineDup((cmsPipeline*) Ptr);
4713 cmsUNUSED_PARAMETER(n);
4714 cmsUNUSED_PARAMETER(self);
4717 static
4718 void Type_MPE_Free(struct _cms_typehandler_struct* self, void *Ptr)
4720 cmsPipelineFree((cmsPipeline*) Ptr);
4721 return;
4723 cmsUNUSED_PARAMETER(self);
4727 // ********************************************************************************
4728 // Type cmsSigVcgtType
4729 // ********************************************************************************
4732 #define cmsVideoCardGammaTableType 0
4733 #define cmsVideoCardGammaFormulaType 1
4735 // Used internally
4736 typedef struct {
4737 double Gamma;
4738 double Min;
4739 double Max;
4740 } _cmsVCGTGAMMA;
4743 static
4744 void *Type_vcgt_Read(struct _cms_typehandler_struct* self,
4745 cmsIOHANDLER* io,
4746 cmsUInt32Number* nItems,
4747 cmsUInt32Number SizeOfTag)
4749 cmsUInt32Number TagType, n, i;
4750 cmsToneCurve** Curves;
4752 *nItems = 0;
4754 // Read tag type
4755 if (!_cmsReadUInt32Number(io, &TagType)) return NULL;
4757 // Allocate space for the array
4758 Curves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4759 if (Curves == NULL) return NULL;
4761 // There are two possible flavors
4762 switch (TagType) {
4764 // Gamma is stored as a table
4765 case cmsVideoCardGammaTableType:
4767 cmsUInt16Number nChannels, nElems, nBytes;
4769 // Check channel count, which should be 3 (we don't support monochrome this time)
4770 if (!_cmsReadUInt16Number(io, &nChannels)) goto Error;
4772 if (nChannels != 3) {
4773 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported number of channels for VCGT '%d'", nChannels);
4774 goto Error;
4777 // Get Table element count and bytes per element
4778 if (!_cmsReadUInt16Number(io, &nElems)) goto Error;
4779 if (!_cmsReadUInt16Number(io, &nBytes)) goto Error;
4781 // Adobe's quirk fixup. Fixing broken profiles...
4782 if (nElems == 256 && nBytes == 1 && SizeOfTag == 1576)
4783 nBytes = 2;
4786 // Populate tone curves
4787 for (n=0; n < 3; n++) {
4789 Curves[n] = cmsBuildTabulatedToneCurve16(self ->ContextID, nElems, NULL);
4790 if (Curves[n] == NULL) goto Error;
4792 // On depending on byte depth
4793 switch (nBytes) {
4795 // One byte, 0..255
4796 case 1:
4797 for (i=0; i < nElems; i++) {
4799 cmsUInt8Number v;
4801 if (!_cmsReadUInt8Number(io, &v)) goto Error;
4802 Curves[n] ->Table16[i] = FROM_8_TO_16(v);
4804 break;
4806 // One word 0..65535
4807 case 2:
4808 if (!_cmsReadUInt16Array(io, nElems, Curves[n]->Table16)) goto Error;
4809 break;
4811 // Unsupported
4812 default:
4813 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported bit depth for VCGT '%d'", nBytes * 8);
4814 goto Error;
4816 } // For all 3 channels
4818 break;
4820 // In this case, gamma is stored as a formula
4821 case cmsVideoCardGammaFormulaType:
4823 _cmsVCGTGAMMA Colorant[3];
4825 // Populate tone curves
4826 for (n=0; n < 3; n++) {
4828 double Params[10];
4830 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
4831 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
4832 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
4834 // Parametric curve type 5 is:
4835 // Y = (aX + b)^Gamma + e | X >= d
4836 // Y = cX + f | X < d
4838 // vcgt formula is:
4839 // Y = (Max - Min) * (X ^ Gamma) + Min
4841 // So, the translation is
4842 // a = (Max - Min) ^ ( 1 / Gamma)
4843 // e = Min
4844 // b=c=d=f=0
4846 Params[0] = Colorant[n].Gamma;
4847 Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
4848 Params[2] = 0;
4849 Params[3] = 0;
4850 Params[4] = 0;
4851 Params[5] = Colorant[n].Min;
4852 Params[6] = 0;
4854 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4855 if (Curves[n] == NULL) goto Error;
4858 break;
4860 // Unsupported
4861 default:
4862 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
4863 goto Error;
4866 *nItems = 1;
4867 return (void*) Curves;
4869 // Regret, free all resources
4870 Error:
4872 cmsFreeToneCurveTriple(Curves);
4873 _cmsFree(self ->ContextID, Curves);
4874 return NULL;
4876 cmsUNUSED_PARAMETER(SizeOfTag);
4880 // We don't support all flavors, only 16bits tables and formula
4881 static
4882 cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4884 cmsToneCurve** Curves = (cmsToneCurve**) Ptr;
4885 cmsUInt32Number i, j;
4887 if (cmsGetToneCurveParametricType(Curves[0]) == 5 &&
4888 cmsGetToneCurveParametricType(Curves[1]) == 5 &&
4889 cmsGetToneCurveParametricType(Curves[2]) == 5) {
4891 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE;
4893 // Save parameters
4894 for (i=0; i < 3; i++) {
4896 _cmsVCGTGAMMA v;
4898 v.Gamma = Curves[i] ->Segments[0].Params[0];
4899 v.Min = Curves[i] ->Segments[0].Params[5];
4900 v.Max = pow(Curves[i] ->Segments[0].Params[1], v.Gamma) + v.Min;
4902 if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE;
4903 if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE;
4904 if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE;
4908 else {
4910 // Always store as a table of 256 words
4911 if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaTableType)) return FALSE;
4912 if (!_cmsWriteUInt16Number(io, 3)) return FALSE;
4913 if (!_cmsWriteUInt16Number(io, 256)) return FALSE;
4914 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
4916 for (i=0; i < 3; i++) {
4917 for (j=0; j < 256; j++) {
4919 cmsFloat32Number v = cmsEvalToneCurveFloat(Curves[i], (cmsFloat32Number) (j / 255.0));
4920 cmsUInt16Number n = _cmsQuickSaturateWord(v * 65535.0);
4922 if (!_cmsWriteUInt16Number(io, n)) return FALSE;
4927 return TRUE;
4929 cmsUNUSED_PARAMETER(self);
4930 cmsUNUSED_PARAMETER(nItems);
4933 static
4934 void* Type_vcgt_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
4936 cmsToneCurve** OldCurves = (cmsToneCurve**) Ptr;
4937 cmsToneCurve** NewCurves;
4939 NewCurves = ( cmsToneCurve**) _cmsCalloc(self ->ContextID, 3, sizeof(cmsToneCurve*));
4940 if (NewCurves == NULL) return NULL;
4942 NewCurves[0] = cmsDupToneCurve(OldCurves[0]);
4943 NewCurves[1] = cmsDupToneCurve(OldCurves[1]);
4944 NewCurves[2] = cmsDupToneCurve(OldCurves[2]);
4946 return (void*) NewCurves;
4948 cmsUNUSED_PARAMETER(n);
4952 static
4953 void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* Ptr)
4955 cmsFreeToneCurveTriple((cmsToneCurve**) Ptr);
4956 _cmsFree(self ->ContextID, Ptr);
4960 // ********************************************************************************
4961 // Type cmsSigDictType
4962 // ********************************************************************************
4964 // Single column of the table can point to wchar or MLUC elements. Holds arrays of data
4965 typedef struct {
4966 cmsContext ContextID;
4967 cmsUInt32Number *Offsets;
4968 cmsUInt32Number *Sizes;
4969 } _cmsDICelem;
4971 typedef struct {
4972 _cmsDICelem Name, Value, DisplayName, DisplayValue;
4974 } _cmsDICarray;
4976 // Allocate an empty array element
4977 static
4978 cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count)
4980 e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
4981 if (e->Offsets == NULL) return FALSE;
4983 e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number));
4984 if (e->Sizes == NULL) {
4986 _cmsFree(ContextID, e -> Offsets);
4987 return FALSE;
4990 e ->ContextID = ContextID;
4991 return TRUE;
4994 // Free an array element
4995 static
4996 void FreeElem(_cmsDICelem* e)
4998 if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets);
4999 if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes);
5000 e->Offsets = e ->Sizes = NULL;
5003 // Get rid of whole array
5004 static
5005 void FreeArray( _cmsDICarray* a)
5007 if (a ->Name.Offsets != NULL) FreeElem(&a->Name);
5008 if (a ->Value.Offsets != NULL) FreeElem(&a ->Value);
5009 if (a ->DisplayName.Offsets != NULL) FreeElem(&a->DisplayName);
5010 if (a ->DisplayValue.Offsets != NULL) FreeElem(&a ->DisplayValue);
5014 // Allocate whole array
5015 static
5016 cmsBool AllocArray(cmsContext ContextID, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
5018 // Empty values
5019 memset(a, 0, sizeof(_cmsDICarray));
5021 // On depending on record size, create column arrays
5022 if (!AllocElem(ContextID, &a ->Name, Count)) goto Error;
5023 if (!AllocElem(ContextID, &a ->Value, Count)) goto Error;
5025 if (Length > 16) {
5026 if (!AllocElem(ContextID, &a -> DisplayName, Count)) goto Error;
5029 if (Length > 24) {
5030 if (!AllocElem(ContextID, &a ->DisplayValue, Count)) goto Error;
5032 return TRUE;
5034 Error:
5035 FreeArray(a);
5036 return FALSE;
5039 // Read one element
5040 static
5041 cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUInt32Number BaseOffset)
5043 if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE;
5044 if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE;
5046 // An offset of zero has special meaning and shall be preserved
5047 if (e ->Offsets[i] > 0)
5048 e ->Offsets[i] += BaseOffset;
5049 return TRUE;
5053 static
5054 cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a,
5055 cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset,
5056 cmsInt32Number* SignedSizeOfTagPtr)
5058 cmsUInt32Number i;
5059 cmsInt32Number SignedSizeOfTag = *SignedSizeOfTagPtr;
5061 // Read column arrays
5062 for (i=0; i < Count; i++) {
5064 if (SignedSizeOfTag < 4 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
5065 SignedSizeOfTag -= 4 * sizeof(cmsUInt32Number);
5067 if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE;
5068 if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE;
5070 if (Length > 16) {
5072 if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
5073 SignedSizeOfTag -= 2 * sizeof(cmsUInt32Number);
5075 if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE;
5079 if (Length > 24) {
5081 if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE;
5082 SignedSizeOfTag -= 2 * (cmsInt32Number) sizeof(cmsUInt32Number);
5084 if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE;
5088 *SignedSizeOfTagPtr = SignedSizeOfTag;
5089 return TRUE;
5093 // Write one element
5094 static
5095 cmsBool WriteOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i)
5097 if (!_cmsWriteUInt32Number(io, e->Offsets[i])) return FALSE;
5098 if (!_cmsWriteUInt32Number(io, e ->Sizes[i])) return FALSE;
5100 return TRUE;
5103 static
5104 cmsBool WriteOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length)
5106 cmsUInt32Number i;
5108 for (i=0; i < Count; i++) {
5110 if (!WriteOneElem(io, &a -> Name, i)) return FALSE;
5111 if (!WriteOneElem(io, &a -> Value, i)) return FALSE;
5113 if (Length > 16) {
5115 if (!WriteOneElem(io, &a -> DisplayName, i)) return FALSE;
5118 if (Length > 24) {
5120 if (!WriteOneElem(io, &a -> DisplayValue, i)) return FALSE;
5124 return TRUE;
5127 static
5128 cmsBool ReadOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, wchar_t ** wcstr)
5131 cmsUInt32Number nChars;
5133 // Special case for undefined strings (see ICC Votable
5134 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5135 if (e -> Offsets[i] == 0) {
5137 *wcstr = NULL;
5138 return TRUE;
5141 if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
5143 nChars = e ->Sizes[i] / sizeof(cmsUInt16Number);
5146 *wcstr = (wchar_t*) _cmsMallocZero(e ->ContextID, (nChars + 1) * sizeof(wchar_t));
5147 if (*wcstr == NULL) return FALSE;
5149 if (!_cmsReadWCharArray(io, nChars, *wcstr)) {
5150 _cmsFree(e ->ContextID, *wcstr);
5151 return FALSE;
5154 // End of string marker
5155 (*wcstr)[nChars] = 0;
5156 return TRUE;
5159 static
5160 cmsUInt32Number mywcslen(const wchar_t *s)
5162 const wchar_t *p;
5164 p = s;
5165 while (*p)
5166 p++;
5168 return (cmsUInt32Number)(p - s);
5171 static
5172 cmsBool WriteOneWChar(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const wchar_t * wcstr, cmsUInt32Number BaseOffset)
5174 cmsUInt32Number Before = io ->Tell(io);
5175 cmsUInt32Number n;
5177 e ->Offsets[i] = Before - BaseOffset;
5179 if (wcstr == NULL) {
5180 e ->Sizes[i] = 0;
5181 e ->Offsets[i] = 0;
5182 return TRUE;
5185 n = mywcslen(wcstr);
5186 if (!_cmsWriteWCharArray(io, n, wcstr)) return FALSE;
5188 e ->Sizes[i] = io ->Tell(io) - Before;
5189 return TRUE;
5192 static
5193 cmsBool ReadOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsMLU** mlu)
5195 cmsUInt32Number nItems = 0;
5197 // A way to get null MLUCs
5198 if (e -> Offsets[i] == 0 || e ->Sizes[i] == 0) {
5200 *mlu = NULL;
5201 return TRUE;
5204 if (!io -> Seek(io, e -> Offsets[i])) return FALSE;
5206 *mlu = (cmsMLU*) Type_MLU_Read(self, io, &nItems, e ->Sizes[i]);
5207 return *mlu != NULL;
5210 static
5211 cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, const cmsMLU* mlu, cmsUInt32Number BaseOffset)
5213 cmsUInt32Number Before;
5215 // Special case for undefined strings (see ICC Votable
5216 // Proposal Submission, Dictionary Type and Metadata TAG Definition)
5217 if (mlu == NULL) {
5218 e ->Sizes[i] = 0;
5219 e ->Offsets[i] = 0;
5220 return TRUE;
5223 Before = io ->Tell(io);
5224 e ->Offsets[i] = Before - BaseOffset;
5226 if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
5228 e ->Sizes[i] = io ->Tell(io) - Before;
5229 return TRUE;
5233 static
5234 void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
5236 cmsHANDLE hDict = NULL;
5237 cmsUInt32Number i, Count, Length;
5238 cmsUInt32Number BaseOffset;
5239 _cmsDICarray a;
5240 wchar_t *NameWCS = NULL, *ValueWCS = NULL;
5241 cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL;
5242 cmsBool rc;
5243 cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag;
5245 *nItems = 0;
5246 memset(&a, 0, sizeof(a));
5248 // Get actual position as a basis for element offsets
5249 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5251 // Get name-value record count
5252 SignedSizeOfTag -= sizeof(cmsUInt32Number);
5253 if (SignedSizeOfTag < 0) goto Error;
5254 if (!_cmsReadUInt32Number(io, &Count)) return NULL;
5256 // Get rec length
5257 SignedSizeOfTag -= sizeof(cmsUInt32Number);
5258 if (SignedSizeOfTag < 0) goto Error;
5259 if (!_cmsReadUInt32Number(io, &Length)) return NULL;
5262 // Check for valid lengths
5263 if (Length != 16 && Length != 24 && Length != 32) {
5264 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown record length in dictionary '%d'", Length);
5265 return NULL;
5268 // Creates an empty dictionary
5269 hDict = cmsDictAlloc(self -> ContextID);
5270 if (hDict == NULL) return NULL;
5272 // On depending on record size, create column arrays
5273 if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error;
5275 // Read column arrays
5276 if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset, &SignedSizeOfTag)) goto Error;
5278 // Seek to each element and read it
5279 for (i=0; i < Count; i++) {
5281 if (!ReadOneWChar(io, &a.Name, i, &NameWCS)) goto Error;
5282 if (!ReadOneWChar(io, &a.Value, i, &ValueWCS)) goto Error;
5284 if (Length > 16) {
5285 if (!ReadOneMLUC(self, io, &a.DisplayName, i, &DisplayNameMLU)) goto Error;
5288 if (Length > 24) {
5289 if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error;
5292 if (NameWCS == NULL || ValueWCS == NULL) {
5294 cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value");
5295 rc = FALSE;
5297 else {
5299 rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
5302 if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
5303 if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS);
5304 if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU);
5305 if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU);
5307 if (!rc) goto Error;
5310 FreeArray(&a);
5311 *nItems = 1;
5312 return (void*) hDict;
5314 Error:
5315 FreeArray(&a);
5316 if (hDict != NULL) cmsDictFree(hDict);
5317 return NULL;
5321 static
5322 cmsBool Type_Dictionary_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
5324 cmsHANDLE hDict = (cmsHANDLE) Ptr;
5325 const cmsDICTentry* p;
5326 cmsBool AnyName, AnyValue;
5327 cmsUInt32Number i, Count, Length;
5328 cmsUInt32Number DirectoryPos, CurrentPos, BaseOffset;
5329 _cmsDICarray a;
5331 if (hDict == NULL) return FALSE;
5333 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
5335 // Let's inspect the dictionary
5336 Count = 0; AnyName = FALSE; AnyValue = FALSE;
5337 for (p = cmsDictGetEntryList(hDict); p != NULL; p = cmsDictNextEntry(p)) {
5339 if (p ->DisplayName != NULL) AnyName = TRUE;
5340 if (p ->DisplayValue != NULL) AnyValue = TRUE;
5341 Count++;
5344 Length = 16;
5345 if (AnyName) Length += 8;
5346 if (AnyValue) Length += 8;
5348 if (!_cmsWriteUInt32Number(io, Count)) return FALSE;
5349 if (!_cmsWriteUInt32Number(io, Length)) return FALSE;
5351 // Keep starting position of offsets table
5352 DirectoryPos = io ->Tell(io);
5354 // Allocate offsets array
5355 if (!AllocArray(self ->ContextID, &a, Count, Length)) goto Error;
5357 // Write a fake directory to be filled latter on
5358 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5360 // Write each element. Keep track of the size as well.
5361 p = cmsDictGetEntryList(hDict);
5362 for (i=0; i < Count; i++) {
5364 if (!WriteOneWChar(io, &a.Name, i, p ->Name, BaseOffset)) goto Error;
5365 if (!WriteOneWChar(io, &a.Value, i, p ->Value, BaseOffset)) goto Error;
5367 if (p ->DisplayName != NULL) {
5368 if (!WriteOneMLUC(self, io, &a.DisplayName, i, p ->DisplayName, BaseOffset)) goto Error;
5371 if (p ->DisplayValue != NULL) {
5372 if (!WriteOneMLUC(self, io, &a.DisplayValue, i, p ->DisplayValue, BaseOffset)) goto Error;
5375 p = cmsDictNextEntry(p);
5378 // Write the directory
5379 CurrentPos = io ->Tell(io);
5380 if (!io ->Seek(io, DirectoryPos)) goto Error;
5382 if (!WriteOffsetArray(io, &a, Count, Length)) goto Error;
5384 if (!io ->Seek(io, CurrentPos)) goto Error;
5386 FreeArray(&a);
5387 return TRUE;
5389 Error:
5390 FreeArray(&a);
5391 return FALSE;
5393 cmsUNUSED_PARAMETER(nItems);
5397 static
5398 void* Type_Dictionary_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
5400 return (void*) cmsDictDup((cmsHANDLE) Ptr);
5402 cmsUNUSED_PARAMETER(n);
5403 cmsUNUSED_PARAMETER(self);
5407 static
5408 void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
5410 cmsDictFree((cmsHANDLE) Ptr);
5411 cmsUNUSED_PARAMETER(self);
5414 // cicp VideoSignalType
5416 static
5417 void* Type_VideoSignal_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
5419 cmsVideoSignalType* cicp = NULL;
5421 if (SizeOfTag != 8) return NULL;
5423 if (!_cmsReadUInt32Number(io, NULL)) return NULL;
5425 cicp = (cmsVideoSignalType*)_cmsCalloc(self->ContextID, 1, sizeof(cmsVideoSignalType));
5426 if (cicp == NULL) return NULL;
5428 if (!_cmsReadUInt8Number(io, &cicp->ColourPrimaries)) goto Error;
5429 if (!_cmsReadUInt8Number(io, &cicp->TransferCharacteristics)) goto Error;
5430 if (!_cmsReadUInt8Number(io, &cicp->MatrixCoefficients)) goto Error;
5431 if (!_cmsReadUInt8Number(io, &cicp->VideoFullRangeFlag)) goto Error;
5433 // Success
5434 *nItems = 1;
5435 return cicp;
5437 Error:
5438 if (cicp != NULL) _cmsFree(self->ContextID, cicp);
5439 return NULL;
5442 static
5443 cmsBool Type_VideoSignal_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
5445 cmsVideoSignalType* cicp = (cmsVideoSignalType*)Ptr;
5447 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
5448 if (!_cmsWriteUInt8Number(io, cicp->ColourPrimaries)) return FALSE;
5449 if (!_cmsWriteUInt8Number(io, cicp->TransferCharacteristics)) return FALSE;
5450 if (!_cmsWriteUInt8Number(io, cicp->MatrixCoefficients)) return FALSE;
5451 if (!_cmsWriteUInt8Number(io, cicp->VideoFullRangeFlag)) return FALSE;
5453 return TRUE;
5455 cmsUNUSED_PARAMETER(self);
5456 cmsUNUSED_PARAMETER(nItems);
5459 void* Type_VideoSignal_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
5461 return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsVideoSignalType));
5463 cmsUNUSED_PARAMETER(n);
5467 static
5468 void Type_VideoSignal_Free(struct _cms_typehandler_struct* self, void* Ptr)
5470 _cmsFree(self->ContextID, Ptr);
5473 // ********************************************************************************
5474 // Type support main routines
5475 // ********************************************************************************
5478 // This is the list of built-in types
5479 static const _cmsTagTypeLinkedList SupportedTagTypes[] = {
5481 {TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), (_cmsTagTypeLinkedList*) &SupportedTagTypes[1] },
5482 {TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), (_cmsTagTypeLinkedList*) &SupportedTagTypes[2] },
5483 {TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[3] },
5484 {TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[4] },
5485 {TYPE_HANDLER(cmsSigTextType, Text), (_cmsTagTypeLinkedList*) &SupportedTagTypes[5] },
5486 {TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), (_cmsTagTypeLinkedList*) &SupportedTagTypes[6] },
5487 {TYPE_HANDLER(cmsSigCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[7] },
5488 {TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[8] },
5489 {TYPE_HANDLER(cmsSigDateTimeType, DateTime), (_cmsTagTypeLinkedList*) &SupportedTagTypes[9] },
5490 {TYPE_HANDLER(cmsSigLut8Type, LUT8), (_cmsTagTypeLinkedList*) &SupportedTagTypes[10] },
5491 {TYPE_HANDLER(cmsSigLut16Type, LUT16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[11] },
5492 {TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), (_cmsTagTypeLinkedList*) &SupportedTagTypes[12] },
5493 {TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), (_cmsTagTypeLinkedList*) &SupportedTagTypes[13] },
5494 {TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), (_cmsTagTypeLinkedList*) &SupportedTagTypes[14] },
5495 {TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc),(_cmsTagTypeLinkedList*) &SupportedTagTypes[15] },
5496 {TYPE_HANDLER(cmsSigSignatureType, Signature), (_cmsTagTypeLinkedList*) &SupportedTagTypes[16] },
5497 {TYPE_HANDLER(cmsSigMeasurementType, Measurement), (_cmsTagTypeLinkedList*) &SupportedTagTypes[17] },
5498 {TYPE_HANDLER(cmsSigDataType, Data), (_cmsTagTypeLinkedList*) &SupportedTagTypes[18] },
5499 {TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), (_cmsTagTypeLinkedList*) &SupportedTagTypes[19] },
5500 {TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), (_cmsTagTypeLinkedList*) &SupportedTagTypes[20] },
5501 {TYPE_HANDLER(cmsSigUcrBgType, UcrBg), (_cmsTagTypeLinkedList*) &SupportedTagTypes[21] },
5502 {TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), (_cmsTagTypeLinkedList*) &SupportedTagTypes[22] },
5503 {TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), (_cmsTagTypeLinkedList*) &SupportedTagTypes[23] },
5504 {TYPE_HANDLER(cmsSigScreeningType, Screening), (_cmsTagTypeLinkedList*) &SupportedTagTypes[24] },
5505 {TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), (_cmsTagTypeLinkedList*) &SupportedTagTypes[25] },
5506 {TYPE_HANDLER(cmsSigXYZType, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[26] },
5507 {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[27] },
5508 {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[28] },
5509 {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] },
5510 {TYPE_HANDLER(cmsSigDictType, Dictionary), (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] },
5511 {TYPE_HANDLER(cmsSigcicpType, VideoSignal), (_cmsTagTypeLinkedList*) &SupportedTagTypes[31] },
5512 {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
5516 _cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL };
5520 // Duplicates the zone of memory used by the plug-in in the new context
5521 static
5522 void DupTagTypeList(struct _cmsContext_struct* ctx,
5523 const struct _cmsContext_struct* src,
5524 int loc)
5526 _cmsTagTypePluginChunkType newHead = { NULL };
5527 _cmsTagTypeLinkedList* entry;
5528 _cmsTagTypeLinkedList* Anterior = NULL;
5529 _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc];
5531 // Walk the list copying all nodes
5532 for (entry = head->TagTypes;
5533 entry != NULL;
5534 entry = entry ->Next) {
5536 _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList));
5538 if (newEntry == NULL)
5539 return;
5541 // We want to keep the linked list order, so this is a little bit tricky
5542 newEntry -> Next = NULL;
5543 if (Anterior)
5544 Anterior -> Next = newEntry;
5546 Anterior = newEntry;
5548 if (newHead.TagTypes == NULL)
5549 newHead.TagTypes = newEntry;
5552 ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType));
5556 void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx,
5557 const struct _cmsContext_struct* src)
5559 if (src != NULL) {
5561 // Duplicate the LIST
5562 DupTagTypeList(ctx, src, TagTypePlugin);
5564 else {
5565 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
5566 ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
5570 void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx,
5571 const struct _cmsContext_struct* src)
5573 if (src != NULL) {
5575 // Duplicate the LIST
5576 DupTagTypeList(ctx, src, MPEPlugin);
5578 else {
5579 static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
5580 ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
5586 // Both kind of plug-ins share same structure
5587 cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data)
5589 return RegisterTypesPlugin(id, Data, TagTypePlugin);
5592 cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data)
5594 return RegisterTypesPlugin(id, Data,MPEPlugin);
5598 // Wrapper for tag types
5599 cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig)
5601 _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin);
5603 return GetHandler(sig, ctx->TagTypes, (_cmsTagTypeLinkedList*) SupportedTagTypes);
5606 // ********************************************************************************
5607 // Tag support main routines
5608 // ********************************************************************************
5610 typedef struct _cmsTagLinkedList_st {
5612 cmsTagSignature Signature;
5613 cmsTagDescriptor Descriptor;
5614 struct _cmsTagLinkedList_st* Next;
5616 } _cmsTagLinkedList;
5618 // This is the list of built-in tags. The data of this list can be modified by plug-ins
5619 static _cmsTagLinkedList SupportedTags[] = {
5621 { cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]},
5622 { cmsSigAToB1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[2]},
5623 { cmsSigAToB2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[3]},
5624 { cmsSigBToA0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[4]},
5625 { cmsSigBToA1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[5]},
5626 { cmsSigBToA2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type}, DecideLUTtypeB2A}, &SupportedTags[6]},
5628 // Allow corbis and its broken XYZ type
5629 { cmsSigRedColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[7]},
5630 { cmsSigGreenColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[8]},
5631 { cmsSigBlueColorantTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, DecideXYZtype}, &SupportedTags[9]},
5633 { cmsSigRedTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[10]},
5634 { cmsSigGreenTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[11]},
5635 { cmsSigBlueTRCTag, { 1, 3, { cmsSigCurveType, cmsSigParametricCurveType, cmsMonacoBrokenCurveType }, DecideCurveType}, &SupportedTags[12]},
5637 { cmsSigCalibrationDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[13]},
5638 { cmsSigCharTargetTag, { 1, 1, { cmsSigTextType }, NULL}, &SupportedTags[14]},
5640 { cmsSigChromaticAdaptationTag, { 9, 1, { cmsSigS15Fixed16ArrayType }, NULL}, &SupportedTags[15]},
5641 { cmsSigChromaticityTag, { 1, 1, { cmsSigChromaticityType }, NULL}, &SupportedTags[16]},
5642 { cmsSigColorantOrderTag, { 1, 1, { cmsSigColorantOrderType }, NULL}, &SupportedTags[17]},
5643 { cmsSigColorantTableTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[18]},
5644 { cmsSigColorantTableOutTag, { 1, 1, { cmsSigColorantTableType }, NULL}, &SupportedTags[19]},
5646 { cmsSigCopyrightTag, { 1, 3, { cmsSigTextType, cmsSigMultiLocalizedUnicodeType, cmsSigTextDescriptionType}, DecideTextType}, &SupportedTags[20]},
5647 { cmsSigDateTimeTag, { 1, 1, { cmsSigDateTimeType }, NULL}, &SupportedTags[21]},
5649 { cmsSigDeviceMfgDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[22]},
5650 { cmsSigDeviceModelDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[23]},
5652 { cmsSigGamutTag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[24]},
5654 { cmsSigGrayTRCTag, { 1, 2, { cmsSigCurveType, cmsSigParametricCurveType }, DecideCurveType}, &SupportedTags[25]},
5655 { cmsSigLuminanceTag, { 1, 1, { cmsSigXYZType }, NULL}, &SupportedTags[26]},
5657 { cmsSigMediaBlackPointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[27]},
5658 { cmsSigMediaWhitePointTag, { 1, 2, { cmsSigXYZType, cmsCorbisBrokenXYZtype }, NULL}, &SupportedTags[28]},
5660 { cmsSigNamedColor2Tag, { 1, 1, { cmsSigNamedColor2Type }, NULL}, &SupportedTags[29]},
5662 { cmsSigPreview0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[30]},
5663 { cmsSigPreview1Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[31]},
5664 { cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]},
5666 { cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]},
5667 { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
5668 { cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]},
5670 { cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]},
5671 { cmsSigPerceptualRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[37]},
5672 { cmsSigSaturationRenderingIntentGamutTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[38]},
5674 { cmsSigMeasurementTag, { 1, 1, { cmsSigMeasurementType }, NULL}, &SupportedTags[39]},
5676 { cmsSigPs2CRD0Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[40]},
5677 { cmsSigPs2CRD1Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[41]},
5678 { cmsSigPs2CRD2Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[42]},
5679 { cmsSigPs2CRD3Tag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[43]},
5680 { cmsSigPs2CSATag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[44]},
5681 { cmsSigPs2RenderingIntentTag, { 1, 1, { cmsSigDataType }, NULL}, &SupportedTags[45]},
5683 { cmsSigViewingCondDescTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[46]},
5685 { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]},
5686 { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]},
5688 { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
5689 { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
5690 { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
5691 { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
5692 { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
5693 { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
5694 { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
5695 { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
5697 { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]},
5698 { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]},
5700 { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
5701 { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
5702 { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
5703 { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
5705 { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
5706 { cmsSigcicpTag, { 1, 1, { cmsSigcicpType}, NULL }, &SupportedTags[64]},
5708 { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL}
5713 Not supported Why
5714 ======================= =========================================
5715 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5716 cmsSigNamedColorTag ==> Deprecated
5717 cmsSigDataTag ==> Ancient, unused
5718 cmsSigDeviceSettingsTag ==> Deprecated, useless
5722 _cmsTagPluginChunkType _cmsTagPluginChunk = { NULL };
5725 // Duplicates the zone of memory used by the plug-in in the new context
5726 static
5727 void DupTagList(struct _cmsContext_struct* ctx,
5728 const struct _cmsContext_struct* src)
5730 _cmsTagPluginChunkType newHead = { NULL };
5731 _cmsTagLinkedList* entry;
5732 _cmsTagLinkedList* Anterior = NULL;
5733 _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin];
5735 // Walk the list copying all nodes
5736 for (entry = head->Tag;
5737 entry != NULL;
5738 entry = entry ->Next) {
5740 _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList));
5742 if (newEntry == NULL)
5743 return;
5745 // We want to keep the linked list order, so this is a little bit tricky
5746 newEntry -> Next = NULL;
5747 if (Anterior)
5748 Anterior -> Next = newEntry;
5750 Anterior = newEntry;
5752 if (newHead.Tag == NULL)
5753 newHead.Tag = newEntry;
5756 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType));
5759 void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx,
5760 const struct _cmsContext_struct* src)
5762 if (src != NULL) {
5764 DupTagList(ctx, src);
5766 else {
5767 static _cmsTagPluginChunkType TagPluginChunk = { NULL };
5768 ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType));
5773 cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data)
5775 cmsPluginTag* Plugin = (cmsPluginTag*) Data;
5776 _cmsTagLinkedList *pt;
5777 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin);
5779 if (Data == NULL) {
5781 TagPluginChunk->Tag = NULL;
5782 return TRUE;
5785 pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList));
5786 if (pt == NULL) return FALSE;
5788 pt ->Signature = Plugin ->Signature;
5789 pt ->Descriptor = Plugin ->Descriptor;
5790 pt ->Next = TagPluginChunk ->Tag;
5792 TagPluginChunk ->Tag = pt;
5794 return TRUE;
5797 // Return a descriptor for a given tag or NULL
5798 cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig)
5800 _cmsTagLinkedList* pt;
5801 _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin);
5803 for (pt = TagPluginChunk->Tag;
5804 pt != NULL;
5805 pt = pt ->Next) {
5807 if (sig == pt -> Signature) return &pt ->Descriptor;
5810 for (pt = SupportedTags;
5811 pt != NULL;
5812 pt = pt ->Next) {
5814 if (sig == pt -> Signature) return &pt ->Descriptor;
5817 return NULL;