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-2014 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 appropiate 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)
70 #define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00)
71
72 // This is the linked list that keeps track of the defined types
73 typedef 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
82 #define WRITE_FN(x) Type_##x##_Write
125 _cmsTagTypeLinkedList* pt;
126
127 for (pt = PluginLinkedList;
128 pt != NULL;
129 pt = pt ->Next) {
130
131 if (sig == pt -> Handler.Signature) return &pt ->Handler;
132 }
133
134 for (pt = DefaultLinkedList;
135 pt != NULL;
136 pt = pt ->Next) {
137
138 if (sig == pt -> Handler.Signature) return &pt ->Handler;
139 }
140
141 return NULL;
142 }
143
144
145 // Auxiliar to convert UTF-32 to UTF-16 in some cases
146 static
147 cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
148 {
149 cmsUInt32Number i;
150
151 _cmsAssert(io != NULL);
152 _cmsAssert(!(Array == NULL && n > 0));
153
154 for (i=0; i < n; i++) {
155 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
156 }
157
158 return TRUE;
159 }
160
161 // Auxiliar to read an array of wchar_t
162 static
163 cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
164 {
165 cmsUInt32Number i;
166 cmsUInt16Number tmp;
167
168 _cmsAssert(io != NULL);
169
170 for (i=0; i < n; i++) {
171
172 if (Array != NULL) {
173
174 if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
175 Array[i] = (wchar_t) tmp;
176 }
177 else {
178 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
179 }
180
181 }
182 return TRUE;
183 }
184
185 // To deal with position tables
186 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
187 cmsIOHANDLER* io,
188 void* Cargo,
189 cmsUInt32Number n,
190 cmsUInt32Number SizeOfTag);
191
192 // Helper function to deal with position tables as decribed in ICC spec 4.3
193 // A table of n elements is readed, where first comes n records containing offsets and sizes and
194 // then a block containing the data itself. This allows to reuse same data in more than one entry
195 static
196 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
197 cmsIOHANDLER* io,
198 cmsUInt32Number Count,
199 cmsUInt32Number BaseOffset,
200 void *Cargo,
201 PositionTableEntryFn ElementFn)
202 {
203 cmsUInt32Number i;
204 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
205
206 // Let's take the offsets to each element
207 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
208 if (ElementOffsets == NULL) goto Error;
209
210 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
211 if (ElementSizes == NULL) goto Error;
212
963
964 Done:
965
966 *nItems = 1;
967 return mlu;
968
969 Error:
970 if (Text) _cmsFree(self ->ContextID, (void*) Text);
971 if (mlu) cmsMLUfree(mlu);
972 return NULL;
973 }
974
975
976 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
977 static
978 cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
979 {
980 cmsMLU* mlu = (cmsMLU*) Ptr;
981 char *Text = NULL;
982 wchar_t *Wide = NULL;
983 cmsUInt32Number len, len_aligned, len_filler_alignment;
984 cmsBool rc = FALSE;
985 char Filler[68];
986
987 // Used below for writting zeroes
988 memset(Filler, 0, sizeof(Filler));
989
990 // Get the len of string
991 len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
992
993 // From ICC3.4: It has been found that textDescriptionType can contain misaligned data
994 //(see clause 4.1 for the definition of “aligned”). Because the Unicode language
995 // code and Unicode count immediately follow the ASCII description, their
996 // alignment is not correct if the ASCII count is not a multiple of four. The
997 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
998 // writing software must be written carefully in order to handle these alignment
999 // problems.
1000
1001 // Compute an aligned size
1002 len_aligned = _cmsALIGNLONG(len);
1003 len_filler_alignment = len_aligned - len;
1004
1005 // Null strings
1006 if (len <= 0) {
1007
1008 Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
1009 Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
1010 }
1011 else {
1012 // Create independent buffers
1013 Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
1014 if (Text == NULL) goto Error;
1015
1016 Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t));
1017 if (Wide == NULL) goto Error;
1018
1019 // Get both representations.
1020 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char));
1021 cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t));
1022 }
1023
1024 // * cmsUInt32Number count; * Description length
1025 // * cmsInt8Number desc[count] * NULL terminated ascii string
1026 // * cmsUInt32Number ucLangCode; * UniCode language code
1027 // * cmsUInt32Number ucCount; * UniCode description length
1028 // * cmsInt16Number ucDesc[ucCount];* The UniCode description
1029 // * cmsUInt16Number scCode; * ScriptCode code
1030 // * cmsUInt8Number scCount; * ScriptCode count
1031 // * cmsInt8Number scDesc[67]; * ScriptCode Description
1032
1033 if (!_cmsWriteUInt32Number(io, len_aligned)) goto Error;
1034 if (!io ->Write(io, len, Text)) goto Error;
1035 if (!io ->Write(io, len_filler_alignment, Filler)) goto Error;
1036
1037 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode
1038
1039 // This part is tricky: we need an aligned tag size, and the ScriptCode part
1040 // takes 70 bytes, so we need 2 extra bytes to do the alignment
1041
1042 if (!_cmsWriteUInt32Number(io, len_aligned+1)) goto Error;
1043
1044 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1045 if (!_cmsWriteWCharArray(io, len, Wide)) goto Error;
1046 if (!_cmsWriteUInt16Array(io, len_filler_alignment+1, (cmsUInt16Number*) Filler)) goto Error;
1047
1048 // ScriptCode Code & count (unused)
1049 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
1050 if (!_cmsWriteUInt8Number(io, 0)) goto Error;
1051
1052 if (!io ->Write(io, 67, Filler)) goto Error;
1053
1054 rc = TRUE;
1055
1056 Error:
1057 if (Text) _cmsFree(self ->ContextID, Text);
1058 if (Wide) _cmsFree(self ->ContextID, Wide);
1059
1060 return rc;
1061
1062 cmsUNUSED_PARAMETER(nItems);
1063 }
1064
1065
1066 static
1067 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1068 {
1069 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1070
1071 cmsUNUSED_PARAMETER(n);
1072 cmsUNUSED_PARAMETER(self);
1073 }
1481 // Now deal with Len and offset.
1482 if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1483 if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1484
1485 // Check for overflow
1486 if (Offset < (SizeOfHeader + 8)) goto Error;
1487
1488 // True begin of the string
1489 BeginOfThisString = Offset - SizeOfHeader - 8;
1490
1491 // Ajust to wchar_t elements
1492 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1493 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1494
1495 // To guess maximum size, add offset + len
1496 EndOfThisString = BeginOfThisString + Len;
1497 if (EndOfThisString > LargestPosition)
1498 LargestPosition = EndOfThisString;
1499 }
1500
1501 // Now read the remaining of tag and fill all strings. Substract the directory
1502 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1503 if (SizeOfTag == 0)
1504 {
1505 Block = NULL;
1506 NumOfWchar = 0;
1507
1508 }
1509 else
1510 {
1511 Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
1512 if (Block == NULL) goto Error;
1513 NumOfWchar = SizeOfTag / sizeof(wchar_t);
1514 if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
1515 }
1516
1517 mlu ->MemPool = Block;
1518 mlu ->PoolSize = SizeOfTag;
1519 mlu ->PoolUsed = SizeOfTag;
1520
1521 *nItems = 1;
1522 return (void*) mlu;
1523
1524 Error:
1525 if (mlu) cmsMLUfree(mlu);
1526 return NULL;
1527 }
1528
1529 static
1530 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1531 {
1532 cmsMLU* mlu =(cmsMLU*) Ptr;
1533 cmsUInt32Number HeaderSize;
1534 cmsUInt32Number Len, Offset;
1535 int i;
1536
1537 if (Ptr == NULL) {
1538
1539 // Empty placeholder
1540 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1541 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1542 return TRUE;
1543 }
1544
1545 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1546 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1547
1548 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1549
1550 for (i=0; i < mlu ->UsedEntries; i++) {
1551
1552 Len = mlu ->Entries[i].Len;
1553 Offset = mlu ->Entries[i].StrW;
1554
1555 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
3116 prefix[31] = suffix[31] = 0;
3117
3118 v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
3119 if (v == NULL) {
3120 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
3121 return NULL;
3122 }
3123
3124 if (nDeviceCoords > cmsMAXCHANNELS) {
3125 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
3126 return 0;
3127 }
3128 for (i=0; i < count; i++) {
3129
3130 cmsUInt16Number PCS[3];
3131 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3132 char Root[33];
3133
3134 memset(Colorant, 0, sizeof(Colorant));
3135 if (io -> Read(io, Root, 32, 1) != 1) return NULL;
3136 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3137 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3138
3139 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3140 }
3141
3142 *nItems = 1;
3143 return (void*) v ;
3144
3145 Error:
3146 cmsFreeNamedColorList(v);
3147 return NULL;
3148
3149 cmsUNUSED_PARAMETER(SizeOfTag);
3150 }
3151
3152
3153 // Saves a named color list into a named color profile
3154 static
3155 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3156 {
3157 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3158 char prefix[32]; // Prefix for each color name
3159 char suffix[32]; // Suffix for each color name
3160 int i, nColors;
3161
3162 nColors = cmsNamedColorCount(NamedColorList);
3163
3164 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3165 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3166 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3167
3168 strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
3169 strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
3170
3171 suffix[31] = prefix[31] = 0;
3172
3173 if (!io ->Write(io, 32, prefix)) return FALSE;
3174 if (!io ->Write(io, 32, suffix)) return FALSE;
3175
3176 for (i=0; i < nColors; i++) {
3177
3178 cmsUInt16Number PCS[3];
3179 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3180 char Root[33];
3181
3182 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3183 if (!io ->Write(io, 32 , Root)) return FALSE;
3184 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3185 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3186 }
3187
3188 return TRUE;
3189
3190 cmsUNUSED_PARAMETER(nItems);
3191 cmsUNUSED_PARAMETER(self);
3192 }
3193
3194 static
3195 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3196 {
3197 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3198
3199 return (void*) cmsDupNamedColorList(nc);
3200
3201 cmsUNUSED_PARAMETER(n);
3202 cmsUNUSED_PARAMETER(self);
3613
3614 // ********************************************************************************
3615 // Type cmsSigCrdInfoType
3616 // ********************************************************************************
3617
3618 /*
3619 This type contains the PostScript product name to which this profile corresponds
3620 and the names of the companion CRDs. Recall that a single profile can generate
3621 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3622 country varies for each element:
3623
3624 nm: PostScript product name
3625 #0: Rendering intent 0 CRD name
3626 #1: Rendering intent 1 CRD name
3627 #2: Rendering intent 2 CRD name
3628 #3: Rendering intent 3 CRD name
3629 */
3630
3631
3632
3633 // Auxiliar, read an string specified as count + string
3634 static
3635 cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
3636 {
3637 cmsUInt32Number Count;
3638 char* Text;
3639
3640 if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
3641
3642 if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
3643
3644 if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
3645 if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
3646
3647 Text = (char*) _cmsMalloc(self ->ContextID, Count+1);
3648 if (Text == NULL) return FALSE;
3649
3650 if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
3651 _cmsFree(self ->ContextID, Text);
3652 return FALSE;
3653 }
3862
3863 static
3864 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3865 {
3866 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3867
3868 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3869 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3870 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3871
3872 return TRUE;
3873
3874 cmsUNUSED_PARAMETER(nItems);
3875 cmsUNUSED_PARAMETER(self);
3876 }
3877
3878
3879 static
3880 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3881 {
3882 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3883
3884 cmsUNUSED_PARAMETER(n);
3885 }
3886
3887
3888 static
3889 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3890 {
3891 _cmsFree(self ->ContextID, Ptr);
3892 }
3893
3894
3895 // ********************************************************************************
3896 // Type cmsSigMultiProcessElementType
3897 // ********************************************************************************
3898
3899
3900 static
3901 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3902 {
4316 for (i=0; i < clut ->nEntries; i++) {
4317
4318 if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
4319 }
4320
4321 *nItems = 1;
4322 return mpe;
4323
4324 Error:
4325 *nItems = 0;
4326 if (mpe != NULL) cmsStageFree(mpe);
4327 return NULL;
4328
4329 cmsUNUSED_PARAMETER(SizeOfTag);
4330 }
4331
4332 // Write a CLUT in floating point
4333 static
4334 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4335 {
4336 cmsUInt8Number Dimensions8[16];
4337 cmsUInt32Number i;
4338 cmsStage* mpe = (cmsStage*) Ptr;
4339 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4340
4341 // Check for maximum number of channels
4342 if (mpe -> InputChannels > 15) return FALSE;
4343
4344 // Only floats are supported in MPE
4345 if (clut ->HasFloatValues == FALSE) return FALSE;
4346
4347 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4348 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4349
4350 memset(Dimensions8, 0, sizeof(Dimensions8));
4351
4352 for (i=0; i < mpe ->InputChannels; i++)
4353 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4354
4355 if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4356
4357 for (i=0; i < clut ->nEntries; i++) {
4358
4359 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4360 }
4361
4362 return TRUE;
5461
5462 { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]},
5463 { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]},
5464
5465 { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
5466 { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
5467 { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
5468 { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
5469 { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
5470 { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
5471 { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
5472 { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
5473
5474 { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]},
5475 { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]},
5476
5477 { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
5478 { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
5479 { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
5480 { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
5481 { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL}
5482
5483
5484 };
5485
5486 /*
5487 Not supported Why
5488 ======================= =========================================
5489 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5490 cmsSigNamedColorTag ==> Deprecated
5491 cmsSigDataTag ==> Ancient, unused
5492 cmsSigDeviceSettingsTag ==> Deprecated, useless
5493 */
5494
5495
5496 _cmsTagPluginChunkType _cmsTagPluginChunk = { NULL };
5497
5498
5499 // Duplicates the zone of memory used by the plug-in in the new context
5500 static
5501 void DupTagList(struct _cmsContext_struct* ctx,
|
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-2016 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)
70 #define cmsMonacoBrokenCurveType ((cmsTagTypeSignature) 0x9478ee00)
71
72 // This is the linked list that keeps track of the defined types
73 typedef 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
82 #define WRITE_FN(x) Type_##x##_Write
125 _cmsTagTypeLinkedList* pt;
126
127 for (pt = PluginLinkedList;
128 pt != NULL;
129 pt = pt ->Next) {
130
131 if (sig == pt -> Handler.Signature) return &pt ->Handler;
132 }
133
134 for (pt = DefaultLinkedList;
135 pt != NULL;
136 pt = pt ->Next) {
137
138 if (sig == pt -> Handler.Signature) return &pt ->Handler;
139 }
140
141 return NULL;
142 }
143
144
145 // Auxiliary to convert UTF-32 to UTF-16 in some cases
146 static
147 cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* Array)
148 {
149 cmsUInt32Number i;
150
151 _cmsAssert(io != NULL);
152 _cmsAssert(!(Array == NULL && n > 0));
153
154 for (i=0; i < n; i++) {
155 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE;
156 }
157
158 return TRUE;
159 }
160
161 // Auxiliary to read an array of wchar_t
162 static
163 cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
164 {
165 cmsUInt32Number i;
166 cmsUInt16Number tmp;
167
168 _cmsAssert(io != NULL);
169
170 for (i=0; i < n; i++) {
171
172 if (Array != NULL) {
173
174 if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
175 Array[i] = (wchar_t) tmp;
176 }
177 else {
178 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
179 }
180
181 }
182 return TRUE;
183 }
184
185 // To deal with position tables
186 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
187 cmsIOHANDLER* io,
188 void* Cargo,
189 cmsUInt32Number n,
190 cmsUInt32Number SizeOfTag);
191
192 // Helper function to deal with position tables as described in ICC spec 4.3
193 // A table of n elements is readed, where first comes n records containing offsets and sizes and
194 // then a block containing the data itself. This allows to reuse same data in more than one entry
195 static
196 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
197 cmsIOHANDLER* io,
198 cmsUInt32Number Count,
199 cmsUInt32Number BaseOffset,
200 void *Cargo,
201 PositionTableEntryFn ElementFn)
202 {
203 cmsUInt32Number i;
204 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
205
206 // Let's take the offsets to each element
207 ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
208 if (ElementOffsets == NULL) goto Error;
209
210 ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
211 if (ElementSizes == NULL) goto Error;
212
963
964 Done:
965
966 *nItems = 1;
967 return mlu;
968
969 Error:
970 if (Text) _cmsFree(self ->ContextID, (void*) Text);
971 if (mlu) cmsMLUfree(mlu);
972 return NULL;
973 }
974
975
976 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
977 static
978 cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
979 {
980 cmsMLU* mlu = (cmsMLU*) Ptr;
981 char *Text = NULL;
982 wchar_t *Wide = NULL;
983 cmsUInt32Number len, len_text, len_tag_requirement, len_aligned;
984 cmsBool rc = FALSE;
985 char Filler[68];
986
987 // Used below for writting zeroes
988 memset(Filler, 0, sizeof(Filler));
989
990 // Get the len of string
991 len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
992
993 // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data
994 //(see clause 4.1 for the definition of “aligned”). Because the Unicode language
995 // code and Unicode count immediately follow the ASCII description, their
996 // alignment is not correct if the ASCII count is not a multiple of four. The
997 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
998 // writing software must be written carefully in order to handle these alignment
999 // problems.
1000 //
1001 // The above last sentence suggest to handle alignment issues in the
1002 // parser. The provided example (Table 69 on Page 60) makes this clear.
1003 // The padding only in the ASCII count is not sufficient for a aligned tag
1004 // size, with the same text size in ASCII and Unicode.
1005
1006 // Null strings
1007 if (len <= 0) {
1008
1009 Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
1010 Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
1011 }
1012 else {
1013 // Create independent buffers
1014 Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
1015 if (Text == NULL) goto Error;
1016
1017 Wide = (wchar_t*) _cmsCalloc(self ->ContextID, len, sizeof(wchar_t));
1018 if (Wide == NULL) goto Error;
1019
1020 // Get both representations.
1021 cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char));
1022 cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t));
1023 }
1024
1025 // Tell the real text len including the null terminator and padding
1026 len_text = (cmsUInt32Number) strlen(Text) + 1;
1027 // Compute an total tag size requirement
1028 len_tag_requirement = (8+4+len_text+4+4+2*len_text+2+1+67);
1029 len_aligned = _cmsALIGNLONG(len_tag_requirement);
1030
1031 // * cmsUInt32Number count; * Description length
1032 // * cmsInt8Number desc[count] * NULL terminated ascii string
1033 // * cmsUInt32Number ucLangCode; * UniCode language code
1034 // * cmsUInt32Number ucCount; * UniCode description length
1035 // * cmsInt16Number ucDesc[ucCount];* The UniCode description
1036 // * cmsUInt16Number scCode; * ScriptCode code
1037 // * cmsUInt8Number scCount; * ScriptCode count
1038 // * cmsInt8Number scDesc[67]; * ScriptCode Description
1039
1040 if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1041 if (!io ->Write(io, len_text, Text)) goto Error;
1042
1043 if (!_cmsWriteUInt32Number(io, 0)) goto Error; // ucLanguageCode
1044
1045 if (!_cmsWriteUInt32Number(io, len_text)) goto Error;
1046 // Note that in some compilers sizeof(cmsUInt16Number) != sizeof(wchar_t)
1047 if (!_cmsWriteWCharArray(io, len_text, Wide)) goto Error;
1048
1049 // ScriptCode Code & count (unused)
1050 if (!_cmsWriteUInt16Number(io, 0)) goto Error;
1051 if (!_cmsWriteUInt8Number(io, 0)) goto Error;
1052
1053 if (!io ->Write(io, 67, Filler)) goto Error;
1054
1055 // possibly add pad at the end of tag
1056 if(len_aligned - len_tag_requirement > 0)
1057 if (!io ->Write(io, len_aligned - len_tag_requirement, Filler)) goto Error;
1058
1059 rc = TRUE;
1060
1061 Error:
1062 if (Text) _cmsFree(self ->ContextID, Text);
1063 if (Wide) _cmsFree(self ->ContextID, Wide);
1064
1065 return rc;
1066
1067 cmsUNUSED_PARAMETER(nItems);
1068 }
1069
1070
1071 static
1072 void* Type_Text_Description_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
1073 {
1074 return (void*) cmsMLUdup((cmsMLU*) Ptr);
1075
1076 cmsUNUSED_PARAMETER(n);
1077 cmsUNUSED_PARAMETER(self);
1078 }
1486 // Now deal with Len and offset.
1487 if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1488 if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1489
1490 // Check for overflow
1491 if (Offset < (SizeOfHeader + 8)) goto Error;
1492
1493 // True begin of the string
1494 BeginOfThisString = Offset - SizeOfHeader - 8;
1495
1496 // Ajust to wchar_t elements
1497 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1498 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1499
1500 // To guess maximum size, add offset + len
1501 EndOfThisString = BeginOfThisString + Len;
1502 if (EndOfThisString > LargestPosition)
1503 LargestPosition = EndOfThisString;
1504 }
1505
1506 // Now read the remaining of tag and fill all strings. Subtract the directory
1507 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1508 if (SizeOfTag == 0)
1509 {
1510 Block = NULL;
1511 NumOfWchar = 0;
1512
1513 }
1514 else
1515 {
1516 Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
1517 if (Block == NULL) goto Error;
1518 NumOfWchar = SizeOfTag / sizeof(wchar_t);
1519 if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
1520 }
1521
1522 mlu ->MemPool = Block;
1523 mlu ->PoolSize = SizeOfTag;
1524 mlu ->PoolUsed = SizeOfTag;
1525
1526 *nItems = 1;
1527 return (void*) mlu;
1528
1529 Error:
1530 if (mlu) cmsMLUfree(mlu);
1531 return NULL;
1532 }
1533
1534 static
1535 cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1536 {
1537 cmsMLU* mlu =(cmsMLU*) Ptr;
1538 cmsUInt32Number HeaderSize;
1539 cmsUInt32Number Len, Offset;
1540 cmsUInt32Number i;
1541
1542 if (Ptr == NULL) {
1543
1544 // Empty placeholder
1545 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
1546 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1547 return TRUE;
1548 }
1549
1550 if (!_cmsWriteUInt32Number(io, mlu ->UsedEntries)) return FALSE;
1551 if (!_cmsWriteUInt32Number(io, 12)) return FALSE;
1552
1553 HeaderSize = 12 * mlu ->UsedEntries + sizeof(_cmsTagBase);
1554
1555 for (i=0; i < mlu ->UsedEntries; i++) {
1556
1557 Len = mlu ->Entries[i].Len;
1558 Offset = mlu ->Entries[i].StrW;
1559
1560 Len = (Len * sizeof(cmsUInt16Number)) / sizeof(wchar_t);
3121 prefix[31] = suffix[31] = 0;
3122
3123 v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix);
3124 if (v == NULL) {
3125 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many named colors '%d'", count);
3126 return NULL;
3127 }
3128
3129 if (nDeviceCoords > cmsMAXCHANNELS) {
3130 cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
3131 return 0;
3132 }
3133 for (i=0; i < count; i++) {
3134
3135 cmsUInt16Number PCS[3];
3136 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3137 char Root[33];
3138
3139 memset(Colorant, 0, sizeof(Colorant));
3140 if (io -> Read(io, Root, 32, 1) != 1) return NULL;
3141 Root[32] = 0; // To prevent exploits
3142
3143 if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
3144 if (!_cmsReadUInt16Array(io, nDeviceCoords, Colorant)) goto Error;
3145
3146 if (!cmsAppendNamedColor(v, Root, PCS, Colorant)) goto Error;
3147 }
3148
3149 *nItems = 1;
3150 return (void*) v ;
3151
3152 Error:
3153 cmsFreeNamedColorList(v);
3154 return NULL;
3155
3156 cmsUNUSED_PARAMETER(SizeOfTag);
3157 }
3158
3159
3160 // Saves a named color list into a named color profile
3161 static
3162 cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3163 {
3164 cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
3165 char prefix[33]; // Prefix for each color name
3166 char suffix[33]; // Suffix for each color name
3167 int i, nColors;
3168
3169 nColors = cmsNamedColorCount(NamedColorList);
3170
3171 if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
3172 if (!_cmsWriteUInt32Number(io, nColors)) return FALSE;
3173 if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE;
3174
3175 strncpy(prefix, (const char*) NamedColorList->Prefix, 32);
3176 strncpy(suffix, (const char*) NamedColorList->Suffix, 32);
3177
3178 suffix[32] = prefix[32] = 0;
3179
3180 if (!io ->Write(io, 32, prefix)) return FALSE;
3181 if (!io ->Write(io, 32, suffix)) return FALSE;
3182
3183 for (i=0; i < nColors; i++) {
3184
3185 cmsUInt16Number PCS[3];
3186 cmsUInt16Number Colorant[cmsMAXCHANNELS];
3187 char Root[33];
3188
3189 if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
3190 Root[32] = 0;
3191 if (!io ->Write(io, 32 , Root)) return FALSE;
3192 if (!_cmsWriteUInt16Array(io, 3, PCS)) return FALSE;
3193 if (!_cmsWriteUInt16Array(io, NamedColorList ->ColorantCount, Colorant)) return FALSE;
3194 }
3195
3196 return TRUE;
3197
3198 cmsUNUSED_PARAMETER(nItems);
3199 cmsUNUSED_PARAMETER(self);
3200 }
3201
3202 static
3203 void* Type_NamedColor_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
3204 {
3205 cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) Ptr;
3206
3207 return (void*) cmsDupNamedColorList(nc);
3208
3209 cmsUNUSED_PARAMETER(n);
3210 cmsUNUSED_PARAMETER(self);
3621
3622 // ********************************************************************************
3623 // Type cmsSigCrdInfoType
3624 // ********************************************************************************
3625
3626 /*
3627 This type contains the PostScript product name to which this profile corresponds
3628 and the names of the companion CRDs. Recall that a single profile can generate
3629 multiple CRDs. It is implemented as a MLU being the language code "PS" and then
3630 country varies for each element:
3631
3632 nm: PostScript product name
3633 #0: Rendering intent 0 CRD name
3634 #1: Rendering intent 1 CRD name
3635 #2: Rendering intent 2 CRD name
3636 #3: Rendering intent 3 CRD name
3637 */
3638
3639
3640
3641 // Auxiliary, read an string specified as count + string
3642 static
3643 cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
3644 {
3645 cmsUInt32Number Count;
3646 char* Text;
3647
3648 if (*SizeOfTag < sizeof(cmsUInt32Number)) return FALSE;
3649
3650 if (!_cmsReadUInt32Number(io, &Count)) return FALSE;
3651
3652 if (Count > UINT_MAX - sizeof(cmsUInt32Number)) return FALSE;
3653 if (*SizeOfTag < Count + sizeof(cmsUInt32Number)) return FALSE;
3654
3655 Text = (char*) _cmsMalloc(self ->ContextID, Count+1);
3656 if (Text == NULL) return FALSE;
3657
3658 if (io ->Read(io, Text, sizeof(cmsUInt8Number), Count) != Count) {
3659 _cmsFree(self ->ContextID, Text);
3660 return FALSE;
3661 }
3870
3871 static
3872 cmsBool Type_ViewingConditions_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
3873 {
3874 cmsICCViewingConditions* sc = (cmsICCViewingConditions* ) Ptr;
3875
3876 if (!_cmsWriteXYZNumber(io, &sc ->IlluminantXYZ)) return FALSE;
3877 if (!_cmsWriteXYZNumber(io, &sc ->SurroundXYZ)) return FALSE;
3878 if (!_cmsWriteUInt32Number(io, sc ->IlluminantType)) return FALSE;
3879
3880 return TRUE;
3881
3882 cmsUNUSED_PARAMETER(nItems);
3883 cmsUNUSED_PARAMETER(self);
3884 }
3885
3886
3887 static
3888 void* Type_ViewingConditions_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3889 {
3890 return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsICCViewingConditions));
3891
3892 cmsUNUSED_PARAMETER(n);
3893 }
3894
3895
3896 static
3897 void Type_ViewingConditions_Free(struct _cms_typehandler_struct* self, void* Ptr)
3898 {
3899 _cmsFree(self ->ContextID, Ptr);
3900 }
3901
3902
3903 // ********************************************************************************
3904 // Type cmsSigMultiProcessElementType
3905 // ********************************************************************************
3906
3907
3908 static
3909 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3910 {
4324 for (i=0; i < clut ->nEntries; i++) {
4325
4326 if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
4327 }
4328
4329 *nItems = 1;
4330 return mpe;
4331
4332 Error:
4333 *nItems = 0;
4334 if (mpe != NULL) cmsStageFree(mpe);
4335 return NULL;
4336
4337 cmsUNUSED_PARAMETER(SizeOfTag);
4338 }
4339
4340 // Write a CLUT in floating point
4341 static
4342 cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
4343 {
4344 cmsUInt8Number Dimensions8[16]; // 16 because the spec says 16 and not max number of channels
4345 cmsUInt32Number i;
4346 cmsStage* mpe = (cmsStage*) Ptr;
4347 _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe ->Data;
4348
4349 // Check for maximum number of channels supported by lcms
4350 if (mpe -> InputChannels > MAX_INPUT_DIMENSIONS) return FALSE;
4351
4352 // Only floats are supported in MPE
4353 if (clut ->HasFloatValues == FALSE) return FALSE;
4354
4355 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4356 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->OutputChannels)) return FALSE;
4357
4358 memset(Dimensions8, 0, sizeof(Dimensions8));
4359
4360 for (i=0; i < mpe ->InputChannels; i++)
4361 Dimensions8[i] = (cmsUInt8Number) clut ->Params ->nSamples[i];
4362
4363 if (!io ->Write(io, 16, Dimensions8)) return FALSE;
4364
4365 for (i=0; i < clut ->nEntries; i++) {
4366
4367 if (!_cmsWriteFloat32Number(io, clut ->Tab.TFloat[i])) return FALSE;
4368 }
4369
4370 return TRUE;
5469
5470 { cmsSigUcrBgTag, { 1, 1, { cmsSigUcrBgType}, NULL}, &SupportedTags[47]},
5471 { cmsSigCrdInfoTag, { 1, 1, { cmsSigCrdInfoType}, NULL}, &SupportedTags[48]},
5472
5473 { cmsSigDToB0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[49]},
5474 { cmsSigDToB1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[50]},
5475 { cmsSigDToB2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[51]},
5476 { cmsSigDToB3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[52]},
5477 { cmsSigBToD0Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[53]},
5478 { cmsSigBToD1Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[54]},
5479 { cmsSigBToD2Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[55]},
5480 { cmsSigBToD3Tag, { 1, 1, { cmsSigMultiProcessElementType}, NULL}, &SupportedTags[56]},
5481
5482 { cmsSigScreeningDescTag, { 1, 1, { cmsSigTextDescriptionType }, NULL}, &SupportedTags[57]},
5483 { cmsSigViewingConditionsTag, { 1, 1, { cmsSigViewingConditionsType }, NULL}, &SupportedTags[58]},
5484
5485 { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]},
5486 { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
5487 { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
5488 { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
5489 { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
5490 { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL}
5491
5492
5493 };
5494
5495 /*
5496 Not supported Why
5497 ======================= =========================================
5498 cmsSigOutputResponseTag ==> WARNING, POSSIBLE PATENT ON THIS SUBJECT!
5499 cmsSigNamedColorTag ==> Deprecated
5500 cmsSigDataTag ==> Ancient, unused
5501 cmsSigDeviceSettingsTag ==> Deprecated, useless
5502 */
5503
5504
5505 _cmsTagPluginChunkType _cmsTagPluginChunk = { NULL };
5506
5507
5508 // Duplicates the zone of memory used by the plug-in in the new context
5509 static
5510 void DupTagList(struct _cmsContext_struct* ctx,
|