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