summaryrefslogtreecommitdiff
path: root/thirdparty/liblcms2/src/cmsnamed.c
diff options
context:
space:
mode:
authorAntonin Descampe <antonin@gmail.com>2011-03-20 22:45:24 +0000
committerAntonin Descampe <antonin@gmail.com>2011-03-20 22:45:24 +0000
commit19f9147e1076d83dd1111609ca93a01085dbfb4f (patch)
tree8ba9fe2ac562b474f627c3ae8c90eefb7d0435a3 /thirdparty/liblcms2/src/cmsnamed.c
parent6bda73eeb2134963f64c3d67fdd11c1304cb14f9 (diff)
Removed the libs directory containing win32 compiled versions of libpng, libtiff and liblcms. Added a thirdparty directory to include main source files of libtiff, libpng, libz and liblcms to enable support of these formats in the codec executables. CMake will try to statically build these libraries if they are not found on the system. Note that these third party libraries are not required to build libopenjpeg (which has no dependencies).
Diffstat (limited to 'thirdparty/liblcms2/src/cmsnamed.c')
-rw-r--r--thirdparty/liblcms2/src/cmsnamed.c750
1 files changed, 750 insertions, 0 deletions
diff --git a/thirdparty/liblcms2/src/cmsnamed.c b/thirdparty/liblcms2/src/cmsnamed.c
new file mode 100644
index 00000000..d1a86b6e
--- /dev/null
+++ b/thirdparty/liblcms2/src/cmsnamed.c
@@ -0,0 +1,750 @@
+//---------------------------------------------------------------------------------
+//
+// Little Color Management System
+// Copyright (c) 1998-2010 Marti Maria Saguer
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+//---------------------------------------------------------------------------------
+//
+
+#include "lcms2_internal.h"
+
+// Multilocalized unicode objects. That is an attempt to encapsulate i18n.
+
+
+// Allocates an empty multi localizad unicode object
+cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems)
+{
+ cmsMLU* mlu;
+
+ // nItems should be positive if given
+ if (nItems <= 0) nItems = 2;
+
+ // Create the container
+ mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU));
+ if (mlu == NULL) return NULL;
+
+ mlu ->ContextID = ContextID;
+
+ // Create entry array
+ mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry));
+ if (mlu ->Entries == NULL) {
+ _cmsFree(ContextID, mlu);
+ return NULL;
+ }
+
+ // Ok, keep indexes up to date
+ mlu ->AllocatedEntries = nItems;
+ mlu ->UsedEntries = 0;
+
+ return mlu;
+}
+
+
+// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two.
+static
+cmsBool GrowMLUpool(cmsMLU* mlu)
+{
+ cmsUInt32Number size;
+ void *NewPtr;
+
+ // Sanity check
+ if (mlu == NULL) return FALSE;
+
+ if (mlu ->PoolSize == 0)
+ size = 256;
+ else
+ size = mlu ->PoolSize * 2;
+
+ // Check for overflow
+ if (size < mlu ->PoolSize) return FALSE;
+
+ // Reallocate the pool
+ NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size);
+ if (NewPtr == NULL) return FALSE;
+
+
+ mlu ->MemPool = NewPtr;
+ mlu ->PoolSize = size;
+
+ return TRUE;
+}
+
+
+// Grows a ntry table for a MLU. Each time this function is called, table size is multiplied times two.
+static
+cmsBool GrowMLUtable(cmsMLU* mlu)
+{
+ int AllocatedEntries;
+ _cmsMLUentry *NewPtr;
+
+ // Sanity check
+ if (mlu == NULL) return FALSE;
+
+ AllocatedEntries = mlu ->AllocatedEntries * 2;
+
+ // Check for overflow
+ if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE;
+
+ // Reallocate the memory
+ NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry));
+ if (NewPtr == NULL) return FALSE;
+
+ mlu ->Entries = NewPtr;
+ mlu ->AllocatedEntries = AllocatedEntries;
+
+ return TRUE;
+}
+
+
+// Search for a specific entry in the structure. Language and Country are used.
+static
+int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
+{
+ int i;
+
+ // Sanity check
+ if (mlu == NULL) return -1;
+
+ // Iterate whole table
+ for (i=0; i < mlu ->UsedEntries; i++) {
+
+ if (mlu ->Entries[i].Country == CountryCode &&
+ mlu ->Entries[i].Language == LanguageCode) return i;
+ }
+
+ // Not found
+ return -1;
+}
+
+// Add a block of characters to the intended MLU. Language and country are specified.
+// Only one entry for Language/country pair is allowed.
+static
+cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,
+ cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
+{
+ cmsUInt32Number Offset;
+ cmsUInt8Number* Ptr;
+
+ // Sanity check
+ if (mlu == NULL) return FALSE;
+
+ // Is there any room available?
+ if (mlu ->UsedEntries >= mlu ->AllocatedEntries) {
+ if (!GrowMLUtable(mlu)) return FALSE;
+ }
+
+ // Only one ASCII string
+ if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed!
+
+ // Check for size
+ while ((mlu ->PoolSize - mlu ->PoolUsed) < size) {
+
+ if (!GrowMLUpool(mlu)) return FALSE;
+ }
+
+ Offset = mlu ->PoolUsed;
+
+ Ptr = (cmsUInt8Number*) mlu ->MemPool;
+ if (Ptr == NULL) return FALSE;
+
+ // Set the entry
+ memmove(Ptr + Offset, Block, size);
+ mlu ->PoolUsed += size;
+
+ mlu ->Entries[mlu ->UsedEntries].StrW = Offset;
+ mlu ->Entries[mlu ->UsedEntries].Len = size;
+ mlu ->Entries[mlu ->UsedEntries].Country = CountryCode;
+ mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode;
+ mlu ->UsedEntries++;
+
+ return TRUE;
+}
+
+
+// Add an ASCII entry.
+cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
+{
+ cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1;
+ wchar_t* WStr;
+ cmsBool rc;
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+
+ if (mlu == NULL) return FALSE;
+
+ WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t));
+ if (WStr == NULL) return FALSE;
+
+ for (i=0; i < len; i++)
+ WStr[i] = (wchar_t) ASCIIString[i];
+
+ rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
+
+ _cmsFree(mlu ->ContextID, WStr);
+ return rc;
+
+}
+
+// We don't need any wcs support library
+static
+cmsUInt32Number mywcslen(const wchar_t *s)
+{
+ const wchar_t *p;
+
+ p = s;
+ while (*p)
+ p++;
+
+ return (cmsUInt32Number)(p - s);
+}
+
+
+// Add a wide entry
+cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString)
+{
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country);
+ cmsUInt32Number len;
+
+ if (mlu == NULL) return FALSE;
+ if (WideString == NULL) return FALSE;
+
+ len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t);
+ return AddMLUBlock(mlu, len, WideString, Lang, Cntry);
+}
+
+// Duplicating a MLU is as easy as copying all members
+cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu)
+{
+ cmsMLU* NewMlu = NULL;
+
+ // Duplicating a NULL obtains a NULL
+ if (mlu == NULL) return NULL;
+
+ NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries);
+ if (NewMlu == NULL) return NULL;
+
+ // Should never happen
+ if (NewMlu ->AllocatedEntries < mlu ->UsedEntries)
+ goto Error;
+
+ // Sanitize...
+ if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error;
+
+ memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry));
+ NewMlu ->UsedEntries = mlu ->UsedEntries;
+
+ // The MLU may be empty
+ if (mlu ->PoolUsed == 0) {
+ NewMlu ->MemPool = NULL;
+ }
+ else {
+ // It is not empty
+ NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed);
+ if (NewMlu ->MemPool == NULL) goto Error;
+ }
+
+ NewMlu ->PoolSize = mlu ->PoolUsed;
+
+ if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error;
+
+ memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed);
+ NewMlu ->PoolUsed = mlu ->PoolUsed;
+
+ return NewMlu;
+
+Error:
+
+ if (NewMlu != NULL) cmsMLUfree(NewMlu);
+ return NULL;
+}
+
+// Free any used memory
+void CMSEXPORT cmsMLUfree(cmsMLU* mlu)
+{
+ if (mlu) {
+
+ if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries);
+ if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool);
+
+ _cmsFree(mlu ->ContextID, mlu);
+ }
+}
+
+
+// The algorithm first searches for an exact match of country and language, if not found it uses
+// the Language. If none is found, first entry is used instead.
+static
+const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
+ cmsUInt32Number *len,
+ cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode,
+ cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode)
+{
+ int i;
+ int Best = -1;
+ _cmsMLUentry* v;
+
+ if (mlu == NULL) return NULL;
+
+ if (mlu -> AllocatedEntries <= 0) return NULL;
+
+ for (i=0; i < mlu ->UsedEntries; i++) {
+
+ v = mlu ->Entries + i;
+
+ if (v -> Language == LanguageCode) {
+
+ if (Best == -1) Best = i;
+
+ if (v -> Country == CountryCode) {
+
+ if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
+ if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
+
+ if (len != NULL) *len = v ->Len;
+
+ return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match
+ }
+ }
+ }
+
+ // No string found. Return First one
+ if (Best == -1)
+ Best = 0;
+
+ v = mlu ->Entries + Best;
+
+ if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
+ if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
+
+ if (len != NULL) *len = v ->Len;
+
+ return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
+}
+
+
+// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len
+cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ char* Buffer, cmsUInt32Number BufferSize)
+{
+ const wchar_t *Wide;
+ cmsUInt32Number StrLen = 0;
+ cmsUInt32Number ASCIIlen, i;
+
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+
+ // Sanitize
+ if (mlu == NULL) return 0;
+
+ // Get WideChar
+ Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
+ if (Wide == NULL) return 0;
+
+ ASCIIlen = StrLen / sizeof(wchar_t);
+
+ // Maybe we want only to know the len?
+ if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end
+
+ // No buffer size means no data
+ if (BufferSize <= 0) return 0;
+
+ // Some clipping may be required
+ if (BufferSize < ASCIIlen + 1)
+ ASCIIlen = BufferSize - 1;
+
+ // Precess each character
+ for (i=0; i < ASCIIlen; i++) {
+
+ if (Wide[i] == 0)
+ Buffer[i] = 0;
+ else
+ Buffer[i] = (char) Wide[i];
+ }
+
+ // We put a termination "\0"
+ Buffer[ASCIIlen] = 0;
+ return ASCIIlen + 1;
+}
+
+// Obtain a wide representation of the MLU, on depending on current locale settings
+cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ wchar_t* Buffer, cmsUInt32Number BufferSize)
+{
+ const wchar_t *Wide;
+ cmsUInt32Number StrLen = 0;
+
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+
+ // Sanitize
+ if (mlu == NULL) return 0;
+
+ Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
+ if (Wide == NULL) return 0;
+
+ // Maybe we want only to know the len?
+ if (Buffer == NULL) return StrLen + sizeof(wchar_t);
+
+ // No buffer size means no data
+ if (BufferSize <= 0) return 0;
+
+ // Some clipping may be required
+ if (BufferSize < StrLen + sizeof(wchar_t))
+ StrLen = BufferSize - + sizeof(wchar_t);
+
+ memmove(Buffer, Wide, StrLen);
+ Buffer[StrLen / sizeof(wchar_t)] = 0;
+
+ return StrLen + sizeof(wchar_t);
+}
+
+
+// Get also the language and country
+CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
+ const char LanguageCode[3], const char CountryCode[3],
+ char ObtainedLanguage[3], char ObtainedCountry[3])
+{
+ const wchar_t *Wide;
+
+ cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
+ cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
+ cmsUInt16Number ObtLang, ObtCode;
+
+ // Sanitize
+ if (mlu == NULL) return FALSE;
+
+ Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode);
+ if (Wide == NULL) return FALSE;
+
+ // Get used language and code
+ *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang);
+ *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode);
+
+ ObtainedLanguage[2] = ObtainedCountry[2] = 0;
+ return TRUE;
+}
+
+
+// Named color lists --------------------------------------------------------------------------------------------
+
+// Grow the list to keep at least NumElements
+static
+cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v)
+{
+ cmsUInt32Number size;
+ _cmsNAMEDCOLOR * NewPtr;
+
+ if (v == NULL) return FALSE;
+
+ if (v ->Allocated == 0)
+ size = 64; // Initial guess
+ else
+ size = v ->Allocated * 2;
+
+ // Keep a maximum color lists can grow, 100K entries seems reasonable
+ if (size > 1024*100) return FALSE;
+
+ NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR));
+ if (NewPtr == NULL)
+ return FALSE;
+
+ v ->List = NewPtr;
+ v ->Allocated = size;
+ return TRUE;
+}
+
+// Allocate a list for n elements
+cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix)
+{
+ cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));
+
+ if (v == NULL) return NULL;
+
+ v ->List = NULL;
+ v ->nColors = 0;
+ v ->ContextID = ContextID;
+
+ while (v -> Allocated < n)
+ GrowNamedColorList(v);
+
+ strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix));
+ strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix));
+ v -> ColorantCount = ColorantCount;
+
+ return v;
+}
+
+// Free a list
+void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v)
+{
+ if (v ->List) _cmsFree(v ->ContextID, v ->List);
+ if (v) _cmsFree(v ->ContextID, v);
+}
+
+cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
+{
+ cmsNAMEDCOLORLIST* NewNC;
+
+ if (v == NULL) return NULL;
+
+ NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix);
+ if (NewNC == NULL) return NULL;
+
+ // For really large tables we need this
+ while (NewNC ->Allocated < v ->Allocated)
+ GrowNamedColorList(NewNC);
+
+ memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix));
+ memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));
+ NewNC ->ColorantCount = v ->ColorantCount;
+ memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR));
+ NewNC ->nColors = v ->nColors;
+ return NewNC;
+}
+
+
+// Append a color to a list. List pointer may change if reallocated
+cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,
+ const char* Name,
+ cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS])
+{
+ cmsUInt32Number i;
+
+ if (NamedColorList == NULL) return FALSE;
+
+ if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) {
+ if (!GrowNamedColorList(NamedColorList)) return FALSE;
+ }
+
+ for (i=0; i < NamedColorList ->ColorantCount; i++)
+ NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i];
+
+ for (i=0; i < 3; i++)
+ NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i];
+
+ if (Name != NULL)
+ strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name,
+ sizeof(NamedColorList ->List[NamedColorList ->nColors].Name));
+ else
+ NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0;
+
+
+ NamedColorList ->nColors++;
+ return TRUE;
+}
+
+// Returns number of elements
+cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList)
+{
+ if (NamedColorList == NULL) return 0;
+ return NamedColorList ->nColors;
+}
+
+// Info aboout a given color
+cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
+ char* Name,
+ char* Prefix,
+ char* Suffix,
+ cmsUInt16Number* PCS,
+ cmsUInt16Number* Colorant)
+{
+ if (NamedColorList == NULL) return FALSE;
+
+ if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE;
+
+ if (Name) strcpy(Name, NamedColorList->List[nColor].Name);
+ if (Prefix) strcpy(Prefix, NamedColorList->Prefix);
+ if (Suffix) strcpy(Suffix, NamedColorList->Suffix);
+ if (PCS)
+ memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number));
+
+ if (Colorant)
+ memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant,
+ sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount);
+
+
+ return TRUE;
+}
+
+// Search for a given color name (no prefix or suffix)
+cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name)
+{
+ int i, n;
+
+ if (NamedColorList == NULL) return -1;
+ n = cmsNamedColorCount(NamedColorList);
+ for (i=0; i < n; i++) {
+ if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+// MPE support -----------------------------------------------------------------------------------------------------------------
+
+static
+void FreeNamedColorList(cmsStage* mpe)
+{
+ cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
+ cmsFreeNamedColorList(List);
+}
+
+static
+void* DupNamedColorList(cmsStage* mpe)
+{
+ cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
+ return cmsDupNamedColorList(List);
+}
+
+static
+void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
+{
+ cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
+ cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
+ cmsUInt32Number j;
+
+ if (index >= NamedColorList-> nColors) {
+ cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
+ }
+ else {
+ for (j=0; j < NamedColorList ->ColorantCount; j++)
+ Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0);
+ }
+}
+
+
+// Named color lookup element
+cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList)
+{
+ return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,
+ cmsSigNamedColorElemType,
+ 1, 3,
+ EvalNamedColor,
+ DupNamedColorList,
+ FreeNamedColorList,
+ cmsDupNamedColorList(NamedColorList));
+
+}
+
+
+// Retrieve the named color list from a transform. Should be first element in the LUT
+cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform)
+{
+ _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
+ cmsStage* mpe = v ->Lut->Elements;
+
+ if (mpe ->Type != cmsSigNamedColorElemType) return NULL;
+ return (cmsNAMEDCOLORLIST*) mpe ->Data;
+}
+
+
+// Profile sequence description routines -------------------------------------------------------------------------------------
+
+cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n)
+{
+ cmsSEQ* Seq;
+ cmsUInt32Number i;
+
+ if (n == 0) return NULL;
+
+ // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked
+ // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door!
+ if (n > 255) return NULL;
+
+ Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ));
+ if (Seq == NULL) return NULL;
+
+ Seq -> ContextID = ContextID;
+ Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC));
+ Seq -> n = n;
+
+
+ for (i=0; i < n; i++) {
+ Seq -> seq[i].Manufacturer = NULL;
+ Seq -> seq[i].Model = NULL;
+ Seq -> seq[i].Description = NULL;
+ }
+
+ return Seq;
+}
+
+void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
+{
+ cmsUInt32Number i;
+
+ for (i=0; i < pseq ->n; i++) {
+ if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
+ if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
+ if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
+ }
+
+ if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);
+ _cmsFree(pseq -> ContextID, pseq);
+}
+
+cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq)
+{
+ cmsSEQ *NewSeq;
+ cmsUInt32Number i;
+
+ if (pseq == NULL)
+ return NULL;
+
+ NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ));
+ if (NewSeq == NULL) return NULL;
+
+
+ NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC));
+ if (NewSeq ->seq == NULL) goto Error;
+
+ NewSeq -> ContextID = pseq ->ContextID;
+ NewSeq -> n = pseq ->n;
+
+ for (i=0; i < pseq->n; i++) {
+
+ memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number));
+
+ NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg;
+ NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel;
+ memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID));
+ NewSeq ->seq[i].technology = pseq ->seq[i].technology;
+
+ NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer);
+ NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model);
+ NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description);
+
+ }
+
+ return NewSeq;
+
+Error:
+
+ cmsFreeProfileSequenceDescription(NewSeq);
+ return NULL;
+}
+
+
+
+