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