Switch to libcms2-2.6
[openjpeg.git] / thirdparty / liblcms2 / src / cmslut.c
index d0fe9c80e4328260398a879f57c1706782327d7a..c491662b25c23048b5b7ad7fe4788211f18bbdc9 100644 (file)
@@ -1,24 +1,24 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2010 Marti Maria Saguer
+//  Copyright (c) 1998-2012 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.
 //
 //---------------------------------------------------------------------------------
 
 
 // Allocates an empty multi profile element
-cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID, 
+cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID,
                                 cmsStageSignature Type,
-                                cmsUInt32Number InputChannels, 
+                                cmsUInt32Number InputChannels,
                                 cmsUInt32Number OutputChannels,
-                                _cmsStageEvalFn     EvalPtr,           
-                                _cmsStageDupElemFn  DupElemPtr,        
-                                _cmsStageFreeElemFn FreePtr,           
-                                void*             Data)             
+                                _cmsStageEvalFn     EvalPtr,
+                                _cmsStageDupElemFn  DupElemPtr,
+                                _cmsStageFreeElemFn FreePtr,
+                                void*             Data)
 {
     cmsStage* ph = (cmsStage*) _cmsMallocZero(ContextID, sizeof(cmsStage));
 
     if (ph == NULL) return NULL;
-    
-    
+
+
     ph ->ContextID = ContextID;
 
     ph ->Type       = Type;
@@ -49,18 +49,18 @@ cmsStage* CMSEXPORT _cmsStageAllocPlaceholder(cmsContext ContextID,
 
     ph ->InputChannels  = InputChannels;
     ph ->OutputChannels = OutputChannels;
-    ph ->EvalPtr        = EvalPtr;      
-    ph ->DupElemPtr     = DupElemPtr;   
-    ph ->FreePtr        = FreePtr;               
+    ph ->EvalPtr        = EvalPtr;
+    ph ->DupElemPtr     = DupElemPtr;
+    ph ->FreePtr        = FreePtr;
     ph ->Data           = Data;
 
-    return ph; 
+    return ph;
 }
 
 
 static
-void EvaluateIdentity(const cmsFloat32Number In[], 
-                            cmsFloat32Number Out[], 
+void EvaluateIdentity(const cmsFloat32Number In[],
+                            cmsFloat32Number Out[],
                       const cmsStage *mpe)
 {
     memmove(Out, In, mpe ->InputChannels * sizeof(cmsFloat32Number));
@@ -69,10 +69,10 @@ void EvaluateIdentity(const cmsFloat32Number In[],
 
 cmsStage* CMSEXPORT cmsStageAllocIdentity(cmsContext ContextID, cmsUInt32Number nChannels)
 {
-    return _cmsStageAllocPlaceholder(ContextID, 
-                                   cmsSigIdentityElemType, 
+    return _cmsStageAllocPlaceholder(ContextID,
+                                   cmsSigIdentityElemType,
                                    nChannels, nChannels,
-                                   EvaluateIdentity,                            
+                                   EvaluateIdentity,
                                    NULL,
                                    NULL,
                                    NULL);
@@ -84,8 +84,8 @@ void FromFloatTo16(const cmsFloat32Number In[], cmsUInt16Number Out[], cmsUInt32
 {
     cmsUInt32Number i;
 
-    for (i=0; i < n; i++) {     
-        Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0);        
+    for (i=0; i < n; i++) {
+        Out[i] = _cmsQuickSaturateWord(In[i] * 65535.0);
     }
 }
 
@@ -105,7 +105,7 @@ void From16ToFloat(const cmsUInt16Number In[], cmsFloat32Number Out[], cmsUInt32
 // that conform the LUT. It should be called with the LUT, the number of expected elements and
 // then a list of expected types followed with a list of cmsFloat64Number pointers to MPE elements. If
 // the function founds a match with current pipeline, it fills the pointers and returns TRUE
-// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass 
+// if not, returns FALSE without touching anything. Setting pointers to NULL does bypass
 // the storage process.
 cmsBool  CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cmsUInt32Number n, ...)
 {
@@ -125,11 +125,11 @@ cmsBool  CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms
     for (i=0; i < n; i++) {
 
         // Get asked type
-        Type  = va_arg(args, cmsStageSignature);      
+        Type  = (cmsStageSignature)va_arg(args, cmsStageSignature);
         if (mpe ->Type != Type) {
 
             va_end(args);       // Mismatch. We are done.
-            return FALSE;       
+            return FALSE;
         }
         mpe = mpe ->Next;
     }
@@ -138,14 +138,14 @@ cmsBool  CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms
     mpe = Lut ->Elements;
     for (i=0; i < n; i++) {
 
-        ElemPtr = va_arg(args, void**);     
-        if (ElemPtr != NULL) 
+        ElemPtr = va_arg(args, void**);
+        if (ElemPtr != NULL)
             *ElemPtr = mpe;
 
         mpe = mpe ->Next;
     }
 
-    va_end(args);   
+    va_end(args);
     return TRUE;
 }
 
@@ -164,8 +164,8 @@ cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe)
 }
 
 static
-void EvaluateCurves(const cmsFloat32Number In[], 
-                    cmsFloat32Number Out[], 
+void EvaluateCurves(const cmsFloat32Number In[],
+                    cmsFloat32Number Out[],
                     const cmsStage *mpe)
 {
     _cmsStageToneCurvesData* Data;
@@ -196,7 +196,7 @@ void CurveSetElemTypeFree(cmsStage* mpe)
 
     if (Data ->TheCurves != NULL) {
         for (i=0; i < Data ->nCurves; i++) {
-            if (Data ->TheCurves[i] != NULL) 
+            if (Data ->TheCurves[i] != NULL)
                 cmsFreeToneCurve(Data ->TheCurves[i]);
         }
     }
@@ -232,13 +232,13 @@ void* CurveSetDup(cmsStage* mpe)
 
 Error:
 
-    if (NewElem ->TheCurves != NULL) { 
+    if (NewElem ->TheCurves != NULL) {
         for (i=0; i < NewElem ->nCurves; i++) {
             if (NewElem ->TheCurves[i])
-                cmsFreeToneCurve(Data ->TheCurves[i]);
+                cmsFreeToneCurve(NewElem ->TheCurves[i]);
         }
     }
-    _cmsFree(mpe ->ContextID, Data ->TheCurves);
+    _cmsFree(mpe ->ContextID, NewElem ->TheCurves);
     _cmsFree(mpe ->ContextID, NewElem);
     return NULL;
 }
@@ -250,15 +250,15 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe
     cmsUInt32Number i;
     _cmsStageToneCurvesData* NewElem;
     cmsStage* NewMPE;
-    
-    
+
+
     NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCurveSetElemType, nChannels, nChannels,
                                      EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL );
     if (NewMPE == NULL) return NULL;
 
-    NewElem = (_cmsStageToneCurvesData*) _cmsMalloc(ContextID, sizeof(_cmsStageToneCurvesData));
+    NewElem = (_cmsStageToneCurvesData*) _cmsMallocZero(ContextID, sizeof(_cmsStageToneCurvesData));
     if (NewElem == NULL) {
-        cmsStageFree(NewMPE); 
+        cmsStageFree(NewMPE);
         return NULL;
     }
 
@@ -267,7 +267,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe
     NewElem ->nCurves   = nChannels;
     NewElem ->TheCurves = (cmsToneCurve**) _cmsCalloc(ContextID, nChannels, sizeof(cmsToneCurve*));
     if (NewElem ->TheCurves == NULL) {
-        cmsStageFree(NewMPE); 
+        cmsStageFree(NewMPE);
         return NULL;
     }
 
@@ -281,12 +281,13 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe
         }
 
         if (NewElem ->TheCurves[i] == NULL) {
-            cmsStageFree(NewMPE); 
+            cmsStageFree(NewMPE);
             return NULL;
         }
+
     }
 
-    return NewMPE;
+   return NewMPE;
 }
 
 
@@ -294,7 +295,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe
 cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels)
 {
     cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL);
-    
+
     if (mpe == NULL) return NULL;
     mpe ->Implements = cmsSigIdentityElemType;
     return mpe;
@@ -308,8 +309,8 @@ cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels)
 
 // Special care should be taken here because precision loss. A temporary cmsFloat64Number buffer is being used
 static
-void EvaluateMatrix(const cmsFloat32Number In[], 
-                    cmsFloat32Number Out[], 
+void EvaluateMatrix(const cmsFloat32Number In[],
+                    cmsFloat32Number Out[],
                     const cmsStage *mpe)
 {
     cmsUInt32Number i, j;
@@ -324,10 +325,10 @@ void EvaluateMatrix(const cmsFloat32Number In[],
             Tmp += In[j] * Data->Double[i*mpe->InputChannels + j];
         }
 
-        if (Data ->Offset != NULL) 
+        if (Data ->Offset != NULL)
             Tmp += Data->Offset[i];
 
-        Out[i] = (cmsFloat32Number) Tmp;     
+        Out[i] = (cmsFloat32Number) Tmp;
     }
 
 
@@ -342,7 +343,7 @@ void* MatrixElemDup(cmsStage* mpe)
     _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
     _cmsStageMatrixData* NewElem;
     cmsUInt32Number sz;
-    
+
     NewElem = (_cmsStageMatrixData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageMatrixData));
     if (NewElem == NULL) return NULL;
 
@@ -351,7 +352,7 @@ void* MatrixElemDup(cmsStage* mpe)
     NewElem ->Double = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, Data ->Double, sz * sizeof(cmsFloat64Number)) ;
 
     if (Data ->Offset)
