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