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