-        NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID, 
+        NewElem ->Offset = (cmsFloat64Number*) _cmsDupMem(mpe ->ContextID,
                                                 Data ->Offset, mpe -> OutputChannels * sizeof(cmsFloat64Number)) ;
 
     return (void*) NewElem;
@@ -362,6 +363,8 @@ static
 void MatrixElemTypeFree(cmsStage* mpe)
 {
     _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data;
+    if (Data == NULL)
+        return;
     if (Data ->Double)
         _cmsFree(mpe ->ContextID, Data ->Double);
 
@@ -373,7 +376,7 @@ void MatrixElemTypeFree(cmsStage* mpe)
 
 
 
-cmsStage*  CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols, 
+cmsStage*  CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number Rows, cmsUInt32Number Cols,
                                      const cmsFloat64Number* Matrix, const cmsFloat64Number* Offset)
 {
     cmsUInt32Number i, n;
@@ -392,10 +395,10 @@ cmsStage*  CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R
                                      EvaluateMatrix, MatrixElemDup, MatrixElemTypeFree, NULL );
     if (NewMPE == NULL) return NULL;
 
-   
+
     NewElem = (_cmsStageMatrixData*) _cmsMallocZero(ContextID, sizeof(_cmsStageMatrixData));
     if (NewElem == NULL) return NULL;
-  
+
 
     NewElem ->Double = (cmsFloat64Number*) _cmsCalloc(ContextID, n, sizeof(cmsFloat64Number));
 
@@ -410,7 +413,7 @@ cmsStage*  CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R
 
 
     if (Offset != NULL) {
-    
+
         NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number));
         if (NewElem->Offset == NULL) {
            MatrixElemTypeFree(NewMPE);
@@ -422,7 +425,7 @@ cmsStage*  CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R
         }
 
     }
-    
+
     NewMPE ->Data  = (void*) NewElem;
     return NewMPE;
 }
@@ -437,7 +440,7 @@ cmsStage*  CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R
 static
 void EvaluateCLUTfloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe)
 {
-    _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;  
+    _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
 
     Data -> Params ->Interpolation.LerpFloat(In, Out, Data->Params);
 }
