Switch to libcms2-2.6
[openjpeg.git] / thirdparty / liblcms2 / src / cmsplugin.c
index 1fa5ff4e6c1d55226b93bfbc1f6c43050e760240..317e33e221f64c4c0ea4f80cbd8c9e1ff7873d32 100644 (file)
@@ -3,22 +3,22 @@
 //  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.
 //
 //---------------------------------------------------------------------------------
@@ -44,7 +44,7 @@ cmsUInt16Number CMSEXPORT  _cmsAdjustEndianess16(cmsUInt16Number Word)
     tmp = pByte[0];
     pByte[0] = pByte[1];
     pByte[1] = tmp;
-#endif      
+#endif
 
     return Word;
 }
@@ -76,12 +76,12 @@ cmsUInt32Number CMSEXPORT  _cmsAdjustEndianess32(cmsUInt32Number DWord)
 // 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);
@@ -91,15 +91,19 @@ void CMSEXPORT  _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number Q
     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
 }
 
@@ -110,8 +114,8 @@ cmsBool CMSEXPORT  _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
 
     _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;
@@ -123,8 +127,8 @@ cmsBool CMSEXPORT  _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
 
     _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;
@@ -155,8 +159,8 @@ cmsBool CMSEXPORT  _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
 
     _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;
@@ -168,8 +172,8 @@ cmsBool CMSEXPORT  _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
 
     _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) {
 
@@ -186,10 +190,10 @@ cmsBool CMSEXPORT   _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
 
     _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;
 }
 
@@ -200,8 +204,8 @@ cmsBool CMSEXPORT  _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n
 
     _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));
@@ -250,9 +254,9 @@ cmsBool CMSEXPORT  _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
 {
     _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;
 }
 
@@ -263,9 +267,9 @@ cmsBool CMSEXPORT  _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
     _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;
 }
 
@@ -290,9 +294,9 @@ cmsBool CMSEXPORT  _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
     _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;
 }
 
@@ -305,22 +309,22 @@ cmsBool CMSEXPORT  _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
 
     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;
 }
 
@@ -331,16 +335,16 @@ cmsBool CMSEXPORT  _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n
     _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);
 
@@ -365,7 +369,7 @@ cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
 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
@@ -386,13 +390,13 @@ cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
     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)
 {
@@ -431,7 +435,7 @@ cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
 
     _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);
@@ -454,7 +458,7 @@ cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
     cmsUInt8Number  Buffer[4];
     cmsUInt32Number NextAligned, At;
     cmsUInt32Number BytesToNextAlignedPos;
-    
+
     _cmsAssert(io != NULL);
 
     At = io -> Tell(io);
@@ -502,7 +506,7 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
     if (len < 0) return FALSE;   // Truncated, which is a fatal error for us
 
     rc = io ->Write(io, len, Buffer);
-    
+
     va_end(args);
 
     return rc;
@@ -511,80 +515,102 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
 
 // 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
@@ -595,18 +621,337 @@ cmsBool CMSEXPORT cmsPlugin(void* 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);
+}
+
+