// 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
+// 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
+// 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
+// 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.
//
//---------------------------------------------------------------------------------
tmp = pByte[0];
pByte[0] = pByte[1];
pByte[1] = tmp;
-#endif
+#endif
return Word;
}
// 1 2 3 4 5 6 7 8
// 8 7 6 5 4 3 2 1
-void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord)
+void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord)
{
-
+
#ifndef CMS_USE_BIG_ENDIAN
-
- cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord;
+
+ cmsUInt8Number* pIn = (cmsUInt8Number*) QWord;
cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
_cmsAssert(Result != NULL);
pOut[5] = pIn[2];
pOut[4] = pIn[3];
pOut[3] = pIn[4];
- pOut[2] = pIn[5];
+ pOut[2] = pIn[5];
pOut[1] = pIn[6];
pOut[0] = pIn[7];
#else
-
_cmsAssert(Result != NULL);
- *Result = QWord;
+# ifdef CMS_DONT_USE_INT64
+ (*Result)[0] = QWord[0];
+ (*Result)[1] = QWord[1];
+# else
+ *Result = *QWord;
+# endif
#endif
}
_cmsAssert(io != NULL);
- if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
- return FALSE;
+ if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
+ return FALSE;
if (n != NULL) *n = tmp;
return TRUE;
_cmsAssert(io != NULL);
- if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
- return FALSE;
+ if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
+ return FALSE;
if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
return TRUE;
_cmsAssert(io != NULL);
- if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
- return FALSE;
+ if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ return FALSE;
if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
return TRUE;
_cmsAssert(io != NULL);
- if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
- return FALSE;
+ if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
+ return FALSE;
if (n != NULL) {
_cmsAssert(io != NULL);
- if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
- return FALSE;
+ if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
+ return FALSE;
- if (n != NULL) _cmsAdjustEndianess64(n, tmp);
+ if (n != NULL) _cmsAdjustEndianess64(n, &tmp);
return TRUE;
}
_cmsAssert(io != NULL);
- if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
- return FALSE;
+ if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ return FALSE;
if (n != NULL) {
*n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
{
_cmsAssert(io != NULL);
- if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
- return FALSE;
-
+ if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
+ return FALSE;
+
return TRUE;
}
_cmsAssert(io != NULL);
tmp = _cmsAdjustEndianess16(n);
- if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
- return FALSE;
-
+ if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
+ return FALSE;
+
return TRUE;
}
_cmsAssert(io != NULL);
tmp = _cmsAdjustEndianess32(n);
- if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
- return FALSE;
-
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
return TRUE;
}
tmp = *(cmsUInt32Number*) &n;
tmp = _cmsAdjustEndianess32(tmp);
- if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
- return FALSE;
-
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
return TRUE;
}
-cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n)
+cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
{
cmsUInt64Number tmp;
_cmsAssert(io != NULL);
_cmsAdjustEndianess64(&tmp, n);
- if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
- return FALSE;
-
+ if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
+ return FALSE;
+
return TRUE;
}
_cmsAssert(io != NULL);
tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
- if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
- return FALSE;
-
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ return FALSE;
+
return TRUE;
}
cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
{
cmsEncodedXYZNumber xyz;
-
+
_cmsAssert(io != NULL);
_cmsAssert(XYZ != NULL);
cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
{
cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
- return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
+ return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
}
// from Fixed point 15.16 to double
return sign * floater;
}
-// from double to Fixed point 15.16
+// from double to Fixed point 15.16
cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
{
return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
}
-// Date/Time functions
+// Date/Time functions
void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
{
_cmsAssert(io != NULL);
- if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
+ if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
return (cmsTagTypeSignature) 0;
return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
cmsUInt8Number Buffer[4];
cmsUInt32Number NextAligned, At;
cmsUInt32Number BytesToNextAlignedPos;
-
+
_cmsAssert(io != NULL);
At = io -> Tell(io);
if (len < 0) return FALSE; // Truncated, which is a fatal error for us
rc = io ->Write(io, len, Buffer);
-
+
va_end(args);
return rc;
// Plugin memory management -------------------------------------------------------------------------------------------------
-static _cmsSubAllocator* PluginPool = NULL;
-
// Specialized malloc for plug-ins, that is freed upon exit.
-void* _cmsPluginMalloc(cmsUInt32Number size)
+void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
{
- if (PluginPool == NULL)
- PluginPool = _cmsCreateSubAlloc(0, 4*1024);
+ struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
+
+ if (ctx ->MemPool == NULL) {
+
+ if (ContextID == NULL) {
- return _cmsSubAlloc(PluginPool, size);
+ ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
+ }
+ else {
+ cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
+ return NULL;
+ }
+ }
+
+ return _cmsSubAlloc(ctx->MemPool, size);
}
// Main plug-in dispatcher
cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
+{
+ return cmsPluginTHR(NULL, Plug_in);
+}
+
+cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
{
cmsPluginBase* Plugin;
- for (Plugin = (cmsPluginBase*) Plug_in;
- Plugin != NULL;
+ for (Plugin = (cmsPluginBase*) Plug_in;
+ Plugin != NULL;
Plugin = Plugin -> Next) {
if (Plugin -> Magic != cmsPluginMagicNumber) {
- cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
+ cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
return FALSE;
}
- if (Plugin ->ExpectedVersion > LCMS_VERSION) {
- cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
- Plugin ->ExpectedVersion, LCMS_VERSION);
- return FALSE;
- }
+ if (Plugin ->ExpectedVersion > LCMS_VERSION) {
+ cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
+ Plugin ->ExpectedVersion, LCMS_VERSION);
+ return FALSE;
+ }
switch (Plugin -> Type) {
case cmsPluginMemHandlerSig:
- if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginInterpolationSig:
- if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
break;
-
+
case cmsPluginTagTypeSig:
- if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
break;
-
+
case cmsPluginTagSig:
- if (!_cmsRegisterTagPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginFormattersSig:
- if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginRenderingIntentSig:
- if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginParametricCurveSig:
- if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginMultiProcessElementSig:
- if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginOptimizationSig:
- if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;
+ break;
+
+ case cmsPluginTransformSig:
+ if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
+ break;
+
+ case cmsPluginMutexSig:
+ if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
break;
default:
- cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
+ cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
return FALSE;
- }
+ }
}
// Keep a reference to the plug-in
// Revert all plug-ins to default
void CMSEXPORT cmsUnregisterPlugins(void)
{
- _cmsRegisterMemHandlerPlugin(NULL);
- _cmsRegisterInterpPlugin(NULL);
- _cmsRegisterTagTypePlugin(NULL);
- _cmsRegisterTagPlugin(NULL);
- _cmsRegisterFormattersPlugin(NULL);
- _cmsRegisterRenderingIntentPlugin(NULL);
- _cmsRegisterParametricCurvesPlugin(NULL);
- _cmsRegisterMultiProcessElementPlugin(NULL);
- _cmsRegisterOptimizationPlugin(NULL);
+ cmsUnregisterPluginsTHR(NULL);
+}
+
+
+// The Global storage for system context. This is the one and only global variable
+// pointers structure. All global vars are referenced here.
+static struct _cmsContext_struct globalContext = {
+
+ NULL, // Not in the linked list
+ NULL, // No suballocator
+ {
+ NULL, // UserPtr,
+ &_cmsLogErrorChunk, // Logger,
+ &_cmsAlarmCodesChunk, // AlarmCodes,
+ &_cmsAdaptationStateChunk, // AdaptationState,
+ &_cmsMemPluginChunk, // MemPlugin,
+ &_cmsInterpPluginChunk, // InterpPlugin,
+ &_cmsCurvesPluginChunk, // CurvesPlugin,
+ &_cmsFormattersPluginChunk, // FormattersPlugin,
+ &_cmsTagTypePluginChunk, // TagTypePlugin,
+ &_cmsTagPluginChunk, // TagPlugin,
+ &_cmsIntentsPluginChunk, // IntentPlugin,
+ &_cmsMPETypePluginChunk, // MPEPlugin,
+ &_cmsOptimizationPluginChunk, // OptimizationPlugin,
+ &_cmsTransformPluginChunk, // TransformPlugin,
+ &_cmsMutexPluginChunk // MutexPlugin
+ },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
+};
+
+
+// The context pool (linked list head)
+static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
+static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
+
+// Internal, get associated pointer, with guessing. Never returns NULL.
+struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
+{
+ struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
+ struct _cmsContext_struct* ctx;
+
+
+ // On 0, use global settings
+ if (id == NULL)
+ return &globalContext;
+
+ // Search
+ for (ctx = _cmsContextPoolHead;
+ ctx != NULL;
+ ctx = ctx ->Next) {
+
+ // Found it?
+ if (id == ctx)
+ return ctx; // New-style context,
+ }
+
+ return &globalContext;
+}
+
+
+// Internal: get the memory area associanted with each context client
+// Returns the block assigned to the specific zone.
+void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
+{
+ struct _cmsContext_struct* ctx;
+ void *ptr;
- if (PluginPool != NULL)
- _cmsSubAllocDestroy(PluginPool);
+ if (mc < 0 || mc >= MemoryClientMax) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client");
+ return NULL;
+ }
+
+ ctx = _cmsGetContext(ContextID);
+ ptr = ctx ->chunks[mc];
- PluginPool = NULL;
+ if (ptr != NULL)
+ return ptr;
+
+ // A null ptr means no special settings for that context, and this
+ // reverts to Context0 globals
+ return globalContext.chunks[mc];
+}
+
+
+// This function returns the given context its default pristine state,
+// as no plug-ins were declared. There is no way to unregister a single
+// plug-in, as a single call to cmsPluginTHR() function may register
+// many different plug-ins simultaneously, then there is no way to
+// identify which plug-in to unregister.
+void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
+{
+ _cmsRegisterMemHandlerPlugin(ContextID, NULL);
+ _cmsRegisterInterpPlugin(ContextID, NULL);
+ _cmsRegisterTagTypePlugin(ContextID, NULL);
+ _cmsRegisterTagPlugin(ContextID, NULL);
+ _cmsRegisterFormattersPlugin(ContextID, NULL);
+ _cmsRegisterRenderingIntentPlugin(ContextID, NULL);
+ _cmsRegisterParametricCurvesPlugin(ContextID, NULL);
+ _cmsRegisterMultiProcessElementPlugin(ContextID, NULL);
+ _cmsRegisterOptimizationPlugin(ContextID, NULL);
+ _cmsRegisterTransformPlugin(ContextID, NULL);
+ _cmsRegisterMutexPlugin(ContextID, NULL);
}
+
+
+// Returns the memory manager plug-in, if any, from the Plug-in bundle
+static
+cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
+{
+ cmsPluginBase* Plugin;
+
+ for (Plugin = (cmsPluginBase*) PluginBundle;
+ Plugin != NULL;
+ Plugin = Plugin -> Next) {
+
+ if (Plugin -> Magic == cmsPluginMagicNumber &&
+ Plugin -> ExpectedVersion <= LCMS_VERSION &&
+ Plugin -> Type == cmsPluginMemHandlerSig) {
+
+ // Found!
+ return (cmsPluginMemHandler*) Plugin;
+ }
+ }
+
+ // Nope, revert to defaults
+ return NULL;
+}
+
+
+// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined
+// data that will be forwarded to plug-ins and logger.
+cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
+{
+ struct _cmsContext_struct* ctx;
+ struct _cmsContext_struct fakeContext;
+
+ _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
+
+ fakeContext.chunks[UserPtr] = UserData;
+ fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
+
+ // Create the context structure.
+ ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
+ if (ctx == NULL)
+ return NULL; // Something very wrong happened!
+
+ // Init the structure and the memory manager
+ memset(ctx, 0, sizeof(struct _cmsContext_struct));
+
+ // Keep memory manager
+ memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
+
+ // Maintain the linked list (with proper locking)
+ _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+ ctx ->Next = _cmsContextPoolHead;
+ _cmsContextPoolHead = ctx;
+ _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+
+ ctx ->chunks[UserPtr] = UserData;
+ ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
+
+ // Now we can allocate the pool by using default memory manager
+ ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers
+ if (ctx ->MemPool == NULL) {
+
+ cmsDeleteContext(ctx);
+ return NULL;
+ }
+
+ _cmsAllocLogErrorChunk(ctx, NULL);
+ _cmsAllocAlarmCodesChunk(ctx, NULL);
+ _cmsAllocAdaptationStateChunk(ctx, NULL);
+ _cmsAllocMemPluginChunk(ctx, NULL);
+ _cmsAllocInterpPluginChunk(ctx, NULL);
+ _cmsAllocCurvesPluginChunk(ctx, NULL);
+ _cmsAllocFormattersPluginChunk(ctx, NULL);
+ _cmsAllocTagTypePluginChunk(ctx, NULL);
+ _cmsAllocMPETypePluginChunk(ctx, NULL);
+ _cmsAllocTagPluginChunk(ctx, NULL);
+ _cmsAllocIntentsPluginChunk(ctx, NULL);
+ _cmsAllocOptimizationPluginChunk(ctx, NULL);
+ _cmsAllocTransformPluginChunk(ctx, NULL);
+ _cmsAllocMutexPluginChunk(ctx, NULL);
+
+ // Setup the plug-ins
+ if (!cmsPluginTHR(ctx, Plugin)) {
+
+ cmsDeleteContext(ctx);
+ return NULL;
+ }
+
+ return (cmsContext) ctx;
+}
+
+// Duplicates a context with all associated plug-ins.
+// Caller may specify an optional pointer to user-defined
+// data that will be forwarded to plug-ins and logger.
+cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
+{
+ int i;
+ struct _cmsContext_struct* ctx;
+ const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
+
+ void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
+
+
+ ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
+ if (ctx == NULL)
+ return NULL; // Something very wrong happened
+
+ // Setup default memory allocators
+ memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
+
+ // Maintain the linked list
+ _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+ ctx ->Next = _cmsContextPoolHead;
+ _cmsContextPoolHead = ctx;
+ _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+
+ ctx ->chunks[UserPtr] = userData;
+ ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
+
+ ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
+ if (ctx ->MemPool == NULL) {
+
+ cmsDeleteContext(ctx);
+ return NULL;
+ }
+
+ // Allocate all required chunks.
+ _cmsAllocLogErrorChunk(ctx, src);
+ _cmsAllocAlarmCodesChunk(ctx, src);
+ _cmsAllocAdaptationStateChunk(ctx, src);
+ _cmsAllocMemPluginChunk(ctx, src);
+ _cmsAllocInterpPluginChunk(ctx, src);
+ _cmsAllocCurvesPluginChunk(ctx, src);
+ _cmsAllocFormattersPluginChunk(ctx, src);
+ _cmsAllocTagTypePluginChunk(ctx, src);
+ _cmsAllocMPETypePluginChunk(ctx, src);
+ _cmsAllocTagPluginChunk(ctx, src);
+ _cmsAllocIntentsPluginChunk(ctx, src);
+ _cmsAllocOptimizationPluginChunk(ctx, src);
+ _cmsAllocTransformPluginChunk(ctx, src);
+ _cmsAllocMutexPluginChunk(ctx, src);
+
+ // Make sure no one failed
+ for (i=Logger; i < MemoryClientMax; i++) {
+
+ if (src ->chunks[i] == NULL) {
+ cmsDeleteContext((cmsContext) ctx);
+ return NULL;
+ }
+ }
+
+ return (cmsContext) ctx;
+}
+
+
+
+static
+struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
+{
+ struct _cmsContext_struct* prev;
+
+ // Search for previous
+ for (prev = _cmsContextPoolHead;
+ prev != NULL;
+ prev = prev ->Next)
+ {
+ if (prev ->Next == id)
+ return prev;
+ }
+
+ return NULL; // List is empty or only one element!
+}
+
+// Frees any resources associated with the given context,
+// and destroys the context placeholder.
+// The ContextID can no longer be used in any THR operation.
+void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
+{
+ if (ContextID != NULL) {
+
+ struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
+ struct _cmsContext_struct fakeContext;
+ struct _cmsContext_struct* prev;
+
+ memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
+
+ fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
+ fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
+
+ // Get rid of plugins
+ cmsUnregisterPluginsTHR(ContextID);
+
+ // Since all memory is allocated in the private pool, all what we need to do is destroy the pool
+ if (ctx -> MemPool != NULL)
+ _cmsSubAllocDestroy(ctx ->MemPool);
+ ctx -> MemPool = NULL;
+
+ // Maintain list
+ _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+ if (_cmsContextPoolHead == ctx) {
+
+ _cmsContextPoolHead = ctx->Next;
+ }
+ else {
+
+ // Search for previous
+ for (prev = _cmsContextPoolHead;
+ prev != NULL;
+ prev = prev ->Next)
+ {
+ if (prev -> Next == ctx) {
+ prev -> Next = ctx ->Next;
+ break;
+ }
+ }
+ }
+ _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+
+ // free the memory block itself
+ _cmsFree(&fakeContext, ctx);
+ }
+}
+
+// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
+void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
+{
+ return _cmsContextGetClientChunk(ContextID, UserPtr);
+}
+
+