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