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