@@ -449,11 +452,11 @@ void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[],
 {
     _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
     cmsUInt16Number In16[MAX_STAGE_CHANNELS], Out16[MAX_STAGE_CHANNELS];
-    
+
     _cmsAssert(mpe ->InputChannels  <= MAX_STAGE_CHANNELS);
     _cmsAssert(mpe ->OutputChannels <= MAX_STAGE_CHANNELS);
 
-    FromFloatTo16(In, In16, mpe ->InputChannels);   
+    FromFloatTo16(In, In16, mpe ->InputChannels);
     Data -> Params ->Interpolation.Lerp16(In16, Out16, Data->Params);
     From16ToFloat(Out16, Out,  mpe ->OutputChannels);
 }
@@ -486,8 +489,8 @@ void* CLUTElemDup(cmsStage* mpe)
 {
     _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
     _cmsStageCLutData* NewElem;
-    
-    
+
+
     NewElem = (_cmsStageCLutData*) _cmsMallocZero(mpe ->ContextID, sizeof(_cmsStageCLutData));
     if (NewElem == NULL) return NULL;
 
@@ -496,20 +499,31 @@ void* CLUTElemDup(cmsStage* mpe)
 
     if (Data ->Tab.T) {
 
-        if (Data ->HasFloatValues)
+        if (Data ->HasFloatValues) {
             NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number));
-        else
+            if (NewElem ->Tab.TFloat == NULL)
+                goto Error;
+        } else {
             NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number));
+            if (NewElem ->Tab.TFloat == NULL)
+                goto Error;
+        }
     }
-    
+
     NewElem ->Params   = _cmsComputeInterpParamsEx(mpe ->ContextID,
-                                                   Data ->Params ->nSamples, 
+                                                   Data ->Params ->nSamples,
                                                    Data ->Params ->nInputs,
-                                                   Data ->Params ->nOutputs, 
+                                                   Data ->Params ->nOutputs,
                                                    NewElem ->Tab.T,
                                                    Data ->Params ->dwFlags);
-
-    return (void*) NewElem;
+    if (NewElem->Params != NULL)
+        return (void*) NewElem;
+ Error:
+    if (NewElem->Tab.T)
+        // This works for both types
+        _cmsFree(mpe ->ContextID, NewElem -> Tab.T);
+    _cmsFree(mpe ->ContextID, NewElem);
+    return NULL;
 }
 
 
@@ -518,7 +532,7 @@ void CLutElemTypeFree(cmsStage* mpe)
 {
 
     _cmsStageCLutData* Data = (_cmsStageCLutData*) mpe ->Data;
-    
+
     // Already empty
     if (Data == NULL) return;
 
@@ -526,29 +540,36 @@ void CLutElemTypeFree(cmsStage* mpe)
     if (Data -> Tab.T)
         _cmsFree(mpe ->ContextID, Data -> Tab.T);
 
-    _cmsFreeInterpParams(Data ->Params);    
+    _cmsFreeInterpParams(Data ->Params);
     _cmsFree(mpe ->ContextID, mpe ->Data);
 }
 
 
 // Allocates a 16-bit multidimensional CLUT. This is evaluated at 16-bit precision. Table may have different
 // granularity on each dimension.
-cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, 
-                                         const cmsUInt32Number clutPoints[], 
-                                         cmsUInt32Number inputChan, 
-                                         cmsUInt32Number outputChan, 
+cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID,
+                                         const cmsUInt32Number clutPoints[],
+                                         cmsUInt32Number inputChan,
+                                         cmsUInt32Number outputChan,
                                          const cmsUInt16Number* Table)
 {
     cmsUInt32Number i, n;
     _cmsStageCLutData* NewElem;
     cmsStage* NewMPE;
-    
+
+    _cmsAssert(clutPoints != NULL);
+
+    if (inputChan > MAX_INPUT_DIMENSIONS) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS);
+        return NULL;
+    }
+
     NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan,
                                      EvaluateCLUTfloatIn16, CLUTElemDup, CLutElemTypeFree, NULL );
 
     if (NewMPE == NULL) return NULL;
 
-    NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData));
+    NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData));
     if (NewElem == NULL) {
         cmsStageFree(NewMPE);
         return NULL;
@@ -586,10 +607,10 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID,
     return NewMPE;
 }
 
-cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID, 
-                                    cmsUInt32Number nGridPoints, 
-                                    cmsUInt32Number inputChan, 
-                                    cmsUInt32Number outputChan, 
+cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID,
+                                    cmsUInt32Number nGridPoints,
+                                    cmsUInt32Number inputChan,
+                                    cmsUInt32Number outputChan,
                                     const cmsUInt16Number* Table)
 {
     cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
@@ -599,15 +620,14 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bit(cmsContext ContextID,
     for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
         Dimensions[i] = nGridPoints;
 
-
     return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table);
 }
 
 
-cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID, 
-                                       cmsUInt32Number nGridPoints, 
-                                       cmsUInt32Number inputChan, 
-                                       cmsUInt32Number outputChan, 
+cmsStage* CMSEXPORT cmsStageAllocCLutFloat(cmsContext ContextID,
+                                       cmsUInt32Number nGridPoints,
+                                       cmsUInt32Number inputChan,
+                                       cmsUInt32Number outputChan,
                                        const cmsFloat32Number* Table)
 {
    cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
@@ -627,15 +647,20 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c
     cmsUInt32Number i, n;
     _cmsStageCLutData* NewElem;
     cmsStage* NewMPE;
-    
+
     _cmsAssert(clutPoints != NULL);
 
+    if (inputChan > MAX_INPUT_DIMENSIONS) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Too many input channels (%d channels, max=%d)", inputChan, MAX_INPUT_DIMENSIONS);
+        return NULL;
+    }
+
     NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan,
                                              EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL);
     if (NewMPE == NULL) return NULL;
 
