Bug Summary

File:jdk/src/java.desktop/share/native/liblcms/cmstypes.c
Warning:line 5127, column 20
Array access (via field 'Offsets') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

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