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