-  
-    NewElem = (_cmsStageCLutData*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData));
+
+    NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData));
     if (NewElem == NULL) {
         cmsStageFree(NewMPE);
         return NULL;
@@ -644,7 +669,7 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c
     NewMPE ->Data  = (void*) NewElem;
 
     // There is a potential integer overflow on conputing n and nEntries.
-    NewElem -> nEntries = n = outputChan * CubeSize( clutPoints, inputChan);
+    NewElem -> nEntries = n = outputChan * CubeSize(clutPoints, inputChan);
     NewElem -> HasFloatValues = TRUE;
 
     if (n == 0) {
@@ -664,16 +689,12 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c
         }
     }
 
-
-    
     NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints,  inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT);
     if (NewElem ->Params == NULL) {
         cmsStageFree(NewMPE);
         return NULL;
     }
 
-
-
     return NewMPE;
 }
 
@@ -684,7 +705,7 @@ int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Numbe
     int nChan = *(int*) Cargo;
     int i;
 
-    for (i=0; i < nChan; i++) 
+    for (i=0; i < nChan; i++)
         Out[i] = In[i];
 
     return 1;
@@ -696,13 +717,13 @@ cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan)
     cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
     cmsStage* mpe ;
     int i;
-        
+
     for (i=0; i < MAX_INPUT_DIMENSIONS; i++)
         Dimensions[i] = 2;
 
     mpe = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, nChan, nChan, NULL);
     if (mpe == NULL) return NULL;
-    
+
     if (!cmsStageSampleCLut16bit(mpe, IdentitySampler, &nChan, 0)) {
         cmsStageFree(mpe);
         return NULL;
@@ -729,17 +750,24 @@ cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples)
 cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags)
 {
     int i, t, nTotalPoints, index, rest;
-    int nInputs, nOutputs;  
+    int nInputs, nOutputs;
     cmsUInt32Number* nSamples;
-    cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS];
-    _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; 
+    cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
+    _cmsStageCLutData* clut;
+
+    if (mpe == NULL) return FALSE;
+
+    clut = (_cmsStageCLutData*) mpe->Data;
 
+    if (clut == NULL) return FALSE;
 
     nSamples = clut->Params ->nSamples;
     nInputs  = clut->Params ->nInputs;
     nOutputs = clut->Params ->nOutputs;
 
-    if (nInputs >= cmsMAXCHANNELS) return FALSE;
+    if (nInputs <= 0) return FALSE;
+    if (nOutputs <= 0) return FALSE;
+    if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE;
     if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
 
     nTotalPoints = CubeSize(nSamples, nInputs);
@@ -755,7 +783,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
 
             rest /= nSamples[t];
 
-            In[t] = _cmsQuantizeVal(Colorant, nSamples[t]);                         
+            In[t] = _cmsQuantizeVal(Colorant, nSamples[t]);
         }
 
         if (clut ->Tab.T != NULL) {
@@ -786,14 +814,16 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
     int i, t, nTotalPoints, index, rest;
     int nInputs, nOutputs;
     cmsUInt32Number* nSamples;
-    cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS];   
-    _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; 
+    cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
+    _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
 
     nSamples = clut->Params ->nSamples;
     nInputs  = clut->Params ->nInputs;
     nOutputs = clut->Params ->nOutputs;
 
-    if (nInputs >= cmsMAXCHANNELS) return FALSE;
+    if (nInputs <= 0) return FALSE;
+    if (nOutputs <= 0) return FALSE;
+    if (nInputs  > MAX_INPUT_DIMENSIONS) return FALSE;
     if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
 
     nTotalPoints = CubeSize(nSamples, nInputs);
@@ -804,12 +834,12 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
 
         rest = i;
         for (t = nInputs-1; t >=0; --t) {
-         
+
             cmsUInt32Number  Colorant = rest % nSamples[t];
 
             rest /= nSamples[t];
 
-            In[t] =  (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0);                         
+            In[t] =  (cmsFloat32Number) (_cmsQuantizeVal(Colorant, nSamples[t]) / 65535.0);
         }
 
         if (clut ->Tab.TFloat != NULL) {
@@ -857,7 +887,7 @@ cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number
             cmsUInt32Number  Colorant = rest % clutPoints[t];
 
             rest /= clutPoints[t];
-            In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]);   
+            In[t] = _cmsQuantizeVal(Colorant, clutPoints[t]);
 
         }
 
@@ -887,7 +917,7 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI
             cmsUInt32Number  Colorant = rest % clutPoints[t];
 
             rest /= clutPoints[t];
-            In[t] =  (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0);    
+            In[t] =  (cmsFloat32Number) (_cmsQuantizeVal(Colorant, clutPoints[t]) / 65535.0);
 
         }
 
@@ -904,8 +934,8 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI
 
 
 static
-void EvaluateLab2XYZ(const cmsFloat32Number In[], 
-                     cmsFloat32Number Out[], 
+void EvaluateLab2XYZ(const cmsFloat32Number In[],
+                     cmsFloat32Number Out[],
                      const cmsStage *mpe)
 {
     cmsCIELab Lab;
@@ -913,18 +943,18 @@ void EvaluateLab2XYZ(const cmsFloat32Number In[],
     const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ;
 
     // V4 rules
-    Lab.L = In[0] * 100.0;        
+    Lab.L = In[0] * 100.0;
     Lab.a = In[1] * 255.0 - 128.0;
     Lab.b = In[2] * 255.0 - 128.0;
 
     cmsLab2XYZ(NULL, &XYZ, &Lab);
 
-    // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff 
+    // From XYZ, range 0..19997 to 0..1.0, note that 1.99997 comes from 0xffff
     // encoded as 1.15 fixed point, so 1 + (32767.0 / 32768.0)
 
-    Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj); 
-    Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj); 
-    Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj); 
+    Out[0] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.X / XYZadj);
+    Out[1] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Y / XYZadj);
+    Out[2] = (cmsFloat32Number) ((cmsFloat64Number) XYZ.Z / XYZadj);
     return;
 
     cmsUNUSED_PARAMETER(mpe);
@@ -939,9 +969,9 @@ cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID)
 
 // ********************************************************************************
 
-// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable 
+// v2 L=100 is supposed to be placed on 0xFF00. There is no reasonable
 // number of gridpoints that would make exact match. However, a prelinearization
-// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot. 
+// of 258 entries, would map 0xFF00 exactly on entry 257, and this is good to avoid scum dot.
 // Almost all what we need but unfortunately, the rest of entries should be scaled by
 // (255*257/256) and this is not exact.
 
@@ -956,13 +986,13 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID)
     LabTable[2] = cmsBuildTabulatedToneCurve16(ContextID, 258, NULL);
 
     for (j=0; j < 3; j++) {
-    
+
         if (LabTable[j] == NULL) {
             cmsFreeToneCurveTriple(LabTable);
             return NULL;
         }
-        
-        // We need to map * (0xffff / 0xff00), thats same as (257 / 256) 
+
+        // We need to map * (0xffff / 0xff00), thats same as (257 / 256)
         // So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256);
         for (i=0; i < 257; i++)  {
 
@@ -975,6 +1005,7 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID)
     mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable);
     cmsFreeToneCurveTriple(LabTable);
 
+    if (mpe == NULL) return NULL;
     mpe ->Implements = cmsSigLabV2toV4;
     return mpe;
 }
@@ -985,8 +1016,8 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID)
 cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID)
 {
     static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0,
-                                     0, 65535.0/65280.0, 0, 
-                                     0, 0, 65535.0/65280.0 
+                                     0, 65535.0/65280.0, 0,
+                                     0, 0, 65535.0/65280.0
                                      };
 
     cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V2ToV4, NULL);
@@ -1001,8 +1032,8 @@ cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID)
 cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID)
 {
     static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0,
-                                     0, 65280.0/65535.0, 0, 
-                                     0, 0, 65280.0/65535.0 
+                                     0, 65280.0/65535.0, 0,
+                                     0, 0, 65280.0/65535.0
                                      };
 
      cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, V4ToV2, NULL);
@@ -1013,6 +1044,89 @@ cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID)
 }
 
 
+// To Lab to float. Note that the MPE gives numbers in normal Lab range
+// and we need 0..1.0 range for the formatters
+// L* : 0...100 => 0...1.0  (L* / 100)
+// ab* : -128..+127 to 0..1  ((ab* + 128) / 255)
+
+cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID)
+{
+    static const cmsFloat64Number a1[] = {
+        1.0/100.0, 0, 0,
+        0, 1.0/255.0, 0,
+        0, 0, 1.0/255.0
+    };
+
+    static const cmsFloat64Number o1[] = {
+        0,
+        128.0/255.0,
+        128.0/255.0
+    };
+
+    cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, o1);
+
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigLab2FloatPCS;
+    return mpe;
+}
+
+// Fom XYZ to floating point PCS
+cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID)
+{
+#define n (32768.0/65535.0)
+    static const cmsFloat64Number a1[] = {
+        n, 0, 0,
+        0, n, 0,
+        0, 0, n
+    };
+#undef n
+
+    cmsStage *mpe =  cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL);
+
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigXYZ2FloatPCS;
+    return mpe;
+}
+
+cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID)
+{
+    static const cmsFloat64Number a1[] = {
+        100.0, 0, 0,
+        0, 255.0, 0,
+        0, 0, 255.0
+    };
+
+    static const cmsFloat64Number o1[] = {
+        0,
+        -128.0,
+        -128.0
+    };
+
+    cmsStage *mpe =  cmsStageAllocMatrix(ContextID, 3, 3, a1, o1);
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigFloatPCS2Lab;
+    return mpe;
+}
+
+cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID)
+{
+#define n (65535.0/32768.0)
+
+    static const cmsFloat64Number a1[] = {
+        n, 0, 0,
+        0, n, 0,
+        0, 0, n
+    };
+#undef n
+
+    cmsStage *mpe = cmsStageAllocMatrix(ContextID, 3, 3, a1, NULL);
+    if (mpe == NULL) return mpe;
+    mpe ->Implements = cmsSigFloatPCS2XYZ;
+    return mpe;
+}
+
+
+
 // ********************************************************************************
 // Type cmsSigXYZ2LabElemType
 // ********************************************************************************
@@ -1022,20 +1136,20 @@ void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const
 {
     cmsCIELab Lab;
     cmsCIEXYZ XYZ;
-    const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ; 
+    const cmsFloat64Number XYZadj = MAX_ENCODEABLE_XYZ;
 
     // From 0..1.0 to XYZ
 
-    XYZ.X = In[0] * XYZadj; 
-    XYZ.Y = In[1] * XYZadj; 
+    XYZ.X = In[0] * XYZadj;
+    XYZ.Y = In[1] * XYZadj;
     XYZ.Z = In[2] * XYZadj;
 
     cmsXYZ2Lab(NULL, &Lab, &XYZ);
-    
+
     // From V4 Lab to 0..1.0
 
-    Out[0] = (cmsFloat32Number) (Lab.L / 100.0); 
-    Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0); 
+    Out[0] = (cmsFloat32Number) (Lab.L / 100.0);
+    Out[1] = (cmsFloat32Number) ((Lab.a + 128.0) / 255.0);
     Out[2] = (cmsFloat32Number) ((Lab.b + 128.0) / 255.0);
     return;
 
@@ -1043,9 +1157,9 @@ void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const
 }
 
 cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID)
-{    
+{
     return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL);
+
 }
 
 // ********************************************************************************
@@ -1065,10 +1179,10 @@ cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID)
 }
 
 
