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