0N/A/*
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A// This file is available under and governed by the GNU General Public
0N/A// License version 2 only, as published by the Free Software Foundation.
0N/A// However, the following notice accompanied the original version of this
0N/A// file:
0N/A//
2693N/A//---------------------------------------------------------------------------------
0N/A//
2693N/A// Little Color Management System
6271N/A// Copyright (c) 1998-2012 Marti Maria Saguer
0N/A//
0N/A// Permission is hereby granted, free of charge, to any person obtaining
0N/A// a copy of this software and associated documentation files (the "Software"),
0N/A// to deal in the Software without restriction, including without limitation
0N/A// the rights to use, copy, modify, merge, publish, distribute, sublicense,
0N/A// and/or sell copies of the Software, and to permit persons to whom the Software
0N/A// is furnished to do so, subject to the following conditions:
0N/A//
0N/A// The above copyright notice and this permission notice shall be included in
0N/A// all copies or substantial portions of the Software.
0N/A//
0N/A// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0N/A// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
0N/A// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0N/A// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0N/A// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0N/A// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0N/A// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2693N/A//
2693N/A//---------------------------------------------------------------------------------
2693N/A//
2693N/A
2693N/A#include "lcms2_internal.h"
2693N/A
2693N/A// Multilocalized unicode objects. That is an attempt to encapsulate i18n.
2693N/A
2693N/A
2693N/A// Allocates an empty multi localizad unicode object
2693N/AcmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems)
2693N/A{
2693N/A cmsMLU* mlu;
2693N/A
2693N/A // nItems should be positive if given
2693N/A if (nItems <= 0) nItems = 2;
2693N/A
2693N/A // Create the container
2693N/A mlu = (cmsMLU*) _cmsMallocZero(ContextID, sizeof(cmsMLU));
2693N/A if (mlu == NULL) return NULL;
2693N/A
2693N/A mlu ->ContextID = ContextID;
2693N/A
2693N/A // Create entry array
2693N/A mlu ->Entries = (_cmsMLUentry*) _cmsCalloc(ContextID, nItems, sizeof(_cmsMLUentry));
2693N/A if (mlu ->Entries == NULL) {
2693N/A _cmsFree(ContextID, mlu);
2693N/A return NULL;
2693N/A }
2693N/A
2693N/A // Ok, keep indexes up to date
2693N/A mlu ->AllocatedEntries = nItems;
2693N/A mlu ->UsedEntries = 0;
2693N/A
2693N/A return mlu;
2693N/A}
0N/A
0N/A
2693N/A// Grows a mempool table for a MLU. Each time this function is called, mempool size is multiplied times two.
2693N/Astatic
2693N/AcmsBool GrowMLUpool(cmsMLU* mlu)
2693N/A{
2693N/A cmsUInt32Number size;
2693N/A void *NewPtr;
2693N/A
2693N/A // Sanity check
2693N/A if (mlu == NULL) return FALSE;
2693N/A
2693N/A if (mlu ->PoolSize == 0)
2693N/A size = 256;
2693N/A else
2693N/A size = mlu ->PoolSize * 2;
2693N/A
2693N/A // Check for overflow
2693N/A if (size < mlu ->PoolSize) return FALSE;
2693N/A
2693N/A // Reallocate the pool
2693N/A NewPtr = _cmsRealloc(mlu ->ContextID, mlu ->MemPool, size);
2693N/A if (NewPtr == NULL) return FALSE;
2693N/A
2693N/A
2693N/A mlu ->MemPool = NewPtr;
2693N/A mlu ->PoolSize = size;
0N/A
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A
6271N/A// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two.
2693N/Astatic
2693N/AcmsBool GrowMLUtable(cmsMLU* mlu)
2693N/A{
2693N/A int AllocatedEntries;
2693N/A _cmsMLUentry *NewPtr;
2693N/A
2693N/A // Sanity check
2693N/A if (mlu == NULL) return FALSE;
0N/A
2693N/A AllocatedEntries = mlu ->AllocatedEntries * 2;
2693N/A
2693N/A // Check for overflow
6271N/A if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE;
2693N/A
2693N/A // Reallocate the memory
2693N/A NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry));
2693N/A if (NewPtr == NULL) return FALSE;
2693N/A
2693N/A mlu ->Entries = NewPtr;
2693N/A mlu ->AllocatedEntries = AllocatedEntries;
2693N/A
2693N/A return TRUE;
2693N/A}
0N/A
0N/A
2693N/A// Search for a specific entry in the structure. Language and Country are used.
0N/Astatic
2693N/Aint SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
0N/A{
2693N/A int i;
2693N/A
2693N/A // Sanity check
2693N/A if (mlu == NULL) return -1;
2693N/A
2693N/A // Iterate whole table
2693N/A for (i=0; i < mlu ->UsedEntries; i++) {
2693N/A
2693N/A if (mlu ->Entries[i].Country == CountryCode &&
2693N/A mlu ->Entries[i].Language == LanguageCode) return i;
2693N/A }
2693N/A
2693N/A // Not found
2693N/A return -1;
2693N/A}
0N/A
2693N/A// Add a block of characters to the intended MLU. Language and country are specified.
2693N/A// Only one entry for Language/country pair is allowed.
2693N/Astatic
2693N/AcmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,
2693N/A cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode)
2693N/A{
2693N/A cmsUInt32Number Offset;
2693N/A cmsUInt8Number* Ptr;
2693N/A
2693N/A // Sanity check
2693N/A if (mlu == NULL) return FALSE;
2693N/A
2693N/A // Is there any room available?
2693N/A if (mlu ->UsedEntries >= mlu ->AllocatedEntries) {
2693N/A if (!GrowMLUtable(mlu)) return FALSE;
2693N/A }
2693N/A
2693N/A // Only one ASCII string
2693N/A if (SearchMLUEntry(mlu, LanguageCode, CountryCode) >= 0) return FALSE; // Only one is allowed!
2693N/A
2693N/A // Check for size
2693N/A while ((mlu ->PoolSize - mlu ->PoolUsed) < size) {
2693N/A
2693N/A if (!GrowMLUpool(mlu)) return FALSE;
2693N/A }
2693N/A
2693N/A Offset = mlu ->PoolUsed;
2693N/A
2693N/A Ptr = (cmsUInt8Number*) mlu ->MemPool;
2693N/A if (Ptr == NULL) return FALSE;
0N/A
2693N/A // Set the entry
2693N/A memmove(Ptr + Offset, Block, size);
2693N/A mlu ->PoolUsed += size;
2693N/A
2693N/A mlu ->Entries[mlu ->UsedEntries].StrW = Offset;
2693N/A mlu ->Entries[mlu ->UsedEntries].Len = size;
2693N/A mlu ->Entries[mlu ->UsedEntries].Country = CountryCode;
2693N/A mlu ->Entries[mlu ->UsedEntries].Language = LanguageCode;
2693N/A mlu ->UsedEntries++;
2693N/A
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A
2693N/A// Add an ASCII entry.
2693N/AcmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
2693N/A{
2693N/A cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString)+1;
2693N/A wchar_t* WStr;
2693N/A cmsBool rc;
2693N/A cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
2693N/A cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
2693N/A
2693N/A if (mlu == NULL) return FALSE;
0N/A
2693N/A WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t));
2693N/A if (WStr == NULL) return FALSE;
2693N/A
2693N/A for (i=0; i < len; i++)
2693N/A WStr[i] = (wchar_t) ASCIIString[i];
2693N/A
2693N/A rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
2693N/A
2693N/A _cmsFree(mlu ->ContextID, WStr);
2693N/A return rc;
2693N/A
2693N/A}
0N/A
2693N/A// We don't need any wcs support library
2693N/Astatic
2693N/AcmsUInt32Number mywcslen(const wchar_t *s)
2693N/A{
2693N/A const wchar_t *p;
2693N/A
2693N/A p = s;
2693N/A while (*p)
2693N/A p++;
2693N/A
2693N/A return (cmsUInt32Number)(p - s);
2693N/A}
0N/A
0N/A
2693N/A// Add a wide entry
2693N/AcmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char Language[3], const char Country[3], const wchar_t* WideString)
2693N/A{
2693N/A cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) Language);
2693N/A cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) Country);
2693N/A cmsUInt32Number len;
2693N/A
2693N/A if (mlu == NULL) return FALSE;
2693N/A if (WideString == NULL) return FALSE;
2693N/A
2693N/A len = (cmsUInt32Number) (mywcslen(WideString) + 1) * sizeof(wchar_t);
2693N/A return AddMLUBlock(mlu, len, WideString, Lang, Cntry);
2693N/A}
2693N/A
2693N/A// Duplicating a MLU is as easy as copying all members
2693N/AcmsMLU* CMSEXPORT cmsMLUdup(const cmsMLU* mlu)
2693N/A{
2693N/A cmsMLU* NewMlu = NULL;
2693N/A
2693N/A // Duplicating a NULL obtains a NULL
2693N/A if (mlu == NULL) return NULL;
2693N/A
2693N/A NewMlu = cmsMLUalloc(mlu ->ContextID, mlu ->UsedEntries);
2693N/A if (NewMlu == NULL) return NULL;
2693N/A
2693N/A // Should never happen
2693N/A if (NewMlu ->AllocatedEntries < mlu ->UsedEntries)
2693N/A goto Error;
2693N/A
2693N/A // Sanitize...
2693N/A if (NewMlu ->Entries == NULL || mlu ->Entries == NULL) goto Error;
2693N/A
2693N/A memmove(NewMlu ->Entries, mlu ->Entries, mlu ->UsedEntries * sizeof(_cmsMLUentry));
2693N/A NewMlu ->UsedEntries = mlu ->UsedEntries;
2693N/A
2693N/A // The MLU may be empty
2693N/A if (mlu ->PoolUsed == 0) {
2693N/A NewMlu ->MemPool = NULL;
2693N/A }
2693N/A else {
2693N/A // It is not empty
2693N/A NewMlu ->MemPool = _cmsMalloc(mlu ->ContextID, mlu ->PoolUsed);
2693N/A if (NewMlu ->MemPool == NULL) goto Error;
2693N/A }
2693N/A
2693N/A NewMlu ->PoolSize = mlu ->PoolUsed;
2693N/A
2693N/A if (NewMlu ->MemPool == NULL || mlu ->MemPool == NULL) goto Error;
2693N/A
2693N/A memmove(NewMlu ->MemPool, mlu->MemPool, mlu ->PoolUsed);
2693N/A NewMlu ->PoolUsed = mlu ->PoolUsed;
0N/A
2693N/A return NewMlu;
2693N/A
2693N/AError:
2693N/A
2693N/A if (NewMlu != NULL) cmsMLUfree(NewMlu);
2693N/A return NULL;
2693N/A}
2693N/A
2693N/A// Free any used memory
2693N/Avoid CMSEXPORT cmsMLUfree(cmsMLU* mlu)
2693N/A{
2693N/A if (mlu) {
2693N/A
2693N/A if (mlu -> Entries) _cmsFree(mlu ->ContextID, mlu->Entries);
2693N/A if (mlu -> MemPool) _cmsFree(mlu ->ContextID, mlu->MemPool);
2693N/A
2693N/A _cmsFree(mlu ->ContextID, mlu);
2693N/A }
2693N/A}
2693N/A
2693N/A
2693N/A// The algorithm first searches for an exact match of country and language, if not found it uses
2693N/A// the Language. If none is found, first entry is used instead.
2693N/Astatic
2693N/Aconst wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
2693N/A cmsUInt32Number *len,
2693N/A cmsUInt16Number LanguageCode, cmsUInt16Number CountryCode,
2693N/A cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode)
2693N/A{
2693N/A int i;
2693N/A int Best = -1;
2693N/A _cmsMLUentry* v;
2693N/A
2693N/A if (mlu == NULL) return NULL;
2693N/A
2693N/A if (mlu -> AllocatedEntries <= 0) return NULL;
2693N/A
2693N/A for (i=0; i < mlu ->UsedEntries; i++) {
2693N/A
2693N/A v = mlu ->Entries + i;
2693N/A
2693N/A if (v -> Language == LanguageCode) {
2693N/A
2693N/A if (Best == -1) Best = i;
2693N/A
2693N/A if (v -> Country == CountryCode) {
2693N/A
2693N/A if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
2693N/A if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
2693N/A
2693N/A if (len != NULL) *len = v ->Len;
2693N/A
2693N/A return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v -> StrW); // Found exact match
2693N/A }
0N/A }
0N/A }
0N/A
2693N/A // No string found. Return First one
2693N/A if (Best == -1)
2693N/A Best = 0;
2693N/A
6271N/A v = mlu ->Entries + Best;
2693N/A
6271N/A if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language;
2693N/A if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country;
2693N/A
2693N/A if (len != NULL) *len = v ->Len;
2693N/A
2693N/A return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
0N/A}
0N/A
0N/A
2693N/A// Obtain an ASCII representation of the wide string. Setting buffer to NULL returns the len
2693N/AcmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
6271N/A const char LanguageCode[3], const char CountryCode[3],
6271N/A char* Buffer, cmsUInt32Number BufferSize)
0N/A{
2693N/A const wchar_t *Wide;
2693N/A cmsUInt32Number StrLen = 0;
2693N/A cmsUInt32Number ASCIIlen, i;
2693N/A
2693N/A cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
2693N/A cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
2693N/A
2693N/A // Sanitize
2693N/A if (mlu == NULL) return 0;
2693N/A
2693N/A // Get WideChar
2693N/A Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
2693N/A if (Wide == NULL) return 0;
2693N/A
2693N/A ASCIIlen = StrLen / sizeof(wchar_t);
2693N/A
2693N/A // Maybe we want only to know the len?
2693N/A if (Buffer == NULL) return ASCIIlen + 1; // Note the zero at the end
2693N/A
2693N/A // No buffer size means no data
2693N/A if (BufferSize <= 0) return 0;
2693N/A
2693N/A // Some clipping may be required
2693N/A if (BufferSize < ASCIIlen + 1)
2693N/A ASCIIlen = BufferSize - 1;
2693N/A
2693N/A // Precess each character
2693N/A for (i=0; i < ASCIIlen; i++) {
2693N/A
2693N/A if (Wide[i] == 0)
2693N/A Buffer[i] = 0;
2693N/A else
2693N/A Buffer[i] = (char) Wide[i];
2693N/A }
0N/A
2693N/A // We put a termination "\0"
2693N/A Buffer[ASCIIlen] = 0;
2693N/A return ASCIIlen + 1;
2693N/A}
2693N/A
2693N/A// Obtain a wide representation of the MLU, on depending on current locale settings
2693N/AcmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
6271N/A const char LanguageCode[3], const char CountryCode[3],
6271N/A wchar_t* Buffer, cmsUInt32Number BufferSize)
2693N/A{
2693N/A const wchar_t *Wide;
2693N/A cmsUInt32Number StrLen = 0;
2693N/A
2693N/A cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
2693N/A cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
2693N/A
2693N/A // Sanitize
2693N/A if (mlu == NULL) return 0;
2693N/A
2693N/A Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
2693N/A if (Wide == NULL) return 0;
2693N/A
2693N/A // Maybe we want only to know the len?
2693N/A if (Buffer == NULL) return StrLen + sizeof(wchar_t);
2693N/A
2693N/A // No buffer size means no data
2693N/A if (BufferSize <= 0) return 0;
2693N/A
2693N/A // Some clipping may be required
2693N/A if (BufferSize < StrLen + sizeof(wchar_t))
2693N/A StrLen = BufferSize - + sizeof(wchar_t);
2693N/A
2693N/A memmove(Buffer, Wide, StrLen);
2693N/A Buffer[StrLen / sizeof(wchar_t)] = 0;
2693N/A
2693N/A return StrLen + sizeof(wchar_t);
2693N/A}
0N/A
0N/A
2693N/A// Get also the language and country
2693N/ACMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
2693N/A const char LanguageCode[3], const char CountryCode[3],
2693N/A char ObtainedLanguage[3], char ObtainedCountry[3])
2693N/A{
2693N/A const wchar_t *Wide;
2693N/A
2693N/A cmsUInt16Number Lang = _cmsAdjustEndianess16(*(cmsUInt16Number*) LanguageCode);
2693N/A cmsUInt16Number Cntry = _cmsAdjustEndianess16(*(cmsUInt16Number*) CountryCode);
2693N/A cmsUInt16Number ObtLang, ObtCode;
2693N/A
2693N/A // Sanitize
2693N/A if (mlu == NULL) return FALSE;
2693N/A
2693N/A Wide = _cmsMLUgetWide(mlu, NULL, Lang, Cntry, &ObtLang, &ObtCode);
2693N/A if (Wide == NULL) return FALSE;
2693N/A
2693N/A // Get used language and code
2693N/A *(cmsUInt16Number *)ObtainedLanguage = _cmsAdjustEndianess16(ObtLang);
2693N/A *(cmsUInt16Number *)ObtainedCountry = _cmsAdjustEndianess16(ObtCode);
2693N/A
2693N/A ObtainedLanguage[2] = ObtainedCountry[2] = 0;
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A
2693N/A// Named color lists --------------------------------------------------------------------------------------------
0N/A
2693N/A// Grow the list to keep at least NumElements
2693N/Astatic
2693N/AcmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v)
2693N/A{
2693N/A cmsUInt32Number size;
2693N/A _cmsNAMEDCOLOR * NewPtr;
2693N/A
2693N/A if (v == NULL) return FALSE;
2693N/A
2693N/A if (v ->Allocated == 0)
2693N/A size = 64; // Initial guess
2693N/A else
2693N/A size = v ->Allocated * 2;
2693N/A
6271N/A // Keep a maximum color lists can grow, 100K entries seems reasonable
6271N/A if (size > 1024*100) return FALSE;
6271N/A
2693N/A NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR));
2693N/A if (NewPtr == NULL)
2693N/A return FALSE;
0N/A
2693N/A v ->List = NewPtr;
2693N/A v ->Allocated = size;
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A// Allocate a list for n elements
2693N/AcmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix)
2693N/A{
2693N/A cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));
2693N/A
2693N/A if (v == NULL) return NULL;
2693N/A
2693N/A v ->List = NULL;
2693N/A v ->nColors = 0;
2693N/A v ->ContextID = ContextID;
2693N/A
2693N/A while (v -> Allocated < n)
2693N/A GrowNamedColorList(v);
2693N/A
6320N/A strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix) - 1);
6320N/A strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix) - 1);
6320N/A v->Prefix[sizeof(v ->Prefix) - 1] = v->Suffix[sizeof(v ->Suffix) - 1] = 0;
6271N/A
2693N/A v -> ColorantCount = ColorantCount;
0N/A
0N/A return v;
0N/A}
0N/A
2693N/A// Free a list
2693N/Avoid CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v)
0N/A{
2693N/A if (v ->List) _cmsFree(v ->ContextID, v ->List);
2693N/A if (v) _cmsFree(v ->ContextID, v);
0N/A}
0N/A
2693N/AcmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v)
0N/A{
2693N/A cmsNAMEDCOLORLIST* NewNC;
0N/A
2693N/A if (v == NULL) return NULL;
0N/A
2693N/A NewNC= cmsAllocNamedColorList(v ->ContextID, v -> nColors, v ->ColorantCount, v ->Prefix, v ->Suffix);
2693N/A if (NewNC == NULL) return NULL;
0N/A
2693N/A // For really large tables we need this
2693N/A while (NewNC ->Allocated < v ->Allocated)
2693N/A GrowNamedColorList(NewNC);
0N/A
2693N/A memmove(NewNC ->Prefix, v ->Prefix, sizeof(v ->Prefix));
2693N/A memmove(NewNC ->Suffix, v ->Suffix, sizeof(v ->Suffix));
2693N/A NewNC ->ColorantCount = v ->ColorantCount;
2693N/A memmove(NewNC->List, v ->List, v->nColors * sizeof(_cmsNAMEDCOLOR));
2693N/A NewNC ->nColors = v ->nColors;
2693N/A return NewNC;
0N/A}
0N/A
0N/A
2693N/A// Append a color to a list. List pointer may change if reallocated
2693N/AcmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,
2693N/A const char* Name,
2693N/A cmsUInt16Number PCS[3], cmsUInt16Number Colorant[cmsMAXCHANNELS])
2693N/A{
2693N/A cmsUInt32Number i;
0N/A
2693N/A if (NamedColorList == NULL) return FALSE;
2693N/A
2693N/A if (NamedColorList ->nColors + 1 > NamedColorList ->Allocated) {
2693N/A if (!GrowNamedColorList(NamedColorList)) return FALSE;
2693N/A }
2693N/A
2693N/A for (i=0; i < NamedColorList ->ColorantCount; i++)
2693N/A NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i];
2693N/A
2693N/A for (i=0; i < 3; i++)
2693N/A NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i];
2693N/A
6271N/A if (Name != NULL) {
6271N/A
2693N/A strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name,
6320N/A sizeof(NamedColorList ->List[NamedColorList ->nColors].Name) - 1);
6271N/A
6320N/A NamedColorList ->List[NamedColorList ->nColors].
6320N/A Name[sizeof(NamedColorList ->List[NamedColorList ->nColors].Name) - 1] = 0;
6271N/A
6271N/A }
2693N/A else
2693N/A NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0;
2693N/A
0N/A
2693N/A NamedColorList ->nColors++;
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A// Returns number of elements
2693N/AcmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColorList)
2693N/A{
2693N/A if (NamedColorList == NULL) return 0;
2693N/A return NamedColorList ->nColors;
2693N/A}
2693N/A
2693N/A// Info aboout a given color
2693N/AcmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor,
2693N/A char* Name,
2693N/A char* Prefix,
2693N/A char* Suffix,
2693N/A cmsUInt16Number* PCS,
2693N/A cmsUInt16Number* Colorant)
0N/A{
2693N/A if (NamedColorList == NULL) return FALSE;
2693N/A
2693N/A if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE;
2693N/A
2693N/A if (Name) strcpy(Name, NamedColorList->List[nColor].Name);
2693N/A if (Prefix) strcpy(Prefix, NamedColorList->Prefix);
2693N/A if (Suffix) strcpy(Suffix, NamedColorList->Suffix);
2693N/A if (PCS)
2693N/A memmove(PCS, NamedColorList ->List[nColor].PCS, 3*sizeof(cmsUInt16Number));
2693N/A
2693N/A if (Colorant)
2693N/A memmove(Colorant, NamedColorList ->List[nColor].DeviceColorant,
2693N/A sizeof(cmsUInt16Number) * NamedColorList ->ColorantCount);
2693N/A
2693N/A
2693N/A return TRUE;
2693N/A}
2693N/A
2693N/A// Search for a given color name (no prefix or suffix)
2693N/AcmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name)
2693N/A{
2693N/A int i, n;
2693N/A
2693N/A if (NamedColorList == NULL) return -1;
2693N/A n = cmsNamedColorCount(NamedColorList);
2693N/A for (i=0; i < n; i++) {
2693N/A if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0)
2693N/A return i;
2693N/A }
0N/A
2693N/A return -1;
2693N/A}
2693N/A
2693N/A// MPE support -----------------------------------------------------------------------------------------------------------------
2693N/A
2693N/Astatic
2693N/Avoid FreeNamedColorList(cmsStage* mpe)
2693N/A{
2693N/A cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
2693N/A cmsFreeNamedColorList(List);
2693N/A}
2693N/A
2693N/Astatic
2693N/Avoid* DupNamedColorList(cmsStage* mpe)
2693N/A{
2693N/A cmsNAMEDCOLORLIST* List = (cmsNAMEDCOLORLIST*) mpe ->Data;
2693N/A return cmsDupNamedColorList(List);
2693N/A}
2693N/A
2693N/Astatic
6271N/Avoid EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
6271N/A{
6271N/A cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
6271N/A cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
6271N/A
6271N/A if (index >= NamedColorList-> nColors) {
6271N/A cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
6271N/A }
6271N/A else {
6271N/A
6271N/A // Named color always uses Lab
6271N/A Out[0] = (cmsFloat32Number) (NamedColorList->List[index].PCS[0] / 65535.0);
6271N/A Out[1] = (cmsFloat32Number) (NamedColorList->List[index].PCS[1] / 65535.0);
6271N/A Out[2] = (cmsFloat32Number) (NamedColorList->List[index].PCS[2] / 65535.0);
6271N/A }
6271N/A}
6271N/A
6271N/Astatic
2693N/Avoid EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
2693N/A{
2693N/A cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) mpe ->Data;
2693N/A cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
2693N/A cmsUInt32Number j;
2693N/A
2693N/A if (index >= NamedColorList-> nColors) {
2693N/A cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
2693N/A }
2693N/A else {
2693N/A for (j=0; j < NamedColorList ->ColorantCount; j++)
2693N/A Out[j] = (cmsFloat32Number) (NamedColorList->List[index].DeviceColorant[j] / 65535.0);
2693N/A }
0N/A}
0N/A
0N/A
2693N/A// Named color lookup element
6271N/AcmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS)
0N/A{
2693N/A return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,
6271N/A cmsSigNamedColorElemType,
6271N/A 1, UsePCS ? 3 : NamedColorList ->ColorantCount,
6271N/A UsePCS ? EvalNamedColorPCS : EvalNamedColor,
6271N/A DupNamedColorList,
6271N/A FreeNamedColorList,
6271N/A cmsDupNamedColorList(NamedColorList));
0N/A
2693N/A}
2693N/A
0N/A
2693N/A// Retrieve the named color list from a transform. Should be first element in the LUT
2693N/AcmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform)
2693N/A{
2693N/A _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
2693N/A cmsStage* mpe = v ->Lut->Elements;
0N/A
2693N/A if (mpe ->Type != cmsSigNamedColorElemType) return NULL;
2693N/A return (cmsNAMEDCOLORLIST*) mpe ->Data;
0N/A}
0N/A
0N/A
2693N/A// Profile sequence description routines -------------------------------------------------------------------------------------
2693N/A
2693N/AcmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext ContextID, cmsUInt32Number n)
0N/A{
2693N/A cmsSEQ* Seq;
2693N/A cmsUInt32Number i;
0N/A
2693N/A if (n == 0) return NULL;
2693N/A
2693N/A // In a absolutely arbitrary way, I hereby decide to allow a maxim of 255 profiles linked
2693N/A // in a devicelink. It makes not sense anyway and may be used for exploits, so let's close the door!
2693N/A if (n > 255) return NULL;
0N/A
2693N/A Seq = (cmsSEQ*) _cmsMallocZero(ContextID, sizeof(cmsSEQ));
2693N/A if (Seq == NULL) return NULL;
2693N/A
2693N/A Seq -> ContextID = ContextID;
2693N/A Seq -> seq = (cmsPSEQDESC*) _cmsCalloc(ContextID, n, sizeof(cmsPSEQDESC));
2693N/A Seq -> n = n;
2693N/A
6291N/A if (Seq -> seq == NULL) {
6291N/A _cmsFree(ContextID, Seq);
6291N/A return NULL;
6291N/A }
0N/A
2693N/A for (i=0; i < n; i++) {
2693N/A Seq -> seq[i].Manufacturer = NULL;
2693N/A Seq -> seq[i].Model = NULL;
2693N/A Seq -> seq[i].Description = NULL;
2693N/A }
2693N/A
2693N/A return Seq;
0N/A}
1002N/A
2693N/Avoid CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
2693N/A{
2693N/A cmsUInt32Number i;
1002N/A
2693N/A for (i=0; i < pseq ->n; i++) {
2693N/A if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
2693N/A if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
2693N/A if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
2693N/A }
2693N/A
2693N/A if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);
2693N/A _cmsFree(pseq -> ContextID, pseq);
2693N/A}
2693N/A
2693N/AcmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq)
2693N/A{
2693N/A cmsSEQ *NewSeq;
2693N/A cmsUInt32Number i;
2693N/A
2693N/A if (pseq == NULL)
2693N/A return NULL;
2693N/A
2693N/A NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ));
2693N/A if (NewSeq == NULL) return NULL;
2693N/A
2693N/A
2693N/A NewSeq -> seq = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC));
2693N/A if (NewSeq ->seq == NULL) goto Error;
2693N/A
2693N/A NewSeq -> ContextID = pseq ->ContextID;
2693N/A NewSeq -> n = pseq ->n;
2693N/A
2693N/A for (i=0; i < pseq->n; i++) {
2693N/A
2693N/A memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number));
2693N/A
2693N/A NewSeq ->seq[i].deviceMfg = pseq ->seq[i].deviceMfg;
2693N/A NewSeq ->seq[i].deviceModel = pseq ->seq[i].deviceModel;
2693N/A memmove(&NewSeq ->seq[i].ProfileID, &pseq ->seq[i].ProfileID, sizeof(cmsProfileID));
2693N/A NewSeq ->seq[i].technology = pseq ->seq[i].technology;
2693N/A
2693N/A NewSeq ->seq[i].Manufacturer = cmsMLUdup(pseq ->seq[i].Manufacturer);
2693N/A NewSeq ->seq[i].Model = cmsMLUdup(pseq ->seq[i].Model);
2693N/A NewSeq ->seq[i].Description = cmsMLUdup(pseq ->seq[i].Description);
2693N/A
2693N/A }
2693N/A
2693N/A return NewSeq;
2693N/A
2693N/AError:
2693N/A
2693N/A cmsFreeProfileSequenceDescription(NewSeq);
2693N/A return NULL;
2693N/A}
2693N/A
6271N/A// Dictionaries --------------------------------------------------------------------------------------------------------
6271N/A
6271N/A// Dictionaries are just very simple linked lists
6271N/A
6271N/A
6271N/Atypedef struct _cmsDICT_struct {
6271N/A cmsDICTentry* head;
6271N/A cmsContext ContextID;
6271N/A} _cmsDICT;
6271N/A
6271N/A
6271N/A// Allocate an empty dictionary
6271N/AcmsHANDLE CMSEXPORT cmsDictAlloc(cmsContext ContextID)
6271N/A{
6271N/A _cmsDICT* dict = (_cmsDICT*) _cmsMallocZero(ContextID, sizeof(_cmsDICT));
6271N/A if (dict == NULL) return NULL;
6271N/A
6271N/A dict ->ContextID = ContextID;
6271N/A return (cmsHANDLE) dict;
6271N/A
6271N/A}
6271N/A
6271N/A// Dispose resources
6271N/Avoid CMSEXPORT cmsDictFree(cmsHANDLE hDict)
6271N/A{
6271N/A _cmsDICT* dict = (_cmsDICT*) hDict;
6271N/A cmsDICTentry *entry, *next;
6271N/A
6271N/A _cmsAssert(dict != NULL);
6271N/A
6271N/A // Walk the list freeing all nodes
6271N/A entry = dict ->head;
6271N/A while (entry != NULL) {
6271N/A
6271N/A if (entry ->DisplayName != NULL) cmsMLUfree(entry ->DisplayName);
6271N/A if (entry ->DisplayValue != NULL) cmsMLUfree(entry ->DisplayValue);
6271N/A if (entry ->Name != NULL) _cmsFree(dict ->ContextID, entry -> Name);
6271N/A if (entry ->Value != NULL) _cmsFree(dict ->ContextID, entry -> Value);
6271N/A
6271N/A // Don't fall in the habitual trap...
6271N/A next = entry ->Next;
6271N/A _cmsFree(dict ->ContextID, entry);
6271N/A
6271N/A entry = next;
6271N/A }
6271N/A
6271N/A _cmsFree(dict ->ContextID, dict);
6271N/A}
6271N/A
6271N/A
6271N/A// Duplicate a wide char string
6271N/Astatic
6271N/Awchar_t* DupWcs(cmsContext ContextID, const wchar_t* ptr)
6271N/A{
6271N/A if (ptr == NULL) return NULL;
6271N/A return (wchar_t*) _cmsDupMem(ContextID, ptr, (mywcslen(ptr) + 1) * sizeof(wchar_t));
6271N/A}
6271N/A
6271N/A// Add a new entry to the linked list
6271N/AcmsBool CMSEXPORT cmsDictAddEntry(cmsHANDLE hDict, const wchar_t* Name, const wchar_t* Value, const cmsMLU *DisplayName, const cmsMLU *DisplayValue)
6271N/A{
6271N/A _cmsDICT* dict = (_cmsDICT*) hDict;
6271N/A cmsDICTentry *entry;
6271N/A
6271N/A _cmsAssert(dict != NULL);
6271N/A _cmsAssert(Name != NULL);
6271N/A
6271N/A entry = (cmsDICTentry*) _cmsMallocZero(dict ->ContextID, sizeof(cmsDICTentry));
6271N/A if (entry == NULL) return FALSE;
6271N/A
6271N/A entry ->DisplayName = cmsMLUdup(DisplayName);
6271N/A entry ->DisplayValue = cmsMLUdup(DisplayValue);
6271N/A entry ->Name = DupWcs(dict ->ContextID, Name);
6271N/A entry ->Value = DupWcs(dict ->ContextID, Value);
6271N/A
6271N/A entry ->Next = dict ->head;
6271N/A dict ->head = entry;
6271N/A
6271N/A return TRUE;
6271N/A}
6271N/A
6271N/A
6271N/A// Duplicates an existing dictionary
6271N/AcmsHANDLE CMSEXPORT cmsDictDup(cmsHANDLE hDict)
6271N/A{
6271N/A _cmsDICT* old_dict = (_cmsDICT*) hDict;
6271N/A cmsHANDLE hNew;
6271N/A _cmsDICT* new_dict;
6271N/A cmsDICTentry *entry;
6271N/A
6271N/A _cmsAssert(old_dict != NULL);
6271N/A
6271N/A hNew = cmsDictAlloc(old_dict ->ContextID);
6271N/A if (hNew == NULL) return NULL;
6271N/A
6271N/A new_dict = (_cmsDICT*) hNew;
6271N/A
6271N/A // Walk the list freeing all nodes
6271N/A entry = old_dict ->head;
6271N/A while (entry != NULL) {
6271N/A
6271N/A if (!cmsDictAddEntry(hNew, entry ->Name, entry ->Value, entry ->DisplayName, entry ->DisplayValue)) {
6271N/A
6271N/A cmsDictFree(hNew);
6271N/A return NULL;
6271N/A }
6271N/A
6271N/A entry = entry -> Next;
6271N/A }
6271N/A
6271N/A return hNew;
6271N/A}
6271N/A
6271N/A// Get a pointer to the linked list
6271N/Aconst cmsDICTentry* CMSEXPORT cmsDictGetEntryList(cmsHANDLE hDict)
6271N/A{
6271N/A _cmsDICT* dict = (_cmsDICT*) hDict;
6271N/A
6271N/A if (dict == NULL) return NULL;
6271N/A return dict ->head;
6271N/A}
6271N/A
6271N/A// Helper For external languages
6271N/Aconst cmsDICTentry* CMSEXPORT cmsDictNextEntry(const cmsDICTentry* e)
6271N/A{
6271N/A if (e == NULL) return NULL;
6271N/A return e ->Next;
6271N/A}