-// Free a single MPE 
+// Free a single MPE
 void CMSEXPORT cmsStageFree(cmsStage* mpe)
 {
-    if (mpe ->FreePtr) 
+    if (mpe ->FreePtr)
         mpe ->FreePtr(mpe);
 
     _cmsFree(mpe ->ContextID, mpe);
@@ -1105,24 +1219,34 @@ cmsStage*  CMSEXPORT cmsStageNext(const cmsStage* mpe)
 cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
 {
     cmsStage* NewMPE;
-    
+
     if (mpe == NULL) return NULL;
-    NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID, 
-                                     mpe ->Type, 
-                                     mpe ->InputChannels, 
+    NewMPE = _cmsStageAllocPlaceholder(mpe ->ContextID,
+                                     mpe ->Type,
+                                     mpe ->InputChannels,
                                      mpe ->OutputChannels,
                                      mpe ->EvalPtr,
                                      mpe ->DupElemPtr,
                                      mpe ->FreePtr,
                                      NULL);
     if (NewMPE == NULL) return NULL;
-  
-    NewMPE ->Implements     = mpe ->Implements;
-    if (mpe ->DupElemPtr) 
-        NewMPE ->Data       = mpe ->DupElemPtr(mpe);
-    else
+
+    NewMPE ->Implements = mpe ->Implements;
+
+    if (mpe ->DupElemPtr) {
+
+        NewMPE ->Data = mpe ->DupElemPtr(mpe);
+
+        if (NewMPE->Data == NULL) {
+
+            cmsStageFree(NewMPE);
+            return NULL;
+        }
+
+    } else {
+
         NewMPE ->Data       = NULL;
+    }
 
     return NewMPE;
 }
@@ -1135,7 +1259,7 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
 static
 void BlessLUT(cmsPipeline* lut)
 {
-    // We can set the input/ouput channels only if we have elements. 
+    // We can set the input/ouput channels only if we have elements.
     if (lut ->Elements != NULL) {
 
         cmsStage *First, *Last;
@@ -1149,50 +1273,50 @@ void BlessLUT(cmsPipeline* lut)
 }
 
 
-// Default to evaluate the LUT on 16 bit-basis. Precision is retained. 
+// Default to evaluate the LUT on 16 bit-basis. Precision is retained.
 static
 void _LUTeval16(register const cmsUInt16Number In[], register cmsUInt16Number Out[],  register const void* D)
 {
     cmsPipeline* lut = (cmsPipeline*) D;
-    cmsStage *mpe;   
+    cmsStage *mpe;
     cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS];
     int Phase = 0, NextPhase;
-    
+
     From16ToFloat(In, &Storage[Phase][0], lut ->InputChannels);
 
-    for (mpe = lut ->Elements; 
-         mpe != NULL; 
+    for (mpe = lut ->Elements;
+         mpe != NULL;
          mpe = mpe ->Next) {
 
-             NextPhase = Phase ^ 1;            
+             NextPhase = Phase ^ 1;
              mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe);
              Phase = NextPhase;
     }
-    
+
 
     FromFloatTo16(&Storage[Phase][0], Out, lut ->OutputChannels);
 }
 
 
 
-// Does evaluate the LUT on cmsFloat32Number-basis. 
+// Does evaluate the LUT on cmsFloat32Number-basis.
 static
 void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Number Out[], const void* D)
 {
     cmsPipeline* lut = (cmsPipeline*) D;
-    cmsStage *mpe;   
+    cmsStage *mpe;
     cmsFloat32Number Storage[2][MAX_STAGE_CHANNELS];
     int Phase = 0, NextPhase;
-    
+
     memmove(&Storage[Phase][0], In, lut ->InputChannels  * sizeof(cmsFloat32Number));
 
-    for (mpe = lut ->Elements; 
-         mpe != NULL; 
+    for (mpe = lut ->Elements;
+         mpe != NULL;
          mpe = mpe ->Next) {
 
               NextPhase = Phase ^ 1;
               mpe ->EvalPtr(&Storage[Phase][0], &Storage[NextPhase][0], mpe);
-              Phase = NextPhase;          
+              Phase = NextPhase;
     }
 
     memmove(Out, &Storage[Phase][0], lut ->OutputChannels * sizeof(cmsFloat32Number));
@@ -1221,7 +1345,7 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In
        NewLUT ->EvalFloatFn = _LUTevalFloat;
        NewLUT ->DupDataFn   = NULL;
        NewLUT ->FreeDataFn  = NULL;
-       NewLUT ->Data        = NewLUT;     
+       NewLUT ->Data        = NewLUT;
        NewLUT ->ContextID   = ContextID;
 
        BlessLUT(NewLUT);
@@ -1229,30 +1353,37 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In
        return NewLUT;
 }
 
+cmsContext CMSEXPORT cmsGetPipelineContextID(const cmsPipeline* lut)
+{
+    _cmsAssert(lut != NULL);
+    return lut ->ContextID;
+}
 
 cmsUInt32Number CMSEXPORT cmsPipelineInputChannels(const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     return lut ->InputChannels;
 }
 
 cmsUInt32Number CMSEXPORT cmsPipelineOutputChannels(const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     return lut ->OutputChannels;
 }
 
 // Free a profile elements LUT
 void CMSEXPORT cmsPipelineFree(cmsPipeline* lut)
 {
-    cmsStage *mpe, *Next;   
+    cmsStage *mpe, *Next;
 
     if (lut == NULL) return;
 
-    for (mpe = lut ->Elements; 
-        mpe != NULL; 
+    for (mpe = lut ->Elements;
+        mpe != NULL;
         mpe = Next) {
 
             Next = mpe ->Next;
-            cmsStageFree(mpe);            
+            cmsStageFree(mpe);
     }
 
     if (lut ->FreeDataFn) lut ->FreeDataFn(lut ->ContextID, lut ->Data);
@@ -1261,16 +1392,18 @@ void CMSEXPORT cmsPipelineFree(cmsPipeline* lut)
 }
 
 
-// Default to evaluate the LUT on 16 bit-basis. 
+// Default to evaluate the LUT on 16 bit-basis.
 void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out[],  const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     lut ->Eval16Fn(In, Out, lut->Data);
 }
 
 
-// Does evaluate the LUT on cmsFloat32Number-basis. 
+// Does evaluate the LUT on cmsFloat32Number-basis.
 void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsPipeline* lut)
 {
+    _cmsAssert(lut != NULL);
     lut ->EvalFloatFn(In, Out, lut);
 }
 
