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