Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c
38918 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324// This file is available under and governed by the GNU General Public25// License version 2 only, as published by the Free Software Foundation.26// However, the following notice accompanied the original version of this27// file:28//29//---------------------------------------------------------------------------------30//31// Little Color Management System32// Copyright (c) 1998-2020 Marti Maria Saguer33//34// Permission is hereby granted, free of charge, to any person obtaining35// a copy of this software and associated documentation files (the "Software"),36// to deal in the Software without restriction, including without limitation37// the rights to use, copy, modify, merge, publish, distribute, sublicense,38// and/or sell copies of the Software, and to permit persons to whom the Software39// is furnished to do so, subject to the following conditions:40//41// The above copyright notice and this permission notice shall be included in42// all copies or substantial portions of the Software.43//44// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,45// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO46// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND47// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE48// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION49// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION50// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.51//52//---------------------------------------------------------------------------------53//5455#include "lcms2_internal.h"5657// Multilocalized unicode objects. That is an attempt to encapsulate i18n.585960// Allocates an empty multi localizad unicode object61cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems)62{63cmsMLU* mlu;6465// nItems should be positive if given66if (nItems <= 0) nItems = 2;6768// Create the container69mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU));70if (mlu == NULL) return NULL;7172mlu ->ContextID = ContextID;7374// Create entry array75mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry));76if (mlu ->Entries == NULL) {77_cmsFree(ContextID, mlu);78return NULL;79}8081// Ok, keep indexes up to date82mlu ->AllocatedEntries = nItems;83mlu ->UsedEntries = 0;8485return mlu;86}878889// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two.90static91cmsBool GrowMLUpool(cmsMLU* mlu)92{93cmsUInt32Number size;94void *NewPtr;9596// Sanity check97if (mlu == NULL) return FALSE;9899if (mlu ->PoolSize == 0)100size = 256;101else102size = mlu ->PoolSize * 2;103104// Check for overflow105if (size < mlu ->PoolSize) return FALSE;106107// Reallocate the pool108NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size);109if (NewPtr == NULL) return FALSE;110111112mlu ->MemPool = NewPtr;113mlu ->PoolSize = size;114115return TRUE;116}117118119// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two.120static121cmsBool GrowMLUtable(cmsMLU* mlu)122{123cmsUInt32Number AllocatedEntries;124_cmsMLUentry *NewPtr;125126// Sanity check127if (mlu == NULL) return FALSE;128129AllocatedEntries = mlu ->AllocatedEntries * 2;130131// Check for overflow132if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE;133134// Reallocate the memory135NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry));136if (NewPtr == NULL) return FALSE;137138mlu ->Entries = NewPtr;139mlu ->AllocatedEntries = AllocatedEntries;140141return TRUE;142}143144145// Search for a specific entry in the structure. Language and Country are used.146static147int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)148{149cmsUInt32Number i;150151// Sanity check152if (mlu == NULL) return -1;153154// Iterate whole table155for (i=0; i < mlu ->UsedEntries; i++) {156157if (mlu ->Entries[i].Country == CountryCode &&158mlu ->Entries[i].Language == LanguageCode) return (int) i;159}160161// Not found162return -1;163}164165// Add a block of characters to the intended MLU. Language and country are specified.166// Only one entry for Language/country pair is allowed.167static168cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,169cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)170{171cmsUInt32Number Offset;172cmsUInt8Number* Ptr;173174// Sanity check175if (mlu == NULL) return FALSE;176177// Is there any room available?178if (mlu ->UsedEntries >= mlu ->AllocatedEntries) {179if (!GrowMLUtable(mlu)) return FALSE;180}181182// Only one ASCII string183if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed!184185// Check for size186while ((mlu ->PoolSize - mlu ->PoolUsed) < size) {187188if (!GrowMLUpool(mlu)) return FALSE;189}190191Offset = mlu ->PoolUsed;192193Ptr = (cmsUInt8Number*) mlu ->MemPool;194if (Ptr == NULL) return FALSE;195196// Set the entry197memmove(Ptr + Offset, Block, size);198mlu ->PoolUsed += size;199200mlu ->Entries[mlu ->UsedEntries].StrW = Offset;201mlu ->Entries[mlu ->UsedEntries].Len = size;202mlu ->Entries[mlu ->UsedEntries].Country = CountryCode;203mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode;204mlu ->UsedEntries++;205206return TRUE;207}208209// Convert from a 3-char code to a cmsUInt16Number. It is done in this way because some210// compilers don't properly align beginning of strings211212static213cmsUInt16Number strTo16(const char str[3])214{215const cmsUInt8Number* ptr8 = (const cmsUInt8Number*)str;216cmsUInt16Number n = (cmsUInt16Number)(((cmsUInt16Number)ptr8[0] << 8) | ptr8[1]);217218return n;219}220221static222void strFrom16(char str[3], cmsUInt16Number n)223{224str[0] = (char)(n >> 8);225str[1] = (char)n;226str[2] = (char)0;227228}229230// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)231cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)232{233cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);234wchar_t* WStr;235cmsBool rc;236cmsUInt16Number Lang = strTo16(LanguageCode);237cmsUInt16Number Cntry = strTo16(CountryCode);238239if (mlu == NULL) return FALSE;240241WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t));242if (WStr == NULL) return FALSE;243244for (i=0; i < len; i++)245WStr[i] = (wchar_t) ASCIIString[i];246247rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);248249_cmsFree(mlu ->ContextID, WStr);250return rc;251252}253254// We don't need any wcs support library255static256cmsUInt32Number mywcslen(const wchar_t *s)257{258const wchar_t *p;259260p = s;261while (*p)262p++;263264return (cmsUInt32Number)(p - s);265}266267// Add a wide entry. Do not add any \0 terminator (ICC1v43_2010-12.pdf page 61)268cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString)269{270cmsUInt16Number Lang = strTo16(Language);271cmsUInt16Number Cntry = strTo16(Country);272cmsUInt32Number len;273274if (mlu == NULL) return FALSE;275if (WideString == NULL) return FALSE;276277len = (cmsUInt32Number) (mywcslen(WideString)) * sizeof(wchar_t);278return AddMLUBlock(mlu, len, WideString, Lang, Cntry);279}280281// Duplicating a MLU is as easy as copying all members282cmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu)283{284cmsMLU* NewMlu = NULL;285286// Duplicating a NULL obtains a NULL287if (mlu == NULL) return NULL;288289NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries);290if (NewMlu == NULL) return NULL;291292// Should never happen293if (NewMlu ->AllocatedEntries < mlu ->UsedEntries)294goto Error;295296// Sanitize...297if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error;298299memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry));300NewMlu ->UsedEntries = mlu ->UsedEntries;301302// The MLU may be empty303if (mlu ->PoolUsed == 0) {304NewMlu ->MemPool = NULL;305}306else {307// It is not empty308NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed);309if (NewMlu ->MemPool == NULL) goto Error;310}311312NewMlu ->PoolSize = mlu ->PoolUsed;313314if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error;315316memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed);317NewMlu ->PoolUsed = mlu ->PoolUsed;318319return NewMlu;320321Error:322323if (NewMlu != NULL) cmsMLUfree(NewMlu);324return NULL;325}326327// Free any used memory328void CMSEXPORT cmsMLUfree(cmsMLU* mlu)329{330if (mlu) {331332if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries);333if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool);334335_cmsFree(mlu ->ContextID, mlu);336}337}338339340// The algorithm first searches for an exact match of country and language, if not found it uses341// the Language. If none is found, first entry is used instead.342static343const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,344cmsUInt32Number *len,345cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode,346cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode)347{348cmsUInt32Number i;349int Best = -1;350_cmsMLUentry* v;351352if (mlu == NULL) return NULL;353354if (mlu -> AllocatedEntries <= 0) return NULL;355356for (i=0; i < mlu ->UsedEntries; i++) {357358v = mlu ->Entries + i;359360if (v -> Language == LanguageCode) {361362if (Best == -1) Best = (int) i;363364if (v -> Country == CountryCode) {365366if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;367if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;368369if (len != NULL) *len = v ->Len;370371return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match372}373}374}375376// No string found. Return First one377if (Best == -1)378Best = 0;379380v = mlu ->Entries + Best;381382if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;383if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;384385if (len != NULL) *len = v ->Len;386387return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);388}389390391// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len392cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,393const char LanguageCode[3], const char CountryCode[3],394char* Buffer, cmsUInt32Number BufferSize)395{396const wchar_t *Wide;397cmsUInt32Number StrLen = 0;398cmsUInt32Number ASCIIlen, i;399400cmsUInt16Number Lang = strTo16(LanguageCode);401cmsUInt16Number Cntry = strTo16(CountryCode);402403// Sanitize404if (mlu == NULL) return 0;405406// Get WideChar407Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);408if (Wide == NULL) return 0;409410ASCIIlen = StrLen / sizeof(wchar_t);411412// Maybe we want only to know the len?413if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end414415// No buffer size means no data416if (BufferSize <= 0) return 0;417418// Some clipping may be required419if (BufferSize < ASCIIlen + 1)420ASCIIlen = BufferSize - 1;421422// Precess each character423for (i=0; i < ASCIIlen; i++) {424425if (Wide[i] == 0)426Buffer[i] = 0;427else428Buffer[i] = (char) Wide[i];429}430431// We put a termination "\0"432Buffer[ASCIIlen] = 0;433return ASCIIlen + 1;434}435436// Obtain a wide representation of the MLU, on depending on current locale settings437cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,438const char LanguageCode[3], const char CountryCode[3],439wchar_t* Buffer, cmsUInt32Number BufferSize)440{441const wchar_t *Wide;442cmsUInt32Number StrLen = 0;443444cmsUInt16Number Lang = strTo16(LanguageCode);445cmsUInt16Number Cntry = strTo16(CountryCode);446447// Sanitize448if (mlu == NULL) return 0;449450Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);451if (Wide == NULL) return 0;452453// Maybe we want only to know the len?454if (Buffer == NULL) return StrLen + sizeof(wchar_t);455456// No buffer size means no data457if (BufferSize <= 0) return 0;458459// Some clipping may be required460if (BufferSize < StrLen + sizeof(wchar_t))461StrLen = BufferSize - + sizeof(wchar_t);462463memmove(Buffer, Wide, StrLen);464Buffer[StrLen / sizeof(wchar_t)] = 0;465466return StrLen + sizeof(wchar_t);467}468469470// Get also the language and country471CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,472const char LanguageCode[3], const char CountryCode[3],473char ObtainedLanguage[3], char ObtainedCountry[3])474{475const wchar_t *Wide;476477cmsUInt16Number Lang = strTo16(LanguageCode);478cmsUInt16Number Cntry = strTo16(CountryCode);479cmsUInt16Number ObtLang, ObtCode;480481// Sanitize482if (mlu == NULL) return FALSE;483484Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode);485if (Wide == NULL) return FALSE;486487// Get used language and code488strFrom16(ObtainedLanguage, ObtLang);489strFrom16(ObtainedCountry, ObtCode);490491return TRUE;492}493494495496// Get the number of translations in the MLU object497cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu)498{499if (mlu == NULL) return 0;500return mlu->UsedEntries;501}502503// Get the language and country codes for a specific MLU index504cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu,505cmsUInt32Number idx,506char LanguageCode[3],507char CountryCode[3])508{509_cmsMLUentry *entry;510511if (mlu == NULL) return FALSE;512513if (idx >= mlu->UsedEntries) return FALSE;514515entry = &mlu->Entries[idx];516517strFrom16(LanguageCode, entry->Language);518strFrom16(CountryCode, entry->Country);519520return TRUE;521}522523524// Named color lists --------------------------------------------------------------------------------------------525526// Grow the list to keep at least NumElements527static528cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v)529{530cmsUInt32Number size;531_cmsNAMEDCOLOR * NewPtr;532533if (v == NULL) return FALSE;534535if (v ->Allocated == 0)536size = 64; // Initial guess537else538size = v ->Allocated * 2;539540// Keep a maximum color lists can grow, 100K entries seems reasonable541if (size > 1024 * 100) {542_cmsFree(v->ContextID, (void*) v->List);543v->List = NULL;544return FALSE;545}546547NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR));548if (NewPtr == NULL)549return FALSE;550551v ->List = NewPtr;552v ->Allocated = size;553return TRUE;554}555556// Allocate a list for n elements557cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix)558{559cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));560561if (v == NULL) return NULL;562563v ->List = NULL;564v ->nColors = 0;565v ->ContextID = ContextID;566567while (v -> Allocated < n) {568if (!GrowNamedColorList(v)) {569cmsFreeNamedColorList(v);570return NULL;571}572}573574strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1);575strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1);576v->Prefix[32] = v->Suffix[32] = 0;577578v -> ColorantCount = ColorantCount;579580return v;581}582583// Free a list584void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v)585{586if (v == NULL) return;587if (v ->List) _cmsFree(v ->ContextID, v ->List);588_cmsFree(v ->ContextID, v);589}590591cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)592{593cmsNAMEDCOLORLIST* NewNC;594595if (v == NULL) return NULL;596597NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix);598if (NewNC == NULL) return NULL;599600// For really large tables we need this601while (NewNC ->Allocated < v ->Allocated){602if (!GrowNamedColorList(NewNC))603{604cmsFreeNamedColorList(NewNC);605return NULL;606}607}608609memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix));610memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));611NewNC ->ColorantCount = v ->ColorantCount;612memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR));613NewNC ->nColors = v ->nColors;614return NewNC;615}616617618// Append a color to a list. List pointer may change if reallocated619cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,620const char* Name,621cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS])622{623cmsUInt32Number i;624625if (NamedColorList == NULL) return FALSE;626627if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) {628if (!GrowNamedColorList(NamedColorList)) return FALSE;629}630631for (i=0; i < NamedColorList ->ColorantCount; i++)632NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL ? (cmsUInt16Number)0 : Colorant[i];633634for (i=0; i < 3; i++)635NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? (cmsUInt16Number) 0 : PCS[i];636637if (Name != NULL) {638639strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1);640NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0;641642}643else644NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0;645646647NamedColorList ->nColors++;648return TRUE;649}650651// Returns number of elements652cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList)653{654if (NamedColorList == NULL) return 0;655return NamedColorList ->nColors;656}657658// Info aboout a given color659cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,660char* Name,661char* Prefix,662char* Suffix,663cmsUInt16Number* PCS,664cmsUInt16Number* Colorant)665{666if (NamedColorList == NULL) return FALSE;667668if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE;669670// strcpy instead of strncpy because many apps are using small buffers671if (Name) strcpy(Name, NamedColorList->List[nColor].Name);672if (Prefix) strcpy(Prefix, NamedColorList->Prefix);673if (Suffix) strcpy(Suffix, NamedColorList->Suffix);674if (PCS)675memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number));676677if (Colorant)678memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant,679sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount);680681682return TRUE;683}684685// Search for a given color name (no prefix or suffix)686cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name)687{688cmsUInt32Number i;689cmsUInt32Number n;690691if (NamedColorList == NULL) return -1;692n = cmsNamedColorCount(NamedColorList);693for (i=0; i < n; i++) {694if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0)695return (cmsInt32Number) i;696}697698return -1;699}700701// MPE support -----------------------------------------------------------------------------------------------------------------702703static704void FreeNamedColorList(cmsStage* mpe)705{706cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;707cmsFreeNamedColorList(List);708}709710static711void* DupNamedColorList(cmsStage* mpe)712{713cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;714return cmsDupNamedColorList(List);715}716717static718void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)719{720cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;721cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);722723if (index >= NamedColorList-> nColors) {724cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range", index);725Out[0] = Out[1] = Out[2] = 0.0f;726}727else {728729// Named color always uses Lab730Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0);731Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0);732Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0);733}734}735736static737void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)738{739cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;740cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);741cmsUInt32Number j;742743if (index >= NamedColorList-> nColors) {744cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range", index);745for (j = 0; j < NamedColorList->ColorantCount; j++)746Out[j] = 0.0f;747748}749else {750for (j=0; j < NamedColorList ->ColorantCount; j++)751Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0);752}753}754755756// Named color lookup element757cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS)758{759return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,760cmsSigNamedColorElemType,7611, UsePCS ? 3 : NamedColorList ->ColorantCount,762UsePCS ? EvalNamedColorPCS : EvalNamedColor,763DupNamedColorList,764FreeNamedColorList,765cmsDupNamedColorList(NamedColorList));766767}768769770// Retrieve the named color list from a transform. Should be first element in the LUT771cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform)772{773_cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;774cmsStage* mpe = v ->Lut->Elements;775776if (mpe ->Type != cmsSigNamedColorElemType) return NULL;777return (cmsNAMEDCOLORLIST*) mpe ->Data;778}779780781// Profile sequence description routines -------------------------------------------------------------------------------------782783cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n)784{785cmsSEQ* Seq;786cmsUInt32Number i;787788if (n == 0) return NULL;789790// In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked791// in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door!792if (n > 255) return NULL;793794Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ));795if (Seq == NULL) return NULL;796797Seq -> ContextID = ContextID;798Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC));799Seq -> n = n;800801if (Seq -> seq == NULL) {802_cmsFree(ContextID, Seq);803return NULL;804}805806for (i=0; i < n; i++) {807Seq -> seq[i].Manufacturer = NULL;808Seq -> seq[i].Model = NULL;809Seq -> seq[i].Description = NULL;810}811812return Seq;813}814815void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)816{817cmsUInt32Number i;818819for (i=0; i < pseq ->n; i++) {820if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);821if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);822if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);823}824825if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);826_cmsFree(pseq -> ContextID, pseq);827}828829cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq)830{831cmsSEQ *NewSeq;832cmsUInt32Number i;833834if (pseq == NULL)835return NULL;836837NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ));838if (NewSeq == NULL) return NULL;839840841NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC));842if (NewSeq ->seq == NULL) goto Error;843844NewSeq -> ContextID = pseq ->ContextID;845NewSeq -> n = pseq ->n;846847for (i=0; i < pseq->n; i++) {848849memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number));850851NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg;852NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel;853memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID));854NewSeq ->seq[i].technology = pseq ->seq[i].technology;855856NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer);857NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model);858NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description);859860}861862return NewSeq;863864Error:865866cmsFreeProfileSequenceDescription(NewSeq);867return NULL;868}869870// Dictionaries --------------------------------------------------------------------------------------------------------871872// Dictionaries are just very simple linked lists873874875typedef struct _cmsDICT_struct {876cmsDICTentry* head;877cmsContext ContextID;878} _cmsDICT;879880881// Allocate an empty dictionary882cmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID)883{884_cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT));885if (dict == NULL) return NULL;886887dict ->ContextID = ContextID;888return (cmsHANDLE) dict;889890}891892// Dispose resources893void CMSEXPORT cmsDictFree(cmsHANDLE hDict)894{895_cmsDICT* dict = (_cmsDICT*) hDict;896cmsDICTentry *entry, *next;897898_cmsAssert(dict != NULL);899900// Walk the list freeing all nodes901entry = dict ->head;902while (entry != NULL) {903904if (entry ->DisplayName != NULL) cmsMLUfree(entry ->DisplayName);905if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue);906if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name);907if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value);908909// Don't fall in the habitual trap...910next = entry ->Next;911_cmsFree(dict ->ContextID, entry);912913entry = next;914}915916_cmsFree(dict ->ContextID, dict);917}918919920// Duplicate a wide char string921static922wchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr)923{924if (ptr == NULL) return NULL;925return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t));926}927928// Add a new entry to the linked list929cmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue)930{931_cmsDICT* dict = (_cmsDICT*) hDict;932cmsDICTentry *entry;933934_cmsAssert(dict != NULL);935_cmsAssert(Name != NULL);936937entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry));938if (entry == NULL) return FALSE;939940entry ->DisplayName = cmsMLUdup(DisplayName);941entry ->DisplayValue = cmsMLUdup(DisplayValue);942entry ->Name = DupWcs(dict ->ContextID, Name);943entry ->Value = DupWcs(dict ->ContextID, Value);944945entry ->Next = dict ->head;946dict ->head = entry;947948return TRUE;949}950951952// Duplicates an existing dictionary953cmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict)954{955_cmsDICT* old_dict = (_cmsDICT*) hDict;956cmsHANDLE hNew;957cmsDICTentry *entry;958959_cmsAssert(old_dict != NULL);960961hNew = cmsDictAlloc(old_dict ->ContextID);962if (hNew == NULL) return NULL;963964// Walk the list freeing all nodes965entry = old_dict ->head;966while (entry != NULL) {967968if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) {969970cmsDictFree(hNew);971return NULL;972}973974entry = entry -> Next;975}976977return hNew;978}979980// Get a pointer to the linked list981const cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict)982{983_cmsDICT* dict = (_cmsDICT*) hDict;984985if (dict == NULL) return NULL;986return dict ->head;987}988989// Helper For external languages990const cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e)991{992if (e == NULL) return NULL;993return e ->Next;994}995996997