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