Path: blob/master/src/java.desktop/share/native/liblcms/cmsplugin.c
41149 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"565758// ----------------------------------------------------------------------------------59// Encoding & Decoding support functions60// ----------------------------------------------------------------------------------6162// Little-Endian to Big-Endian6364// Adjust a word value after being read/ before being written from/to an ICC profile65cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word)66{67#ifndef CMS_USE_BIG_ENDIAN6869cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;70cmsUInt8Number tmp;7172tmp = pByte[0];73pByte[0] = pByte[1];74pByte[1] = tmp;75#endif7677return Word;78}798081// Transports to properly encoded values - note that icc profiles does use big endian notation.8283// 1 2 3 484// 4 3 2 18586cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord)87{88#ifndef CMS_USE_BIG_ENDIAN8990cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;91cmsUInt8Number temp1;92cmsUInt8Number temp2;9394temp1 = *pByte++;95temp2 = *pByte++;96*(pByte-1) = *pByte;97*pByte++ = temp2;98*(pByte-3) = *pByte;99*pByte = temp1;100#endif101return DWord;102}103104// 1 2 3 4 5 6 7 8105// 8 7 6 5 4 3 2 1106107void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord)108{109110#ifndef CMS_USE_BIG_ENDIAN111112cmsUInt8Number* pIn = (cmsUInt8Number*) QWord;113cmsUInt8Number* pOut = (cmsUInt8Number*) Result;114115_cmsAssert(Result != NULL);116117pOut[7] = pIn[0];118pOut[6] = pIn[1];119pOut[5] = pIn[2];120pOut[4] = pIn[3];121pOut[3] = pIn[4];122pOut[2] = pIn[5];123pOut[1] = pIn[6];124pOut[0] = pIn[7];125126#else127_cmsAssert(Result != NULL);128129# ifdef CMS_DONT_USE_INT64130(*Result)[0] = (*QWord)[0];131(*Result)[1] = (*QWord)[1];132# else133*Result = *QWord;134# endif135#endif136}137138// Auxiliary -- read 8, 16 and 32-bit numbers139cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)140{141cmsUInt8Number tmp;142143_cmsAssert(io != NULL);144145if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)146return FALSE;147148if (n != NULL) *n = tmp;149return TRUE;150}151152cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)153{154cmsUInt16Number tmp;155156_cmsAssert(io != NULL);157158if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)159return FALSE;160161if (n != NULL) *n = _cmsAdjustEndianess16(tmp);162return TRUE;163}164165cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)166{167cmsUInt32Number i;168169_cmsAssert(io != NULL);170171for (i=0; i < n; i++) {172173if (Array != NULL) {174if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;175}176else {177if (!_cmsReadUInt16Number(io, NULL)) return FALSE;178}179180}181return TRUE;182}183184cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)185{186cmsUInt32Number tmp;187188_cmsAssert(io != NULL);189190if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)191return FALSE;192193if (n != NULL) *n = _cmsAdjustEndianess32(tmp);194return TRUE;195}196197cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)198{199cmsUInt32Number tmp;200201_cmsAssert(io != NULL);202203if (io->Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)204return FALSE;205206if (n != NULL) {207208tmp = _cmsAdjustEndianess32(tmp);209*n = *(cmsFloat32Number*)(void*)&tmp;210211// Safeguard which covers against absurd values212if (*n > 1E+20 || *n < -1E+20) return FALSE;213214#if defined(_MSC_VER) && _MSC_VER < 1800215return TRUE;216#elif defined (__BORLANDC__)217return TRUE;218#elif !defined(_MSC_VER) && (defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L)219return TRUE;220#else221222// fpclassify() required by C99 (only provided by MSVC >= 1800, VS2013 onwards)223return ((fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL));224#endif225}226227return TRUE;228}229230231cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)232{233cmsUInt64Number tmp;234235_cmsAssert(io != NULL);236237if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)238return FALSE;239240if (n != NULL) {241242_cmsAdjustEndianess64(n, &tmp);243}244245return TRUE;246}247248249cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)250{251cmsUInt32Number tmp;252253_cmsAssert(io != NULL);254255if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)256return FALSE;257258if (n != NULL) {259*n = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32(tmp));260}261262return TRUE;263}264265266cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)267{268cmsEncodedXYZNumber xyz;269270_cmsAssert(io != NULL);271272if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;273274if (XYZ != NULL) {275276XYZ->X = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.X));277XYZ->Y = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Y));278XYZ->Z = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Z));279}280return TRUE;281}282283cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)284{285_cmsAssert(io != NULL);286287if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)288return FALSE;289290return TRUE;291}292293cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)294{295cmsUInt16Number tmp;296297_cmsAssert(io != NULL);298299tmp = _cmsAdjustEndianess16(n);300if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)301return FALSE;302303return TRUE;304}305306cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)307{308cmsUInt32Number i;309310_cmsAssert(io != NULL);311_cmsAssert(Array != NULL);312313for (i=0; i < n; i++) {314if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;315}316317return TRUE;318}319320cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)321{322cmsUInt32Number tmp;323324_cmsAssert(io != NULL);325326tmp = _cmsAdjustEndianess32(n);327if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)328return FALSE;329330return TRUE;331}332333334cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)335{336cmsUInt32Number tmp;337338_cmsAssert(io != NULL);339340tmp = *(cmsUInt32Number*) (void*) &n;341tmp = _cmsAdjustEndianess32(tmp);342if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)343return FALSE;344345return TRUE;346}347348cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)349{350cmsUInt64Number tmp;351352_cmsAssert(io != NULL);353354_cmsAdjustEndianess64(&tmp, n);355if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)356return FALSE;357358return TRUE;359}360361cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)362{363cmsUInt32Number tmp;364365_cmsAssert(io != NULL);366367tmp = _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(n));368if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)369return FALSE;370371return TRUE;372}373374cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)375{376cmsEncodedXYZNumber xyz;377378_cmsAssert(io != NULL);379_cmsAssert(XYZ != NULL);380381xyz.X = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->X));382xyz.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Y));383xyz.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Z));384385return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);386}387388// from Fixed point 8.8 to double389cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)390{391cmsUInt8Number msb, lsb;392393lsb = (cmsUInt8Number) (fixed8 & 0xff);394msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);395396return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));397}398399cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)400{401cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);402return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);403}404405// from Fixed point 15.16 to double406cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)407{408cmsFloat64Number floater, sign, mid;409int Whole, FracPart;410411sign = (fix32 < 0 ? -1 : 1);412fix32 = abs(fix32);413414Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;415FracPart = (cmsUInt16Number)(fix32 & 0xffff);416417mid = (cmsFloat64Number) FracPart / 65536.0;418floater = (cmsFloat64Number) Whole + mid;419420return sign * floater;421}422423// from double to Fixed point 15.16424cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)425{426return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));427}428429// Date/Time functions430431void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)432{433434_cmsAssert(Dest != NULL);435_cmsAssert(Source != NULL);436437Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds);438Dest->tm_min = _cmsAdjustEndianess16(Source->minutes);439Dest->tm_hour = _cmsAdjustEndianess16(Source->hours);440Dest->tm_mday = _cmsAdjustEndianess16(Source->day);441Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1;442Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900;443Dest->tm_wday = -1;444Dest->tm_yday = -1;445Dest->tm_isdst = 0;446}447448void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)449{450_cmsAssert(Dest != NULL);451_cmsAssert(Source != NULL);452453Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);454Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);455Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);456Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);457Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));458Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));459}460461// Read base and return type base462cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)463{464_cmsTagBase Base;465466_cmsAssert(io != NULL);467468if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)469return (cmsTagTypeSignature) 0;470471return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);472}473474// Setup base marker475cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)476{477_cmsTagBase Base;478479_cmsAssert(io != NULL);480481Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);482memset(&Base.reserved, 0, sizeof(Base.reserved));483return io -> Write(io, sizeof(_cmsTagBase), &Base);484}485486cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)487{488cmsUInt8Number Buffer[4];489cmsUInt32Number NextAligned, At;490cmsUInt32Number BytesToNextAlignedPos;491492_cmsAssert(io != NULL);493494At = io -> Tell(io);495NextAligned = _cmsALIGNLONG(At);496BytesToNextAlignedPos = NextAligned - At;497if (BytesToNextAlignedPos == 0) return TRUE;498if (BytesToNextAlignedPos > 4) return FALSE;499500return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);501}502503cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)504{505cmsUInt8Number Buffer[4];506cmsUInt32Number NextAligned, At;507cmsUInt32Number BytesToNextAlignedPos;508509_cmsAssert(io != NULL);510511At = io -> Tell(io);512NextAligned = _cmsALIGNLONG(At);513BytesToNextAlignedPos = NextAligned - At;514if (BytesToNextAlignedPos == 0) return TRUE;515if (BytesToNextAlignedPos > 4) return FALSE;516517memset(Buffer, 0, BytesToNextAlignedPos);518return io -> Write(io, BytesToNextAlignedPos, Buffer);519}520521522// To deal with text streams. 2K at most523cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)524{525va_list args;526int len;527cmsUInt8Number Buffer[2048];528cmsBool rc;529cmsUInt8Number* ptr;530531_cmsAssert(io != NULL);532_cmsAssert(frm != NULL);533534va_start(args, frm);535536len = vsnprintf((char*) Buffer, 2047, frm, args);537if (len < 0) {538va_end(args);539return FALSE; // Truncated, which is a fatal error for us540}541542// setlocale may be active, no commas are needed in PS generator543// and PS generator is our only client544for (ptr = Buffer; *ptr; ptr++)545{546if (*ptr == ',') *ptr = '.';547}548549rc = io ->Write(io, (cmsUInt32Number) len, Buffer);550551va_end(args);552553return rc;554}555556557// Plugin memory management -------------------------------------------------------------------------------------------------558559// Specialized malloc for plug-ins, that is freed upon exit.560void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)561{562struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);563564if (ctx ->MemPool == NULL) {565566if (ContextID == NULL) {567568ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);569if (ctx->MemPool == NULL) return NULL;570}571else {572cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");573return NULL;574}575}576577return _cmsSubAlloc(ctx->MemPool, size);578}579580581// Main plug-in dispatcher582cmsBool CMSEXPORT cmsPlugin(void* Plug_in)583{584return cmsPluginTHR(NULL, Plug_in);585}586587cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)588{589cmsPluginBase* Plugin;590591for (Plugin = (cmsPluginBase*) Plug_in;592Plugin != NULL;593Plugin = Plugin -> Next) {594595if (Plugin -> Magic != cmsPluginMagicNumber) {596cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");597return FALSE;598}599600if (Plugin ->ExpectedVersion > LCMS_VERSION) {601cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",602Plugin ->ExpectedVersion, LCMS_VERSION);603return FALSE;604}605606switch (Plugin -> Type) {607608case cmsPluginMemHandlerSig:609if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;610break;611612case cmsPluginInterpolationSig:613if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;614break;615616case cmsPluginTagTypeSig:617if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;618break;619620case cmsPluginTagSig:621if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;622break;623624case cmsPluginFormattersSig:625if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;626break;627628case cmsPluginRenderingIntentSig:629if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;630break;631632case cmsPluginParametricCurveSig:633if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;634break;635636case cmsPluginMultiProcessElementSig:637if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;638break;639640case cmsPluginOptimizationSig:641if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;642break;643644case cmsPluginTransformSig:645if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;646break;647648case cmsPluginMutexSig:649if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;650break;651652default:653cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);654return FALSE;655}656}657658// Keep a reference to the plug-in659return TRUE;660}661662663// Revert all plug-ins to default664void CMSEXPORT cmsUnregisterPlugins(void)665{666cmsUnregisterPluginsTHR(NULL);667}668669670// The Global storage for system context. This is the one and only global variable671// pointers structure. All global vars are referenced here.672static struct _cmsContext_struct globalContext = {673674NULL, // Not in the linked list675NULL, // No suballocator676{677NULL, // UserPtr,678&_cmsLogErrorChunk, // Logger,679&_cmsAlarmCodesChunk, // AlarmCodes,680&_cmsAdaptationStateChunk, // AdaptationState,681&_cmsMemPluginChunk, // MemPlugin,682&_cmsInterpPluginChunk, // InterpPlugin,683&_cmsCurvesPluginChunk, // CurvesPlugin,684&_cmsFormattersPluginChunk, // FormattersPlugin,685&_cmsTagTypePluginChunk, // TagTypePlugin,686&_cmsTagPluginChunk, // TagPlugin,687&_cmsIntentsPluginChunk, // IntentPlugin,688&_cmsMPETypePluginChunk, // MPEPlugin,689&_cmsOptimizationPluginChunk, // OptimizationPlugin,690&_cmsTransformPluginChunk, // TransformPlugin,691&_cmsMutexPluginChunk // MutexPlugin692},693694{ NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0695};696697698// The context pool (linked list head)699static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;700static struct _cmsContext_struct* _cmsContextPoolHead = NULL;701702// Internal, get associated pointer, with guessing. Never returns NULL.703struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)704{705struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;706struct _cmsContext_struct* ctx;707708709// On 0, use global settings710if (id == NULL)711return &globalContext;712713// Search714_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);715716for (ctx = _cmsContextPoolHead;717ctx != NULL;718ctx = ctx ->Next) {719720// Found it?721if (id == ctx)722{723_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);724return ctx; // New-style context725}726}727728_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);729return &globalContext;730}731732733// Internal: get the memory area associanted with each context client734// Returns the block assigned to the specific zone. Never return NULL.735void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)736{737struct _cmsContext_struct* ctx;738void *ptr;739740if ((int) mc < 0 || mc >= MemoryClientMax) {741742cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption");743744// This is catastrophic. Should never reach here745_cmsAssert(0);746747// Reverts to global context748return globalContext.chunks[UserPtr];749}750751ctx = _cmsGetContext(ContextID);752ptr = ctx ->chunks[mc];753754if (ptr != NULL)755return ptr;756757// A null ptr means no special settings for that context, and this758// reverts to Context0 globals759return globalContext.chunks[mc];760}761762763// This function returns the given context its default pristine state,764// as no plug-ins were declared. There is no way to unregister a single765// plug-in, as a single call to cmsPluginTHR() function may register766// many different plug-ins simultaneously, then there is no way to767// identify which plug-in to unregister.768void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)769{770_cmsRegisterMemHandlerPlugin(ContextID, NULL);771_cmsRegisterInterpPlugin(ContextID, NULL);772_cmsRegisterTagTypePlugin(ContextID, NULL);773_cmsRegisterTagPlugin(ContextID, NULL);774_cmsRegisterFormattersPlugin(ContextID, NULL);775_cmsRegisterRenderingIntentPlugin(ContextID, NULL);776_cmsRegisterParametricCurvesPlugin(ContextID, NULL);777_cmsRegisterMultiProcessElementPlugin(ContextID, NULL);778_cmsRegisterOptimizationPlugin(ContextID, NULL);779_cmsRegisterTransformPlugin(ContextID, NULL);780_cmsRegisterMutexPlugin(ContextID, NULL);781}782783784// Returns the memory manager plug-in, if any, from the Plug-in bundle785static786cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)787{788cmsPluginBase* Plugin;789790for (Plugin = (cmsPluginBase*) PluginBundle;791Plugin != NULL;792Plugin = Plugin -> Next) {793794if (Plugin -> Magic == cmsPluginMagicNumber &&795Plugin -> ExpectedVersion <= LCMS_VERSION &&796Plugin -> Type == cmsPluginMemHandlerSig) {797798// Found!799return (cmsPluginMemHandler*) Plugin;800}801}802803// Nope, revert to defaults804return NULL;805}806807808// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined809// data that will be forwarded to plug-ins and logger.810cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)811{812struct _cmsContext_struct* ctx;813struct _cmsContext_struct fakeContext;814815// See the comments regarding locking in lcms2_internal.h816// for an explanation of why we need the following code.817#ifndef CMS_NO_PTHREADS818#ifdef CMS_IS_WINDOWS_819#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT820{821static HANDLE _cmsWindowsInitMutex = NULL;822static volatile HANDLE* mutex = &_cmsWindowsInitMutex;823824if (*mutex == NULL)825{826HANDLE p = CreateMutex(NULL, FALSE, NULL);827if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL)828CloseHandle(p);829}830if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)831return NULL;832if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL)833InitializeCriticalSection(&_cmsContextPoolHeadMutex);834if (*mutex == NULL || !ReleaseMutex(*mutex))835return NULL;836}837#endif838#endif839#endif840841_cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);842843fakeContext.chunks[UserPtr] = UserData;844fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;845846// Create the context structure.847ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));848if (ctx == NULL)849return NULL; // Something very wrong happened!850851// Init the structure and the memory manager852memset(ctx, 0, sizeof(struct _cmsContext_struct));853854// Keep memory manager855memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));856857// Maintain the linked list (with proper locking)858_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);859ctx ->Next = _cmsContextPoolHead;860_cmsContextPoolHead = ctx;861_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);862863ctx ->chunks[UserPtr] = UserData;864ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;865866// Now we can allocate the pool by using default memory manager867ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 22 pointers868if (ctx ->MemPool == NULL) {869870cmsDeleteContext(ctx);871return NULL;872}873874_cmsAllocLogErrorChunk(ctx, NULL);875_cmsAllocAlarmCodesChunk(ctx, NULL);876_cmsAllocAdaptationStateChunk(ctx, NULL);877_cmsAllocMemPluginChunk(ctx, NULL);878_cmsAllocInterpPluginChunk(ctx, NULL);879_cmsAllocCurvesPluginChunk(ctx, NULL);880_cmsAllocFormattersPluginChunk(ctx, NULL);881_cmsAllocTagTypePluginChunk(ctx, NULL);882_cmsAllocMPETypePluginChunk(ctx, NULL);883_cmsAllocTagPluginChunk(ctx, NULL);884_cmsAllocIntentsPluginChunk(ctx, NULL);885_cmsAllocOptimizationPluginChunk(ctx, NULL);886_cmsAllocTransformPluginChunk(ctx, NULL);887_cmsAllocMutexPluginChunk(ctx, NULL);888889// Setup the plug-ins890if (!cmsPluginTHR(ctx, Plugin)) {891892cmsDeleteContext(ctx);893return NULL;894}895896return (cmsContext) ctx;897}898899// Duplicates a context with all associated plug-ins.900// Caller may specify an optional pointer to user-defined901// data that will be forwarded to plug-ins and logger.902cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)903{904int i;905struct _cmsContext_struct* ctx;906const struct _cmsContext_struct* src = _cmsGetContext(ContextID);907908void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];909910911ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));912if (ctx == NULL)913return NULL; // Something very wrong happened914915// Setup default memory allocators916memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));917918// Maintain the linked list919_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);920ctx ->Next = _cmsContextPoolHead;921_cmsContextPoolHead = ctx;922_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);923924ctx ->chunks[UserPtr] = userData;925ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;926927ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));928if (ctx ->MemPool == NULL) {929930cmsDeleteContext(ctx);931return NULL;932}933934// Allocate all required chunks.935_cmsAllocLogErrorChunk(ctx, src);936_cmsAllocAlarmCodesChunk(ctx, src);937_cmsAllocAdaptationStateChunk(ctx, src);938_cmsAllocMemPluginChunk(ctx, src);939_cmsAllocInterpPluginChunk(ctx, src);940_cmsAllocCurvesPluginChunk(ctx, src);941_cmsAllocFormattersPluginChunk(ctx, src);942_cmsAllocTagTypePluginChunk(ctx, src);943_cmsAllocMPETypePluginChunk(ctx, src);944_cmsAllocTagPluginChunk(ctx, src);945_cmsAllocIntentsPluginChunk(ctx, src);946_cmsAllocOptimizationPluginChunk(ctx, src);947_cmsAllocTransformPluginChunk(ctx, src);948_cmsAllocMutexPluginChunk(ctx, src);949950// Make sure no one failed951for (i=Logger; i < MemoryClientMax; i++) {952953if (src ->chunks[i] == NULL) {954cmsDeleteContext((cmsContext) ctx);955return NULL;956}957}958959return (cmsContext) ctx;960}961962963// Frees any resources associated with the given context,964// and destroys the context placeholder.965// The ContextID can no longer be used in any THR operation.966void CMSEXPORT cmsDeleteContext(cmsContext ContextID)967{968if (ContextID != NULL) {969970struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;971struct _cmsContext_struct fakeContext;972struct _cmsContext_struct* prev;973974memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));975976fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];977fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;978979// Get rid of plugins980cmsUnregisterPluginsTHR(ContextID);981982// Since all memory is allocated in the private pool, all what we need to do is destroy the pool983if (ctx -> MemPool != NULL)984_cmsSubAllocDestroy(ctx ->MemPool);985ctx -> MemPool = NULL;986987// Maintain list988_cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);989if (_cmsContextPoolHead == ctx) {990991_cmsContextPoolHead = ctx->Next;992}993else {994995// Search for previous996for (prev = _cmsContextPoolHead;997prev != NULL;998prev = prev ->Next)999{1000if (prev -> Next == ctx) {1001prev -> Next = ctx ->Next;1002break;1003}1004}1005}1006_cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);10071008// free the memory block itself1009_cmsFree(&fakeContext, ctx);1010}1011}10121013// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation1014void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)1015{1016return _cmsContextGetClientChunk(ContextID, UserPtr);1017}10181019102010211022