@@ -1280,14 +1413,16 @@ void CMSEXPORT cmsPipelineEvalFloat(const cmsFloat32Number In[], cmsFloat32Numbe
 cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
 {
     cmsPipeline* NewLUT;
-    cmsStage *NewMPE, *Anterior = NULL, *mpe;   
+    cmsStage *NewMPE, *Anterior = NULL, *mpe;
     cmsBool  First = TRUE;
 
     if (lut == NULL) return NULL;
 
-    NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels);  
-    for (mpe = lut ->Elements; 
-         mpe != NULL; 
+    NewLUT = cmsPipelineAlloc(lut ->ContextID, lut ->InputChannels, lut ->OutputChannels);
+    if (NewLUT == NULL) return NULL;
+
+    for (mpe = lut ->Elements;
+         mpe != NULL;
          mpe = mpe ->Next) {
 
              NewMPE = cmsStageDup(mpe);
@@ -1296,22 +1431,24 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
                  cmsPipelineFree(NewLUT);
                  return NULL;
              }
-    
+
              if (First) {
                  NewLUT ->Elements = NewMPE;
                  First = FALSE;
              }
              else {
-                Anterior ->Next = NewMPE;               
+                Anterior ->Next = NewMPE;
              }
 
             Anterior = NewMPE;
     }
 
-    NewLUT ->DupDataFn  = lut ->DupDataFn;
-    NewLUT ->FreeDataFn = lut ->FreeDataFn;
+    NewLUT ->Eval16Fn    = lut ->Eval16Fn;
+    NewLUT ->EvalFloatFn = lut ->EvalFloatFn;
+    NewLUT ->DupDataFn   = lut ->DupDataFn;
+    NewLUT ->FreeDataFn  = lut ->FreeDataFn;
 
-    if (NewLUT ->DupDataFn != NULL) 
+    if (NewLUT ->DupDataFn != NULL)
         NewLUT ->Data = NewLUT ->DupDataFn(lut ->ContextID, lut->Data);
 
 
@@ -1322,12 +1459,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
 }
 
 
-void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe)
+int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe)
 {
     cmsStage* Anterior = NULL, *pt;
 
-    _cmsAssert(lut != NULL);
-    _cmsAssert(mpe != NULL);
+    if (lut == NULL || mpe == NULL)
+        return FALSE;
 
     switch (loc) {
 
@@ -1338,10 +1475,10 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
 
         case cmsAT_END:
 
-            if (lut ->Elements == NULL) 
+            if (lut ->Elements == NULL)
                 lut ->Elements = mpe;
             else {
-            
+
                 for (pt = lut ->Elements;
                      pt != NULL;
                      pt = pt -> Next) Anterior = pt;
@@ -1351,9 +1488,11 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
             }
             break;
         default:;
+            return FALSE;
     }
 
     BlessLUT(lut);
+    return TRUE;
 }
 
 // Unlink an element and return the pointer to it
@@ -1362,7 +1501,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
     cmsStage *Anterior, *pt, *Last;
     cmsStage *Unlinked = NULL;
 
-    
+
     // If empty LUT, there is nothing to remove
     if (lut ->Elements == NULL) {
         if (mpe) *mpe = NULL;
@@ -1372,14 +1511,14 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
     // On depending on the strategy...
     switch (loc) {
 
-        case cmsAT_BEGIN: 
+        case cmsAT_BEGIN:
             {
                 cmsStage* elem = lut ->Elements;
-             
+
                 lut ->Elements = elem -> Next;
                 elem ->Next = NULL;
                 Unlinked = elem;
-                           
+
             }
             break;
 
@@ -1389,21 +1528,21 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
                 pt != NULL;
                 pt = pt -> Next) {
                     Anterior = Last;
-                    Last = pt;              
+                    Last = pt;
             }
 
             Unlinked = Last;  // Next already points to NULL
 
             // Truncate the chain
-            if (Anterior) 
+            if (Anterior)
                 Anterior ->Next = NULL;
-            else 
+            else
                 lut ->Elements = NULL;
             break;
         default:;
     }
 
-    if (mpe) 
+    if (mpe)
         *mpe = Unlinked;
     else
         cmsStageFree(Unlinked);
@@ -1415,9 +1554,9 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
 // Concatenate two LUT into a new single one
 cmsBool  CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
 {
-    cmsStage* mpe, *NewMPE;
+    cmsStage* mpe;
 
-    // If both LUTS does not have elements, we need to inherit 
+    // If both LUTS does not have elements, we need to inherit
     // the number of channels
     if (l1 ->Elements == NULL && l2 ->Elements == NULL) {
         l1 ->InputChannels  = l2 ->InputChannels;
@@ -1425,22 +1564,17 @@ cmsBool  CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
     }
 
     // Cat second
-    for (mpe = l2 ->Elements; 
-         mpe != NULL; 
+    for (mpe = l2 ->Elements;
+         mpe != NULL;
          mpe = mpe ->Next) {
 
             // We have to dup each element
-             NewMPE = cmsStageDup(mpe);
-
-             if (NewMPE == NULL) {
-                 return FALSE;
-             }
-    
-             cmsPipelineInsertStage(l1, cmsAT_END, NewMPE);
+            if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe)))
+                return FALSE;
     }
 
-  BlessLUT(l1);
-  return TRUE;
+    BlessLUT(l1);
+    return TRUE;
 }
 
 
@@ -1479,58 +1613,58 @@ cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut)
     return n;
 }
 
-// This function may be used to set the optional evalueator and a block of private data. If private data is being used, an optional
+// This function may be used to set the optional evaluator and a block of private data. If private data is being used, an optional
 // duplicator and free functions should also be specified in order to duplicate the LUT construct. Use NULL to inhibit such functionality.
