1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2012 Marti Maria Saguer
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Software
11 // is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
29 // Multilocalized unicode objects. That is an attempt to encapsulate i18n.
32 // Allocates an empty multi localizad unicode object
33 cmsMLU
* CMSEXPORT
cmsMLUalloc(cmsContext ContextID
, cmsUInt32Number nItems
)
37 // nItems should be positive if given
38 if (nItems
<= 0) nItems
= 2;
40 // Create the container
41 mlu
= (cmsMLU
*) _cmsMallocZero(ContextID
, sizeof(cmsMLU
));
42 if (mlu
== NULL
) return NULL
;
44 mlu
->ContextID
= ContextID
;
47 mlu
->Entries
= (_cmsMLUentry
*) _cmsCalloc(ContextID
, nItems
, sizeof(_cmsMLUentry
));
48 if (mlu
->Entries
== NULL
) {
49 _cmsFree(ContextID
, mlu
);
53 // Ok, keep indexes up to date
54 mlu
->AllocatedEntries
= nItems
;
55 mlu
->UsedEntries
= 0;
61 // Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two.
63 cmsBool
GrowMLUpool(cmsMLU
* mlu
)
69 if (mlu
== NULL
) return FALSE
;
71 if (mlu
->PoolSize
== 0)
74 size
= mlu
->PoolSize
* 2;
77 if (size
< mlu
->PoolSize
) return FALSE
;
79 // Reallocate the pool
80 NewPtr
= _cmsRealloc(mlu
->ContextID
, mlu
->MemPool
, size
);
81 if (NewPtr
== NULL
) return FALSE
;
84 mlu
->MemPool
= NewPtr
;
85 mlu
->PoolSize
= size
;
91 // Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two.
93 cmsBool
GrowMLUtable(cmsMLU
* mlu
)
99 if (mlu
== NULL
) return FALSE
;
101 AllocatedEntries
= mlu
->AllocatedEntries
* 2;
103 // Check for overflow
104 if (AllocatedEntries
/ 2 != mlu
->AllocatedEntries
) return FALSE
;
106 // Reallocate the memory
107 NewPtr
= (_cmsMLUentry
*)_cmsRealloc(mlu
->ContextID
, mlu
->Entries
, AllocatedEntries
*sizeof(_cmsMLUentry
));
108 if (NewPtr
== NULL
) return FALSE
;
110 mlu
->Entries
= NewPtr
;
111 mlu
->AllocatedEntries
= AllocatedEntries
;
117 // Search for a specific entry in the structure. Language and Country are used.
119 int SearchMLUEntry(cmsMLU
* mlu
, cmsUInt16Number LanguageCode
, cmsUInt16Number CountryCode
)
124 if (mlu
== NULL
) return -1;
126 // Iterate whole table
127 for (i
=0; i
< mlu
->UsedEntries
; i
++) {
129 if (mlu
->Entries
[i
].Country
== CountryCode
&&
130 mlu
->Entries
[i
].Language
== LanguageCode
) return i
;
137 // Add a block of characters to the intended MLU. Language and country are specified.
138 // Only one entry for Language/country pair is allowed.
140 cmsBool
AddMLUBlock(cmsMLU
* mlu
, cmsUInt32Number size
, const wchar_t *Block
,
141 cmsUInt16Number LanguageCode
, cmsUInt16Number CountryCode
)
143 cmsUInt32Number Offset
;
147 if (mlu
== NULL
) return FALSE
;
149 // Is there any room available?
150 if (mlu
->UsedEntries
>= mlu
->AllocatedEntries
) {
151 if (!GrowMLUtable(mlu
)) return FALSE
;
154 // Only one ASCII string
155 if (SearchMLUEntry(mlu
, LanguageCode
, CountryCode
) >= 0) return FALSE
; // Only one is allowed!
158 while ((mlu
->PoolSize
- mlu
->PoolUsed
) < size
) {
160 if (!GrowMLUpool(mlu
)) return FALSE
;
163 Offset
= mlu
->PoolUsed
;
165 Ptr
= (cmsUInt8Number
*) mlu
->MemPool
;
166 if (Ptr
== NULL
) return FALSE
;
169 memmove(Ptr
+ Offset
, Block
, size
);
170 mlu
->PoolUsed
+= size
;
172 mlu
->Entries
[mlu
->UsedEntries
].StrW
= Offset
;
173 mlu
->Entries
[mlu
->UsedEntries
].Len
= size
;
174 mlu
->Entries
[mlu
->UsedEntries
].Country
= CountryCode
;
175 mlu
->Entries
[mlu
->UsedEntries
].Language
= LanguageCode
;
182 // Add an ASCII entry.
183 cmsBool CMSEXPORT
cmsMLUsetASCII(cmsMLU
* mlu
, const char LanguageCode
[3], const char CountryCode
[3], const char* ASCIIString
)
185 cmsUInt32Number i
, len
= (cmsUInt32Number
) strlen(ASCIIString
)+1;
188 cmsUInt16Number Lang
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) LanguageCode
);
189 cmsUInt16Number Cntry
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) CountryCode
);
191 if (mlu
== NULL
) return FALSE
;
193 WStr
= (wchar_t*) _cmsCalloc(mlu
->ContextID
, len
, sizeof(wchar_t));
194 if (WStr
== NULL
) return FALSE
;
196 for (i
=0; i
< len
; i
++)
197 WStr
[i
] = (wchar_t) ASCIIString
[i
];
199 rc
= AddMLUBlock(mlu
, len
* sizeof(wchar_t), WStr
, Lang
, Cntry
);
201 _cmsFree(mlu
->ContextID
, WStr
);
206 // We don't need any wcs support library
208 cmsUInt32Number
mywcslen(const wchar_t *s
)
216 return (cmsUInt32Number
)(p
- s
);
221 cmsBool CMSEXPORT
cmsMLUsetWide(cmsMLU
* mlu
, const char Language
[3], const char Country
[3], const wchar_t* WideString
)
223 cmsUInt16Number Lang
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) Language
);
224 cmsUInt16Number Cntry
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) Country
);
227 if (mlu
== NULL
) return FALSE
;
228 if (WideString
== NULL
) return FALSE
;
230 len
= (cmsUInt32Number
) (mywcslen(WideString
) + 1) * sizeof(wchar_t);
231 return AddMLUBlock(mlu
, len
, WideString
, Lang
, Cntry
);
234 // Duplicating a MLU is as easy as copying all members
235 cmsMLU
* CMSEXPORT
cmsMLUdup(const cmsMLU
* mlu
)
237 cmsMLU
* NewMlu
= NULL
;
239 // Duplicating a NULL obtains a NULL
240 if (mlu
== NULL
) return NULL
;
242 NewMlu
= cmsMLUalloc(mlu
->ContextID
, mlu
->UsedEntries
);
243 if (NewMlu
== NULL
) return NULL
;
245 // Should never happen
246 if (NewMlu
->AllocatedEntries
< mlu
->UsedEntries
)
250 if (NewMlu
->Entries
== NULL
|| mlu
->Entries
== NULL
) goto Error
;
252 memmove(NewMlu
->Entries
, mlu
->Entries
, mlu
->UsedEntries
* sizeof(_cmsMLUentry
));
253 NewMlu
->UsedEntries
= mlu
->UsedEntries
;
255 // The MLU may be empty
256 if (mlu
->PoolUsed
== 0) {
257 NewMlu
->MemPool
= NULL
;
261 NewMlu
->MemPool
= _cmsMalloc(mlu
->ContextID
, mlu
->PoolUsed
);
262 if (NewMlu
->MemPool
== NULL
) goto Error
;
265 NewMlu
->PoolSize
= mlu
->PoolUsed
;
267 if (NewMlu
->MemPool
== NULL
|| mlu
->MemPool
== NULL
) goto Error
;
269 memmove(NewMlu
->MemPool
, mlu
->MemPool
, mlu
->PoolUsed
);
270 NewMlu
->PoolUsed
= mlu
->PoolUsed
;
276 if (NewMlu
!= NULL
) cmsMLUfree(NewMlu
);
280 // Free any used memory
281 void CMSEXPORT
cmsMLUfree(cmsMLU
* mlu
)
285 if (mlu
-> Entries
) _cmsFree(mlu
->ContextID
, mlu
->Entries
);
286 if (mlu
-> MemPool
) _cmsFree(mlu
->ContextID
, mlu
->MemPool
);
288 _cmsFree(mlu
->ContextID
, mlu
);
293 // The algorithm first searches for an exact match of country and language, if not found it uses
294 // the Language. If none is found, first entry is used instead.
296 const wchar_t* _cmsMLUgetWide(const cmsMLU
* mlu
,
297 cmsUInt32Number
*len
,
298 cmsUInt16Number LanguageCode
, cmsUInt16Number CountryCode
,
299 cmsUInt16Number
* UsedLanguageCode
, cmsUInt16Number
* UsedCountryCode
)
305 if (mlu
== NULL
) return NULL
;
307 if (mlu
-> AllocatedEntries
<= 0) return NULL
;
309 for (i
=0; i
< mlu
->UsedEntries
; i
++) {
311 v
= mlu
->Entries
+ i
;
313 if (v
-> Language
== LanguageCode
) {
315 if (Best
== -1) Best
= i
;
317 if (v
-> Country
== CountryCode
) {
319 if (UsedLanguageCode
!= NULL
) *UsedLanguageCode
= v
->Language
;
320 if (UsedCountryCode
!= NULL
) *UsedCountryCode
= v
->Country
;
322 if (len
!= NULL
) *len
= v
->Len
;
324 return (wchar_t*) ((cmsUInt8Number
*) mlu
->MemPool
+ v
-> StrW
); // Found exact match
329 // No string found. Return First one
333 v
= mlu
->Entries
+ Best
;
335 if (UsedLanguageCode
!= NULL
) *UsedLanguageCode
= v
->Language
;
336 if (UsedCountryCode
!= NULL
) *UsedCountryCode
= v
->Country
;
338 if (len
!= NULL
) *len
= v
->Len
;
340 return(wchar_t*) ((cmsUInt8Number
*) mlu
->MemPool
+ v
->StrW
);
344 // Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len
345 cmsUInt32Number CMSEXPORT
cmsMLUgetASCII(const cmsMLU
* mlu
,
346 const char LanguageCode
[3], const char CountryCode
[3],
347 char* Buffer
, cmsUInt32Number BufferSize
)
350 cmsUInt32Number StrLen
= 0;
351 cmsUInt32Number ASCIIlen
, i
;
353 cmsUInt16Number Lang
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) LanguageCode
);
354 cmsUInt16Number Cntry
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) CountryCode
);
357 if (mlu
== NULL
) return 0;
360 Wide
= _cmsMLUgetWide(mlu
, &StrLen
, Lang
, Cntry
, NULL
, NULL
);
361 if (Wide
== NULL
) return 0;
363 ASCIIlen
= StrLen
/ sizeof(wchar_t);
365 // Maybe we want only to know the len?
366 if (Buffer
== NULL
) return ASCIIlen
+ 1; // Note the zero at the end
368 // No buffer size means no data
369 if (BufferSize
<= 0) return 0;
371 // Some clipping may be required
372 if (BufferSize
< ASCIIlen
+ 1)
373 ASCIIlen
= BufferSize
- 1;
375 // Precess each character
376 for (i
=0; i
< ASCIIlen
; i
++) {
381 Buffer
[i
] = (char) Wide
[i
];
384 // We put a termination "\0"
385 Buffer
[ASCIIlen
] = 0;
389 // Obtain a wide representation of the MLU, on depending on current locale settings
390 cmsUInt32Number CMSEXPORT
cmsMLUgetWide(const cmsMLU
* mlu
,
391 const char LanguageCode
[3], const char CountryCode
[3],
392 wchar_t* Buffer
, cmsUInt32Number BufferSize
)
395 cmsUInt32Number StrLen
= 0;
397 cmsUInt16Number Lang
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) LanguageCode
);
398 cmsUInt16Number Cntry
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) CountryCode
);
401 if (mlu
== NULL
) return 0;
403 Wide
= _cmsMLUgetWide(mlu
, &StrLen
, Lang
, Cntry
, NULL
, NULL
);
404 if (Wide
== NULL
) return 0;
406 // Maybe we want only to know the len?
407 if (Buffer
== NULL
) return StrLen
+ sizeof(wchar_t);
409 // No buffer size means no data
410 if (BufferSize
<= 0) return 0;
412 // Some clipping may be required
413 if (BufferSize
< StrLen
+ sizeof(wchar_t))
414 StrLen
= BufferSize
- + sizeof(wchar_t);
416 memmove(Buffer
, Wide
, StrLen
);
417 Buffer
[StrLen
/ sizeof(wchar_t)] = 0;
419 return StrLen
+ sizeof(wchar_t);
423 // Get also the language and country
424 CMSAPI cmsBool CMSEXPORT
cmsMLUgetTranslation(const cmsMLU
* mlu
,
425 const char LanguageCode
[3], const char CountryCode
[3],
426 char ObtainedLanguage
[3], char ObtainedCountry
[3])
430 cmsUInt16Number Lang
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) LanguageCode
);
431 cmsUInt16Number Cntry
= _cmsAdjustEndianess16(*(cmsUInt16Number
*) CountryCode
);
432 cmsUInt16Number ObtLang
, ObtCode
;
435 if (mlu
== NULL
) return FALSE
;
437 Wide
= _cmsMLUgetWide(mlu
, NULL
, Lang
, Cntry
, &ObtLang
, &ObtCode
);
438 if (Wide
== NULL
) return FALSE
;
440 // Get used language and code
441 *(cmsUInt16Number
*)ObtainedLanguage
= _cmsAdjustEndianess16(ObtLang
);
442 *(cmsUInt16Number
*)ObtainedCountry
= _cmsAdjustEndianess16(ObtCode
);
444 ObtainedLanguage
[2] = ObtainedCountry
[2] = 0;
450 // Get the number of translations in the MLU object
451 cmsUInt32Number CMSEXPORT
cmsMLUtranslationsCount(const cmsMLU
* mlu
)
453 if (mlu
== NULL
) return 0;
454 return mlu
->UsedEntries
;
457 // Get the language and country codes for a specific MLU index
458 cmsBool CMSEXPORT
cmsMLUtranslationsCodes(const cmsMLU
* mlu
,
460 char LanguageCode
[3],
465 if (mlu
== NULL
) return FALSE
;
467 if (idx
>= (cmsUInt32Number
) mlu
->UsedEntries
) return FALSE
;
469 entry
= &mlu
->Entries
[idx
];
471 *(cmsUInt16Number
*)LanguageCode
= _cmsAdjustEndianess16(entry
->Language
);
472 *(cmsUInt16Number
*)CountryCode
= _cmsAdjustEndianess16(entry
->Country
);
478 // Named color lists --------------------------------------------------------------------------------------------
480 // Grow the list to keep at least NumElements
482 cmsBool
GrowNamedColorList(cmsNAMEDCOLORLIST
* v
)
484 cmsUInt32Number size
;
485 _cmsNAMEDCOLOR
* NewPtr
;
487 if (v
== NULL
) return FALSE
;
489 if (v
->Allocated
== 0)
490 size
= 64; // Initial guess
492 size
= v
->Allocated
* 2;
494 // Keep a maximum color lists can grow, 100K entries seems reasonable
495 if (size
> 1024*100) return FALSE
;
497 NewPtr
= (_cmsNAMEDCOLOR
*) _cmsRealloc(v
->ContextID
, v
->List
, size
* sizeof(_cmsNAMEDCOLOR
));
502 v
->Allocated
= size
;
506 // Allocate a list for n elements
507 cmsNAMEDCOLORLIST
* CMSEXPORT
cmsAllocNamedColorList(cmsContext ContextID
, cmsUInt32Number n
, cmsUInt32Number ColorantCount
, const char* Prefix
, const char* Suffix
)
509 cmsNAMEDCOLORLIST
* v
= (cmsNAMEDCOLORLIST
*) _cmsMallocZero(ContextID
, sizeof(cmsNAMEDCOLORLIST
));
511 if (v
== NULL
) return NULL
;
515 v
->ContextID
= ContextID
;
517 while (v
-> Allocated
< n
)
518 GrowNamedColorList(v
);
520 strncpy(v
->Prefix
, Prefix
, sizeof(v
->Prefix
)-1);
521 strncpy(v
->Suffix
, Suffix
, sizeof(v
->Suffix
)-1);
522 v
->Prefix
[32] = v
->Suffix
[32] = 0;
524 v
-> ColorantCount
= ColorantCount
;
530 void CMSEXPORT
cmsFreeNamedColorList(cmsNAMEDCOLORLIST
* v
)
532 if (v
== NULL
) return;
533 if (v
->List
) _cmsFree(v
->ContextID
, v
->List
);
534 _cmsFree(v
->ContextID
, v
);
537 cmsNAMEDCOLORLIST
* CMSEXPORT
cmsDupNamedColorList(const cmsNAMEDCOLORLIST
* v
)
539 cmsNAMEDCOLORLIST
* NewNC
;
541 if (v
== NULL
) return NULL
;
543 NewNC
= cmsAllocNamedColorList(v
->ContextID
, v
-> nColors
, v
->ColorantCount
, v
->Prefix
, v
->Suffix
);
544 if (NewNC
== NULL
) return NULL
;
546 // For really large tables we need this
547 while (NewNC
->Allocated
< v
->Allocated
)
548 GrowNamedColorList(NewNC
);
550 memmove(NewNC
->Prefix
, v
->Prefix
, sizeof(v
->Prefix
));
551 memmove(NewNC
->Suffix
, v
->Suffix
, sizeof(v
->Suffix
));
552 NewNC
->ColorantCount
= v
->ColorantCount
;
553 memmove(NewNC
->List
, v
->List
, v
->nColors
* sizeof(_cmsNAMEDCOLOR
));
554 NewNC
->nColors
= v
->nColors
;
559 // Append a color to a list. List pointer may change if reallocated
560 cmsBool CMSEXPORT
cmsAppendNamedColor(cmsNAMEDCOLORLIST
* NamedColorList
,
562 cmsUInt16Number PCS
[3], cmsUInt16Number Colorant
[cmsMAXCHANNELS
])
566 if (NamedColorList
== NULL
) return FALSE
;
568 if (NamedColorList
->nColors
+ 1 > NamedColorList
->Allocated
) {
569 if (!GrowNamedColorList(NamedColorList
)) return FALSE
;
572 for (i
=0; i
< NamedColorList
->ColorantCount
; i
++)
573 NamedColorList
->List
[NamedColorList
->nColors
].DeviceColorant
[i
] = Colorant
== NULL
? 0 : Colorant
[i
];
575 for (i
=0; i
< 3; i
++)
576 NamedColorList
->List
[NamedColorList
->nColors
].PCS
[i
] = PCS
== NULL
? 0 : PCS
[i
];
580 strncpy(NamedColorList
->List
[NamedColorList
->nColors
].Name
, Name
, cmsMAX_PATH
-1);
581 NamedColorList
->List
[NamedColorList
->nColors
].Name
[cmsMAX_PATH
-1] = 0;
585 NamedColorList
->List
[NamedColorList
->nColors
].Name
[0] = 0;
588 NamedColorList
->nColors
++;
592 // Returns number of elements
593 cmsUInt32Number CMSEXPORT
cmsNamedColorCount(const cmsNAMEDCOLORLIST
* NamedColorList
)
595 if (NamedColorList
== NULL
) return 0;
596 return NamedColorList
->nColors
;
599 // Info aboout a given color
600 cmsBool CMSEXPORT
cmsNamedColorInfo(const cmsNAMEDCOLORLIST
* NamedColorList
, cmsUInt32Number nColor
,
604 cmsUInt16Number
* PCS
,
605 cmsUInt16Number
* Colorant
)
607 if (NamedColorList
== NULL
) return FALSE
;
609 if (nColor
>= cmsNamedColorCount(NamedColorList
)) return FALSE
;
611 if (Name
) strcpy(Name
, NamedColorList
->List
[nColor
].Name
);
612 if (Prefix
) strcpy(Prefix
, NamedColorList
->Prefix
);
613 if (Suffix
) strcpy(Suffix
, NamedColorList
->Suffix
);
615 memmove(PCS
, NamedColorList
->List
[nColor
].PCS
, 3*sizeof(cmsUInt16Number
));
618 memmove(Colorant
, NamedColorList
->List
[nColor
].DeviceColorant
,
619 sizeof(cmsUInt16Number
) * NamedColorList
->ColorantCount
);
625 // Search for a given color name (no prefix or suffix)
626 cmsInt32Number CMSEXPORT
cmsNamedColorIndex(const cmsNAMEDCOLORLIST
* NamedColorList
, const char* Name
)
630 if (NamedColorList
== NULL
) return -1;
631 n
= cmsNamedColorCount(NamedColorList
);
632 for (i
=0; i
< n
; i
++) {
633 if (cmsstrcasecmp(Name
, NamedColorList
->List
[i
].Name
) == 0)
640 // MPE support -----------------------------------------------------------------------------------------------------------------
643 void FreeNamedColorList(cmsStage
* mpe
)
645 cmsNAMEDCOLORLIST
* List
= (cmsNAMEDCOLORLIST
*) mpe
->Data
;
646 cmsFreeNamedColorList(List
);
650 void* DupNamedColorList(cmsStage
* mpe
)
652 cmsNAMEDCOLORLIST
* List
= (cmsNAMEDCOLORLIST
*) mpe
->Data
;
653 return cmsDupNamedColorList(List
);
657 void EvalNamedColorPCS(const cmsFloat32Number In
[], cmsFloat32Number Out
[], const cmsStage
*mpe
)
659 cmsNAMEDCOLORLIST
* NamedColorList
= (cmsNAMEDCOLORLIST
*) mpe
->Data
;
660 cmsUInt16Number index
= (cmsUInt16Number
) _cmsQuickSaturateWord(In
[0] * 65535.0);
662 if (index
>= NamedColorList
-> nColors
) {
663 cmsSignalError(NamedColorList
->ContextID
, cmsERROR_RANGE
, "Color %d out of range; ignored", index
);
667 // Named color always uses Lab
668 Out
[0] = (cmsFloat32Number
) (NamedColorList
->List
[index
].PCS
[0] / 65535.0);
669 Out
[1] = (cmsFloat32Number
) (NamedColorList
->List
[index
].PCS
[1] / 65535.0);
670 Out
[2] = (cmsFloat32Number
) (NamedColorList
->List
[index
].PCS
[2] / 65535.0);
675 void EvalNamedColor(const cmsFloat32Number In
[], cmsFloat32Number Out
[], const cmsStage
*mpe
)
677 cmsNAMEDCOLORLIST
* NamedColorList
= (cmsNAMEDCOLORLIST
*) mpe
->Data
;
678 cmsUInt16Number index
= (cmsUInt16Number
) _cmsQuickSaturateWord(In
[0] * 65535.0);
681 if (index
>= NamedColorList
-> nColors
) {
682 cmsSignalError(NamedColorList
->ContextID
, cmsERROR_RANGE
, "Color %d out of range; ignored", index
);
685 for (j
=0; j
< NamedColorList
->ColorantCount
; j
++)
686 Out
[j
] = (cmsFloat32Number
) (NamedColorList
->List
[index
].DeviceColorant
[j
] / 65535.0);
691 // Named color lookup element
692 cmsStage
* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST
* NamedColorList
, cmsBool UsePCS
)
694 return _cmsStageAllocPlaceholder(NamedColorList
->ContextID
,
695 cmsSigNamedColorElemType
,
696 1, UsePCS
? 3 : NamedColorList
->ColorantCount
,
697 UsePCS
? EvalNamedColorPCS
: EvalNamedColor
,
700 cmsDupNamedColorList(NamedColorList
));
705 // Retrieve the named color list from a transform. Should be first element in the LUT
706 cmsNAMEDCOLORLIST
* CMSEXPORT
cmsGetNamedColorList(cmsHTRANSFORM xform
)
708 _cmsTRANSFORM
* v
= (_cmsTRANSFORM
*) xform
;
709 cmsStage
* mpe
= v
->Lut
->Elements
;
711 if (mpe
->Type
!= cmsSigNamedColorElemType
) return NULL
;
712 return (cmsNAMEDCOLORLIST
*) mpe
->Data
;
716 // Profile sequence description routines -------------------------------------------------------------------------------------
718 cmsSEQ
* CMSEXPORT
cmsAllocProfileSequenceDescription(cmsContext ContextID
, cmsUInt32Number n
)
723 if (n
== 0) return NULL
;
725 // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked
726 // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door!
727 if (n
> 255) return NULL
;
729 Seq
= (cmsSEQ
*) _cmsMallocZero(ContextID
, sizeof(cmsSEQ
));
730 if (Seq
== NULL
) return NULL
;
732 Seq
-> ContextID
= ContextID
;
733 Seq
-> seq
= (cmsPSEQDESC
*) _cmsCalloc(ContextID
, n
, sizeof(cmsPSEQDESC
));
736 if (Seq
-> seq
== NULL
) {
737 _cmsFree(ContextID
, Seq
);
741 for (i
=0; i
< n
; i
++) {
742 Seq
-> seq
[i
].Manufacturer
= NULL
;
743 Seq
-> seq
[i
].Model
= NULL
;
744 Seq
-> seq
[i
].Description
= NULL
;
750 void CMSEXPORT
cmsFreeProfileSequenceDescription(cmsSEQ
* pseq
)
754 for (i
=0; i
< pseq
->n
; i
++) {
755 if (pseq
->seq
[i
].Manufacturer
!= NULL
) cmsMLUfree(pseq
->seq
[i
].Manufacturer
);
756 if (pseq
->seq
[i
].Model
!= NULL
) cmsMLUfree(pseq
->seq
[i
].Model
);
757 if (pseq
->seq
[i
].Description
!= NULL
) cmsMLUfree(pseq
->seq
[i
].Description
);
760 if (pseq
->seq
!= NULL
) _cmsFree(pseq
->ContextID
, pseq
->seq
);
761 _cmsFree(pseq
-> ContextID
, pseq
);
764 cmsSEQ
* CMSEXPORT
cmsDupProfileSequenceDescription(const cmsSEQ
* pseq
)
772 NewSeq
= (cmsSEQ
*) _cmsMalloc(pseq
-> ContextID
, sizeof(cmsSEQ
));
773 if (NewSeq
== NULL
) return NULL
;
776 NewSeq
-> seq
= (cmsPSEQDESC
*) _cmsCalloc(pseq
->ContextID
, pseq
->n
, sizeof(cmsPSEQDESC
));
777 if (NewSeq
->seq
== NULL
) goto Error
;
779 NewSeq
-> ContextID
= pseq
->ContextID
;
780 NewSeq
-> n
= pseq
->n
;
782 for (i
=0; i
< pseq
->n
; i
++) {
784 memmove(&NewSeq
->seq
[i
].attributes
, &pseq
->seq
[i
].attributes
, sizeof(cmsUInt64Number
));
786 NewSeq
->seq
[i
].deviceMfg
= pseq
->seq
[i
].deviceMfg
;
787 NewSeq
->seq
[i
].deviceModel
= pseq
->seq
[i
].deviceModel
;
788 memmove(&NewSeq
->seq
[i
].ProfileID
, &pseq
->seq
[i
].ProfileID
, sizeof(cmsProfileID
));
789 NewSeq
->seq
[i
].technology
= pseq
->seq
[i
].technology
;
791 NewSeq
->seq
[i
].Manufacturer
= cmsMLUdup(pseq
->seq
[i
].Manufacturer
);
792 NewSeq
->seq
[i
].Model
= cmsMLUdup(pseq
->seq
[i
].Model
);
793 NewSeq
->seq
[i
].Description
= cmsMLUdup(pseq
->seq
[i
].Description
);
801 cmsFreeProfileSequenceDescription(NewSeq
);
805 // Dictionaries --------------------------------------------------------------------------------------------------------
807 // Dictionaries are just very simple linked lists
810 typedef struct _cmsDICT_struct
{
812 cmsContext ContextID
;
816 // Allocate an empty dictionary
817 cmsHANDLE CMSEXPORT
cmsDictAlloc(cmsContext ContextID
)
819 _cmsDICT
* dict
= (_cmsDICT
*) _cmsMallocZero(ContextID
, sizeof(_cmsDICT
));
820 if (dict
== NULL
) return NULL
;
822 dict
->ContextID
= ContextID
;
823 return (cmsHANDLE
) dict
;
828 void CMSEXPORT
cmsDictFree(cmsHANDLE hDict
)
830 _cmsDICT
* dict
= (_cmsDICT
*) hDict
;
831 cmsDICTentry
*entry
, *next
;
833 _cmsAssert(dict
!= NULL
);
835 // Walk the list freeing all nodes
837 while (entry
!= NULL
) {
839 if (entry
->DisplayName
!= NULL
) cmsMLUfree(entry
->DisplayName
);
840 if (entry
->DisplayValue
!= NULL
) cmsMLUfree(entry
->DisplayValue
);
841 if (entry
->Name
!= NULL
) _cmsFree(dict
->ContextID
, entry
-> Name
);
842 if (entry
->Value
!= NULL
) _cmsFree(dict
->ContextID
, entry
-> Value
);
844 // Don't fall in the habitual trap...
846 _cmsFree(dict
->ContextID
, entry
);
851 _cmsFree(dict
->ContextID
, dict
);
855 // Duplicate a wide char string
857 wchar_t* DupWcs(cmsContext ContextID
, const wchar_t* ptr
)
859 if (ptr
== NULL
) return NULL
;
860 return (wchar_t*) _cmsDupMem(ContextID
, ptr
, (mywcslen(ptr
) + 1) * sizeof(wchar_t));
863 // Add a new entry to the linked list
864 cmsBool CMSEXPORT
cmsDictAddEntry(cmsHANDLE hDict
, const wchar_t* Name
, const wchar_t* Value
, const cmsMLU
*DisplayName
, const cmsMLU
*DisplayValue
)
866 _cmsDICT
* dict
= (_cmsDICT
*) hDict
;
869 _cmsAssert(dict
!= NULL
);
870 _cmsAssert(Name
!= NULL
);
872 entry
= (cmsDICTentry
*) _cmsMallocZero(dict
->ContextID
, sizeof(cmsDICTentry
));
873 if (entry
== NULL
) return FALSE
;
875 entry
->DisplayName
= cmsMLUdup(DisplayName
);
876 entry
->DisplayValue
= cmsMLUdup(DisplayValue
);
877 entry
->Name
= DupWcs(dict
->ContextID
, Name
);
878 entry
->Value
= DupWcs(dict
->ContextID
, Value
);
880 entry
->Next
= dict
->head
;
887 // Duplicates an existing dictionary
888 cmsHANDLE CMSEXPORT
cmsDictDup(cmsHANDLE hDict
)
890 _cmsDICT
* old_dict
= (_cmsDICT
*) hDict
;
894 _cmsAssert(old_dict
!= NULL
);
896 hNew
= cmsDictAlloc(old_dict
->ContextID
);
897 if (hNew
== NULL
) return NULL
;
899 // Walk the list freeing all nodes
900 entry
= old_dict
->head
;
901 while (entry
!= NULL
) {
903 if (!cmsDictAddEntry(hNew
, entry
->Name
, entry
->Value
, entry
->DisplayName
, entry
->DisplayValue
)) {
909 entry
= entry
-> Next
;
915 // Get a pointer to the linked list
916 const cmsDICTentry
* CMSEXPORT
cmsDictGetEntryList(cmsHANDLE hDict
)
918 _cmsDICT
* dict
= (_cmsDICT
*) hDict
;
920 if (dict
== NULL
) return NULL
;
924 // Helper For external languages
925 const cmsDICTentry
* CMSEXPORT
cmsDictNextEntry(const cmsDICTentry
* e
)
927 if (e
== NULL
) return NULL
;