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