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