-void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, 
-                                        _cmsOPTeval16Fn Eval16, 
-                                        void* PrivateData, 
-                                        _cmsOPTfreeDataFn FreePrivateDataFn, 
-                                        _cmsOPTdupDataFn DupPrivateDataFn)
+void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut,
+                                        _cmsOPTeval16Fn Eval16,
+                                        void* PrivateData,
+                                        _cmsFreeUserDataFn FreePrivateDataFn,
+                                        _cmsDupUserDataFn  DupPrivateDataFn)
 {
 
     Lut ->Eval16Fn = Eval16;
     Lut ->DupDataFn = DupPrivateDataFn;
-    Lut ->FreeDataFn = FreePrivateDataFn;   
+    Lut ->FreeDataFn = FreePrivateDataFn;
     Lut ->Data = PrivateData;
 }
 
 
 // ----------------------------------------------------------- Reverse interpolation
-// Here's how it goes. The derivative Df(x) of the function f is the linear 
-// transformation that best approximates f near the point x. It can be represented 
-// by a matrix A whose entries are the partial derivatives of the components of f 
+// Here's how it goes. The derivative Df(x) of the function f is the linear
+// transformation that best approximates f near the point x. It can be represented
+// by a matrix A whose entries are the partial derivatives of the components of f
 // with respect to all the coordinates. This is know as the Jacobian
 //
-// The best linear approximation to f is given by the matrix equation: 
-// 
-// y-y0 = A (x-x0) 
-// 
-// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this 
-// linear approximation will give a "better guess" for the zero of f. Thus let y=0, 
-// and since y0=f(x0) one can solve the above equation for x. This leads to the 
-// Newton's method formula: 
+// The best linear approximation to f is given by the matrix equation:
+//
+// y-y0 = A (x-x0)
+//
+// So, if x0 is a good "guess" for the zero of f, then solving for the zero of this
+// linear approximation will give a "better guess" for the zero of f. Thus let y=0,
+// and since y0=f(x0) one can solve the above equation for x. This leads to the
+// Newton's method formula:
+//
+// xn+1 = xn - A-1 f(xn)
 //
-// xn+1 = xn - A-1 f(xn) 
-// 
-// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the 
-// fashion described above. Iterating this will give better and better approximations 
-// if you have a "good enough" initial guess. 
+// where xn+1 denotes the (n+1)-st guess, obtained from the n-th guess xn in the
+// fashion described above. Iterating this will give better and better approximations
+// if you have a "good enough" initial guess.
 
 
 #define JACOBIAN_EPSILON            0.001f
 #define INVERSION_MAX_ITERATIONS    30
 
 // Increment with reflexion on boundary
-static 
+static
 void IncDelta(cmsFloat32Number *Val)
 {
-    if (*Val < (1.0 - JACOBIAN_EPSILON)) 
+    if (*Val < (1.0 - JACOBIAN_EPSILON))
 
         *Val += JACOBIAN_EPSILON;
-    
-    else 
+
+    else
         *Val -= JACOBIAN_EPSILON;
-    
+
 }
 
 
@@ -1554,7 +1688,7 @@ cmsFloat32Number EuclideanDistance(cmsFloat32Number a[], cmsFloat32Number b[], i
 // Evaluate a LUT in reverse direction. It only searches on 3->3 LUT. Uses Newton method
 //
 // x1 <- x - [J(x)]^-1 * f(x)
-// 
+//
 // lut: The LUT on where to do the search
 // Target: LabK, 3 values of Lab plus destination K which is fixed
 // Result: The obtained CMYK
@@ -1566,20 +1700,15 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
                                               const cmsPipeline* lut)
 {
     cmsUInt32Number  i, j;
-    cmsFloat64Number  error, LastError = 1E20;    
+    cmsFloat64Number  error, LastError = 1E20;
     cmsFloat32Number  fx[4], x[4], xd[4], fxd[4];
     cmsVEC3 tmp, tmp2;
-    cmsMAT3 Jacobian;    
-    cmsFloat64Number LastResult[4];
-
-
+    cmsMAT3 Jacobian;
+    
     // Only 3->3 and 4->3 are supported
     if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE;
     if (lut ->OutputChannels != 3) return FALSE;
-
-    // Mark result of -1
-    LastResult[0] = LastResult[1] = LastResult[2] = -1.0f;
-
+   
     // Take the hint as starting point if specified
     if (Hint == NULL) {
 
@@ -1589,10 +1718,10 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
     else {
 
         // Only copy 3 channels from hint...
-        for (j=0; j < 3; j++) 
-            x[j] = Hint[j];         
+        for (j=0; j < 3; j++)
+            x[j] = Hint[j];
     }
-    
+
     // If Lut is 4-dimensions, then grab target[3], which is fixed
     if (lut ->InputChannels == 4) {
         x[3] = Target[3];
@@ -1600,7 +1729,7 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
     else x[3] = 0; // To keep lint happy
 
 
-    // Iterate    
+    // Iterate
     for (i = 0; i < INVERSION_MAX_ITERATIONS; i++) {
 
         // Get beginning fx
@@ -1610,19 +1739,19 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
         error = EuclideanDistance(fx, Target, 3);
 
         // If not convergent, return last safe value
-        if (error >= LastError) 
+        if (error >= LastError)
             break;
 
         // Keep latest values
         LastError     = error;
-        for (j=0; j < lut ->InputChannels; j++) 
-                Result[j] = x[j]; 
+        for (j=0; j < lut ->InputChannels; j++)
+                Result[j] = x[j];
 
         // Found an exact match?
-        if (error <= 0) 
+        if (error <= 0)
             break;
 
-        // Obtain slope (the Jacobian)              
+        // Obtain slope (the Jacobian)
         for (j = 0; j < 3; j++) {
 
             xd[0] = x[0];
@@ -1636,7 +1765,7 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
 
             Jacobian.v[0].n[j] = ((fxd[0] - fx[0]) / JACOBIAN_EPSILON);
             Jacobian.v[1].n[j] = ((fxd[1] - fx[1]) / JACOBIAN_EPSILON);
-            Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON);        
+            Jacobian.v[2].n[j] = ((fxd[2] - fx[2]) / JACOBIAN_EPSILON);
         }
 
         // Solve system
@@ -1663,3 +1792,4 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[],
     return TRUE;
 }
 
+