Upgrade to lcms 2.12.

Update 0030-const-data.patch to patch cleanly, as some of the data to be
made const has changed.

Change-Id: Ie09cc33a7c97f70f061783a57c80024d2c5c4d8e
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/85430
Reviewed-by: Daniel Hosseinian <dhoss@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/third_party/lcms/0030-const-data.patch b/third_party/lcms/0030-const-data.patch
index 3b28020..42a3b93 100644
--- a/third_party/lcms/0030-const-data.patch
+++ b/third_party/lcms/0030-const-data.patch
@@ -21,9 +21,9 @@
  // The built-in list
 -static _cmsParametricCurvesCollection DefaultCurves = {
 +static const _cmsParametricCurvesCollection DefaultCurves = {
-     9,                                  // # of curve types
-     { 1, 2, 3, 4, 5, 6, 7, 8, 108 },    // Parametric curve ID
-     { 1, 3, 4, 5, 7, 4, 5, 5, 1 },      // Parameters by type
+     10,                                      // # of curve types
+     { 1, 2, 3, 4, 5, 6, 7, 8, 108, 109 },    // Parametric curve ID
+     { 1, 3, 4, 5, 7, 4, 5, 5,   1,   1 },    // Parameters by type
 @@ -162,7 +162,7 @@ cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase*
  
  // Search in type list, return position or -1 if not found
diff --git a/third_party/lcms/include/lcms2.h b/third_party/lcms/include/lcms2.h
index a8237d7..f60f5f7 100644
--- a/third_party/lcms/include/lcms2.h
+++ b/third_party/lcms/include/lcms2.h
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2020 Marti Maria Saguer
+//  Copyright (c) 1998-2021 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"),
@@ -23,7 +23,7 @@
 //
 //---------------------------------------------------------------------------------
 //
-// Version 2.11
+// Version 2.12
 //
 
 #ifndef _lcms2_H
@@ -81,7 +81,7 @@
 #endif
 
 // Version/release
-#define LCMS_VERSION        2100
+#define LCMS_VERSION        2120
 
 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant
 #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -1270,7 +1270,7 @@
 #define SAMPLER_INSPECT     0x01000000
 
 // For CLUT only
-CMSAPI cmsBool           CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe,    cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags);
+CMSAPI cmsBool           CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags);
 CMSAPI cmsBool           CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void* Cargo, cmsUInt32Number dwFlags);
 
 // Slicers
diff --git a/third_party/lcms/include/lcms2_plugin.h b/third_party/lcms/include/lcms2_plugin.h
index c36998e..5bc8227 100644
--- a/third_party/lcms/include/lcms2_plugin.h
+++ b/third_party/lcms/include/lcms2_plugin.h
@@ -286,7 +286,7 @@
 #define CMS_LERP_FLAGS_TRILINEAR          0x0100        // Hint only
 
 
-#define MAX_INPUT_DIMENSIONS 8
+#define MAX_INPUT_DIMENSIONS 15
 
 typedef struct _cms_interp_struc {  // Used on all interpolations. Supplied by lcms2 when calling the interpolation function
 
@@ -547,22 +547,28 @@
 // the optimization  search. Or FALSE if it is unable to optimize and want to give a chance
 // to the rest of optimizers.
 
-typedef void     (* _cmsOPTeval16Fn)(CMSREGISTER const cmsUInt16Number In[],
-                                     CMSREGISTER cmsUInt16Number Out[],
-                                     CMSREGISTER const void* Data);
-
-
 typedef cmsBool  (* _cmsOPToptimizeFn)(cmsPipeline** Lut,
                                        cmsUInt32Number  Intent,
                                        cmsUInt32Number* InputFormat,
                                        cmsUInt32Number* OutputFormat,
                                        cmsUInt32Number* dwFlags);
 
+// Pipeline Evaluator (in 16 bits)
+typedef void (* _cmsPipelineEval16Fn)(CMSREGISTER const cmsUInt16Number In[],
+                                     CMSREGISTER cmsUInt16Number Out[],
+                                     const void* Data);
+
+// Pipeline Evaluator (in floating point)
+typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[],
+                                         cmsFloat32Number Out[],
+                                         const void* Data);
+
+
 // 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.
 
 CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut,
-                                               _cmsOPTeval16Fn Eval16,
+                                               _cmsPipelineEval16Fn Eval16,
                                                void* PrivateData,
                                                _cmsFreeUserDataFn FreePrivateDataFn,
                                                _cmsDupUserDataFn DupPrivateDataFn);
@@ -626,6 +632,9 @@
 CMSAPI void   CMSEXPORT _cmsGetTransformFormatters16   (struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput);
 CMSAPI void   CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput);
 
+// Retrieve original flags
+CMSAPI cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo);
+
 typedef struct {
       cmsPluginBase     base;
 
diff --git a/third_party/lcms/src/cmsalpha.c b/third_party/lcms/src/cmsalpha.c
index a211318..36fdc9c 100644
--- a/third_party/lcms/src/cmsalpha.c
+++ b/third_party/lcms/src/cmsalpha.c
@@ -75,7 +75,7 @@
 void from8to16(void* dst, const void* src)
 {
        cmsUInt8Number n = *(cmsUInt8Number*)src;
-       *(cmsUInt16Number*) dst = FROM_8_TO_16(n);
+       *(cmsUInt16Number*) dst = (cmsUInt16Number) FROM_8_TO_16(n);
 }
 
 static
@@ -88,13 +88,13 @@
 static
 void from8toFLT(void* dst, const void* src)
 {
-       *(cmsFloat32Number*)dst = (*(cmsUInt8Number*)src) / 255.0f;
+       *(cmsFloat32Number*)dst = (cmsFloat32Number) (*(cmsUInt8Number*)src) / 255.0f;
 }
 
 static
 void from8toDBL(void* dst, const void* src)
 {
-       *(cmsFloat64Number*)dst = (*(cmsUInt8Number*)src) / 255.0;
+       *(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt8Number*)src) / 255.0;
 }
 
 static
@@ -153,13 +153,13 @@
 static
 void from16toDBL(void* dst, const void* src)
 {
-       *(cmsFloat64Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
+       *(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt16Number*)src) / 65535.0;
 }
 
 static
 void from16SEtoDBL(void* dst, const void* src)
 {
-    *(cmsFloat64Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;
+    *(cmsFloat64Number*)dst = (cmsFloat64Number) (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0;
 }
 
 static
diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c
index 217c67a..e0d5c12 100644
--- a/third_party/lcms/src/cmscgats.c
+++ b/third_party/lcms/src/cmscgats.c
@@ -1499,6 +1499,14 @@
     return SetDataFormat(it8, n, Sample);
 }
 
+// A safe atoi that returns 0 when NULL input is given
+static
+cmsInt32Number satoi(const char* b)
+{
+    if (b == NULL) return 0;
+    return atoi(b);
+}
+
 static
 void AllocateDataSet(cmsIT8* it8)
 {
@@ -1506,14 +1514,15 @@
 
     if (t -> Data) return;    // Already allocated
 
-    t-> nSamples   = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
-    t-> nPatches   = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
+    t-> nSamples   = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
+    t-> nPatches   = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
 
     if (t -> nSamples < 0 || t->nSamples > 0x7ffe || t->nPatches < 0 || t->nPatches > 0x7ffe)
     {
         SynError(it8, "AllocateDataSet: too much data");
     }
     else {
+        // Some dumb analizers warns of possible overflow here, just take a look couple of lines above.
         t->Data = (char**)AllocChunk(it8, ((cmsUInt32Number)t->nSamples + 1) * ((cmsUInt32Number)t->nPatches + 1) * sizeof(char*));
         if (t->Data == NULL) {
 
@@ -1679,11 +1688,11 @@
                     break;
 
             case WRITE_HEXADECIMAL:
-                    Writef(fp, "\t0x%X", atoi(p ->Value));
+                    Writef(fp, "\t0x%X", satoi(p ->Value));
                     break;
 
             case WRITE_BINARY:
-                    Writef(fp, "\t0x%B", atoi(p ->Value));
+                    Writef(fp, "\t0x%B", satoi(p ->Value));
                     break;
 
             case WRITE_PAIR:
@@ -1712,7 +1721,7 @@
 
        WriteStr(fp, "BEGIN_DATA_FORMAT\n");
        WriteStr(fp, " ");
-       nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
+       nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
 
        for (i = 0; i < nSamples; i++) {
 
@@ -1735,7 +1744,7 @@
 
        WriteStr (fp, "BEGIN_DATA\n");
 
-       t->nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
+       t->nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
 
        for (i = 0; i < t-> nPatches; i++) {
 
diff --git a/third_party/lcms/src/cmscnvrt.c b/third_party/lcms/src/cmscnvrt.c
index 301c3c8..b471da7 100644
--- a/third_party/lcms/src/cmscnvrt.c
+++ b/third_party/lcms/src/cmscnvrt.c
@@ -730,6 +730,9 @@
     cmsUInt32Number ICCIntents[256];
     cmsStage*         CLUT;
     cmsUInt32Number i, nGridPoints;
+    cmsUInt32Number lastProfilePos;
+    cmsUInt32Number preservationProfilesCount;
+    cmsHPROFILE hLastProfile;
 
 
     // Sanity check
@@ -739,20 +742,36 @@
     for (i=0; i < nProfiles; i++)
         ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]);
 
+
+    // Trim all CMYK devicelinks at the end  
+    lastProfilePos = nProfiles - 1;
+    hLastProfile = hProfiles[lastProfilePos];
+
+    while (lastProfilePos > 1)
+    {
+        hLastProfile = hProfiles[--lastProfilePos];
+        if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
+            cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
+            break;
+    }
+
+    preservationProfilesCount = lastProfilePos + 1;
+
     // Check for non-cmyk profiles
     if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
-        cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData)
+        !(cmsGetColorSpace(hLastProfile) == cmsSigCmykData ||
+        cmsGetDeviceClass(hLastProfile) == cmsSigOutputClass))
            return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags);
 
-    memset(&bp, 0, sizeof(bp));
-
     // Allocate an empty LUT for holding the result
     Result = cmsPipelineAlloc(ContextID, 4, 4);
     if (Result == NULL) return NULL;
 
+    memset(&bp, 0, sizeof(bp));
+
     // Create a LUT holding normal ICC transform
     bp.cmyk2cmyk = DefaultICCintents(ContextID,
-        nProfiles,
+                                     preservationProfilesCount,
         ICCIntents,
         hProfiles,
         BPC,
@@ -764,7 +783,7 @@
     // Now, compute the tone curve
     bp.KTone = _cmsBuildKToneCurve(ContextID,
         4096,
-        nProfiles,
+                                    preservationProfilesCount,
         ICCIntents,
         hProfiles,
         BPC,
@@ -789,6 +808,19 @@
     if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0))
         goto Error;
 
+    
+    // Insert possible devicelinks at the end
+    for (i = lastProfilePos + 1; i < nProfiles; i++)
+    {
+        cmsPipeline* devlink = _cmsReadDevicelinkLUT(hProfiles[i], ICCIntents[i]);
+        if (devlink == NULL)
+            goto Error;
+
+        if (!cmsPipelineCat(Result, devlink))
+            goto Error;
+    }
+
+
     // Get rid of xform and tone curve
     cmsPipelineFree(bp.cmyk2cmyk);
     cmsFreeToneCurve(bp.KTone);
@@ -907,6 +939,8 @@
     return TRUE;
 }
 
+
+
 // This is the entry for black-plane preserving, which are non-ICC
 static
 cmsPipeline* BlackPreservingKPlaneIntents(cmsContext     ContextID,
@@ -918,10 +952,14 @@
                                           cmsUInt32Number dwFlags)
 {
     PreserveKPlaneParams bp;
+
     cmsPipeline*    Result = NULL;
     cmsUInt32Number ICCIntents[256];
     cmsStage*         CLUT;
     cmsUInt32Number i, nGridPoints;
+    cmsUInt32Number lastProfilePos;
+    cmsUInt32Number preservationProfilesCount;
+    cmsHPROFILE hLastProfile;
     cmsHPROFILE hLab;
 
     // Sanity check
@@ -931,32 +969,45 @@
     for (i=0; i < nProfiles; i++)
         ICCIntents[i] = TranslateNonICCIntents(TheIntents[i]);
 
+    // Trim all CMYK devicelinks at the end  
+    lastProfilePos = nProfiles - 1;
+    hLastProfile = hProfiles[lastProfilePos];
+
+    while (lastProfilePos > 1)
+    {   
+        hLastProfile = hProfiles[--lastProfilePos];
+        if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
+            cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
+            break;        
+    } 
+
+    preservationProfilesCount = lastProfilePos + 1;
+
     // Check for non-cmyk profiles
     if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData ||
-        !(cmsGetColorSpace(hProfiles[nProfiles-1]) == cmsSigCmykData ||
-        cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigOutputClass))
+        !(cmsGetColorSpace(hLastProfile) == cmsSigCmykData ||
+        cmsGetDeviceClass(hLastProfile) == cmsSigOutputClass))
            return  DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags);
 
     // Allocate an empty LUT for holding the result
     Result = cmsPipelineAlloc(ContextID, 4, 4);
     if (Result == NULL) return NULL;
 
-
     memset(&bp, 0, sizeof(bp));
 
     // We need the input LUT of the last profile, assuming this one is responsible of
     // black generation. This LUT will be searched in inverse order.
-    bp.LabK2cmyk = _cmsReadInputLUT(hProfiles[nProfiles-1], INTENT_RELATIVE_COLORIMETRIC);
+    bp.LabK2cmyk = _cmsReadInputLUT(hLastProfile, INTENT_RELATIVE_COLORIMETRIC);
     if (bp.LabK2cmyk == NULL) goto Cleanup;
 
     // Get total area coverage (in 0..1 domain)
-    bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0;
+    bp.MaxTAC = cmsDetectTAC(hLastProfile) / 100.0;
     if (bp.MaxTAC <= 0) goto Cleanup;
 
 
     // Create a LUT holding normal ICC transform
     bp.cmyk2cmyk = DefaultICCintents(ContextID,
-                                         nProfiles,
+                                         preservationProfilesCount,
                                          ICCIntents,
                                          hProfiles,
                                          BPC,
@@ -965,7 +1016,7 @@
     if (bp.cmyk2cmyk == NULL) goto Cleanup;
 
     // Now the tone curve
-    bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles,
+    bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, preservationProfilesCount,
                                    ICCIntents,
                                    hProfiles,
                                    BPC,
@@ -975,14 +1026,14 @@
 
     // To measure the output, Last profile to Lab
     hLab = cmsCreateLab4ProfileTHR(ContextID, NULL);
-    bp.hProofOutput = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1],
+    bp.hProofOutput = cmsCreateTransformTHR(ContextID, hLastProfile,
                                          CHANNELS_SH(4)|BYTES_SH(2), hLab, TYPE_Lab_DBL,
                                          INTENT_RELATIVE_COLORIMETRIC,
                                          cmsFLAGS_NOCACHE|cmsFLAGS_NOOPTIMIZE);
     if ( bp.hProofOutput == NULL) goto Cleanup;
 
     // Same as anterior, but lab in the 0..1 range
-    bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hProfiles[nProfiles-1],
+    bp.cmyk2Lab = cmsCreateTransformTHR(ContextID, hLastProfile,
                                          FLOAT_SH(1)|CHANNELS_SH(4)|BYTES_SH(4), hLab,
                                          FLOAT_SH(1)|CHANNELS_SH(3)|BYTES_SH(4),
                                          INTENT_RELATIVE_COLORIMETRIC,
@@ -1005,6 +1056,18 @@
 
     cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0);
 
+    // Insert possible devicelinks at the end    
+    for (i = lastProfilePos + 1; i < nProfiles; i++)
+    {        
+        cmsPipeline* devlink = _cmsReadDevicelinkLUT(hProfiles[i], ICCIntents[i]);
+        if (devlink == NULL)
+            goto Cleanup;
+
+        if (!cmsPipelineCat(Result, devlink))
+            goto Cleanup;
+    }
+
+
 Cleanup:
 
     if (bp.cmyk2cmyk) cmsPipelineFree(bp.cmyk2cmyk);
@@ -1017,6 +1080,8 @@
     return Result;
 }
 
+
+
 // Link routines ------------------------------------------------------------------------------------------------------
 
 // Chain several profiles into a single LUT. It just checks the parameters and then calls the handler
diff --git a/third_party/lcms/src/cmsgamma.c b/third_party/lcms/src/cmsgamma.c
index bef57ae..08a7c22 100644
--- a/third_party/lcms/src/cmsgamma.c
+++ b/third_party/lcms/src/cmsgamma.c
@@ -59,11 +59,11 @@
 
 // The built-in list
 static const _cmsParametricCurvesCollection DefaultCurves = {
-    9,                                  // # of curve types
-    { 1, 2, 3, 4, 5, 6, 7, 8, 108 },    // Parametric curve ID
-    { 1, 3, 4, 5, 7, 4, 5, 5, 1 },      // Parameters by type
-    DefaultEvalParametricFn,            // Evaluator
-    NULL                                // Next in chain
+    10,                                      // # of curve types
+    { 1, 2, 3, 4, 5, 6, 7, 8, 108, 109 },    // Parametric curve ID
+    { 1, 3, 4, 5, 7, 4, 5, 5,   1,   1 },    // Parameters by type
+    DefaultEvalParametricFn,                 // Evaluator
+    NULL                                     // Next in chain
 };
 
 // Duplicates the zone of memory used by the plug-in in the new context
@@ -309,6 +309,32 @@
 }
 
 
+// Generates a sigmoidal function with desired steepness.
+cmsINLINE double sigmoid_base(double k, double t)
+{
+    return (1.0 / (1.0 + exp(-k * t))) - 0.5;
+}
+
+cmsINLINE double inverted_sigmoid_base(double k, double t)
+{
+    return -log((1.0 / (t + 0.5)) - 1.0) / k;
+}
+
+cmsINLINE double sigmoid_factory(double k, double t)
+{
+    double correction = 0.5 / sigmoid_base(k, 1);
+
+    return correction * sigmoid_base(k, 2.0 * t - 1.0) + 0.5;
+}
+
+cmsINLINE double inverse_sigmoid_factory(double k, double t)
+{
+    double correction = 0.5 / sigmoid_base(k, 1);
+
+    return (inverted_sigmoid_base(k, (t - 0.5) / correction) + 1.0) / 2.0;
+}
+
+
 // Parametric Fn using floating point
 static
 cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R)
@@ -640,6 +666,7 @@
        }
        break;
 
+
    // S-Shaped: (1 - (1-x)^1/g)^1/g
    case 108:
        if (fabs(Params[0]) < MATRIX_DET_TOLERANCE)
@@ -657,6 +684,15 @@
         Val = 1 - pow(1 - pow(R, Params[0]), Params[0]);
         break;
 
+    // Sigmoidals
+    case 109:
+        Val = sigmoid_factory(Params[0], R);
+        break;
+
+    case -109:
+        Val = inverse_sigmoid_factory(Params[0], R);
+        break;
+
     default:
         // Unsupported parametric curve. Should never reach here
         return 0;
@@ -957,7 +993,7 @@
     //Iterate
     for (i=0; i <  nResultingPoints; i++) {
 
-        t = (cmsFloat32Number) i / (nResultingPoints-1);
+        t = (cmsFloat32Number) i / (cmsFloat32Number)(nResultingPoints-1);
         x = cmsEvalToneCurveFloat(X,  t);
         Res[i] = cmsEvalToneCurveFloat(Yreversed, x);
     }
@@ -1171,6 +1207,7 @@
     cmsBool SuccessStatus = TRUE;
     cmsFloat32Number *w, *y, *z;
     cmsUInt32Number i, nItems, Zeros, Poles;
+    cmsBool notCheck = FALSE;
 
     if (Tab != NULL && Tab->InterpParams != NULL)
     {
@@ -1198,6 +1235,12 @@
                         w[i + 1] = 1.0;
                     }
 
+                    if (lambda < 0)
+                    {
+                        notCheck = TRUE;
+                        lambda = -lambda;
+                    }
+
                     if (smooth2(ContextID, w, y, z, (cmsFloat32Number)lambda, (int)nItems))
                     {
                         // Do some reality - checking...
@@ -1210,7 +1253,7 @@
                             if (z[i] < z[i - 1])
                             {
                                 cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic.");
-                                SuccessStatus = FALSE;
+                                SuccessStatus = notCheck;
                                 break;
                             }
                         }
@@ -1218,13 +1261,13 @@
                         if (SuccessStatus && Zeros > (nItems / 3))
                         {
                             cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros.");
-                            SuccessStatus = FALSE;
+                            SuccessStatus = notCheck;
                         }
 
                         if (SuccessStatus && Poles > (nItems / 3))
                         {
                             cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles.");
-                            SuccessStatus = FALSE;
+                            SuccessStatus = notCheck;
                         }
 
                         if (SuccessStatus) // Seems ok
diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c
index 4fc5c59..3d9a405 100644
--- a/third_party/lcms/src/cmsintrp.c
+++ b/third_party/lcms/src/cmsintrp.c
@@ -405,12 +405,13 @@
            const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
            int        OutChan, TotalOut;
            cmsS15Fixed16Number    fx, fy;
-  CMSREGISTER int        rx, ry;
-           int        x0, y0;
-  CMSREGISTER int        X0, X1, Y0, Y1;
-           int        d00, d01, d10, d11,
-                      dx0, dx1,
-                      dxy;
+           CMSREGISTER int        rx, ry;
+           int                    x0, y0;
+           CMSREGISTER int        X0, X1, Y0, Y1;
+
+           int                    d00, d01, d10, d11,
+                                  dx0, dx1,
+                                  dxy;
 
     TotalOut   = p -> nOutputs;
 
@@ -466,11 +467,12 @@
     int        x0, y0, z0,
                X0, Y0, Z0, X1, Y1, Z1;
     int        TotalOut, OutChan;
+
     cmsFloat32Number      fx, fy, fz,
-        d000, d001, d010, d011,
-        d100, d101, d110, d111,
-        dx00, dx01, dx10, dx11,
-        dxy0, dxy1, dxyz;
+                          d000, d001, d010, d011,
+                          d100, d101, d110, d111,
+                          dx00, dx01, dx10, dx11,
+                          dxy0, dxy1, dxyz;
 
     TotalOut   = p -> nOutputs;
 
@@ -536,13 +538,13 @@
            const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table;
            int        OutChan, TotalOut;
            cmsS15Fixed16Number    fx, fy, fz;
-  CMSREGISTER int        rx, ry, rz;
-           int        x0, y0, z0;
-  CMSREGISTER int        X0, X1, Y0, Y1, Z0, Z1;
-           int        d000, d001, d010, d011,
-                      d100, d101, d110, d111,
-                      dx00, dx01, dx10, dx11,
-                      dxy0, dxy1, dxyz;
+           CMSREGISTER int        rx, ry, rz;
+           int                    x0, y0, z0;
+           CMSREGISTER int        X0, X1, Y0, Y1, Z0, Z1;
+           int                    d000, d001, d010, d011,
+                                  d100, d101, d110, d111,
+                                  dx00, dx01, dx10, dx11,
+                                  dxy0, dxy1, dxyz;
 
     TotalOut   = p -> nOutputs;
 
@@ -610,8 +612,8 @@
 {
     const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
     cmsFloat32Number     px, py, pz;
-    int        x0, y0, z0,
-               X0, Y0, Z0, X1, Y1, Z1;
+    int                  x0, y0, z0,
+                         X0, Y0, Z0, X1, Y1, Z1;
     cmsFloat32Number     rx, ry, rz;
     cmsFloat32Number     c0, c1=0, c2=0, c3=0;
     int                  OutChan, TotalOut;
@@ -701,9 +703,6 @@
 
 #undef DENS
 
-
-
-
 static CMS_NO_SANITIZE
 void TetrahedralInterp16(CMSREGISTER const cmsUInt16Number Input[],
                          CMSREGISTER cmsUInt16Number Output[],
@@ -714,7 +713,7 @@
     cmsS15Fixed16Number rx, ry, rz;
     int x0, y0, z0;
     cmsS15Fixed16Number c0, c1, c2, c3, Rest;
-    cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
+    cmsUInt32Number X0, X1, Y0, Y1, Z0, Z1;
     cmsUInt32Number TotalOut = p -> nOutputs;
 
     fx = _cmsToFixedDomain((int) Input[0] * p -> Domain[0]);
@@ -737,8 +736,8 @@
 
     Z0 = p -> opta[0] * z0;
     Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]);
-
-    LutTable = &LutTable[X0+Y0+Z0];
+    
+    LutTable += X0+Y0+Z0;
 
     // Output should be computed as x = ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest))
     // which expands as: x = (Rest + ((Rest+0x7fff)/0xFFFF) + 0x8000)>>16
@@ -1022,8 +1021,6 @@
 
 // For more that 3 inputs (i.e., CMYK)
 // evaluate two 3-dimensional interpolations and then linearly interpolate between them.
-
-
 static
 void Eval4InputsFloat(const cmsFloat32Number Input[],
                       cmsFloat32Number Output[],
@@ -1066,351 +1063,102 @@
        }
 }
 
-
-static CMS_NO_SANITIZE
-void Eval5Inputs(CMSREGISTER const cmsUInt16Number Input[],
-                 CMSREGISTER cmsUInt16Number Output[],
-
-                 CMSREGISTER const cmsInterpParams* p16)
-{
-       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
-       cmsS15Fixed16Number fk;
-       cmsS15Fixed16Number k0, rk;
-       int K0, K1;
-       const cmsUInt16Number* T;
-       cmsUInt32Number i;
-       cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-
-       fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta[4] * k0;
-       K1 = p16 -> opta[4] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
-
-       p1 = *p16;
-       memmove(&p1.Domain[0], &p16 ->Domain[1], 4*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval4Inputs(Input + 1, Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-
-       Eval4Inputs(Input + 1, Tmp2, &p1);
-
-       for (i=0; i < p16 -> nOutputs; i++) {
-
-              Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
-       }
-
+#define EVAL_FNS(N,NM) static CMS_NO_SANITIZE \
+void Eval##N##Inputs(CMSREGISTER const cmsUInt16Number Input[], CMSREGISTER cmsUInt16Number Output[], CMSREGISTER const cmsInterpParams* p16)\
+{\
+       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;\
+       cmsS15Fixed16Number fk;\
+       cmsS15Fixed16Number k0, rk;\
+       int K0, K1;\
+       const cmsUInt16Number* T;\
+       cmsUInt32Number i;\
+       cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\
+       cmsInterpParams p1;\
+\
+       fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);\
+       k0 = FIXED_TO_INT(fk);\
+       rk = FIXED_REST_TO_INT(fk);\
+\
+       K0 = p16 -> opta[NM] * k0;\
+       K1 = p16 -> opta[NM] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));\
+\
+       p1 = *p16;\
+       memmove(&p1.Domain[0], &p16 ->Domain[1], NM*sizeof(cmsUInt32Number));\
+\
+       T = LutTable + K0;\
+       p1.Table = T;\
+\
+       Eval##NM##Inputs(Input + 1, Tmp1, &p1);\
+\
+       T = LutTable + K1;\
+       p1.Table = T;\
+\
+       Eval##NM##Inputs(Input + 1, Tmp2, &p1);\
+\
+       for (i=0; i < p16 -> nOutputs; i++) {\
+\
+              Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);\
+       }\
+}\
+\
+static void Eval##N##InputsFloat(const cmsFloat32Number Input[], \
+                                 cmsFloat32Number Output[],\
+                                 const cmsInterpParams * p)\
+{\
+       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;\
+       cmsFloat32Number rest;\
+       cmsFloat32Number pk;\
+       int k0, K0, K1;\
+       const cmsFloat32Number* T;\
+       cmsUInt32Number i;\
+       cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];\
+       cmsInterpParams p1;\
+\
+       pk = fclamp(Input[0]) * p->Domain[0];\
+       k0 = _cmsQuickFloor(pk);\
+       rest = pk - (cmsFloat32Number) k0;\
+\
+       K0 = p -> opta[NM] * k0;\
+       K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[NM]);\
+\
+       p1 = *p;\
+       memmove(&p1.Domain[0], &p ->Domain[1], NM*sizeof(cmsUInt32Number));\
+\
+       T = LutTable + K0;\
+       p1.Table = T;\
+\
+       Eval##NM##InputsFloat(Input + 1, Tmp1, &p1);\
+\
+       T = LutTable + K1;\
+       p1.Table = T;\
+\
+       Eval##NM##InputsFloat(Input + 1, Tmp2, &p1);\
+\
+       for (i=0; i < p -> nOutputs; i++) {\
+\
+              cmsFloat32Number y0 = Tmp1[i];\
+              cmsFloat32Number y1 = Tmp2[i];\
+\
+              Output[i] = y0 + (y1 - y0) * rest;\
+       }\
 }
 
 
-static
-void Eval5InputsFloat(const cmsFloat32Number Input[],
-                      cmsFloat32Number Output[],
-                      const cmsInterpParams* p)
-{
-       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
-       cmsFloat32Number rest;
-       cmsFloat32Number pk;
-       int k0, K0, K1;
-       const cmsFloat32Number* T;
-       cmsUInt32Number i;
-       cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-       pk = fclamp(Input[0]) * p->Domain[0];
-       k0 = _cmsQuickFloor(pk);
-       rest = pk - (cmsFloat32Number) k0;
-
-       K0 = p -> opta[4] * k0;
-       K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[4]);
-
-       p1 = *p;
-       memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval4InputsFloat(Input + 1,  Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-
-       Eval4InputsFloat(Input + 1,  Tmp2, &p1);
-
-       for (i=0; i < p -> nOutputs; i++) {
-
-              cmsFloat32Number y0 = Tmp1[i];
-              cmsFloat32Number y1 = Tmp2[i];
-
-              Output[i] = y0 + (y1 - y0) * rest;
-       }
-}
-
-
-
-static CMS_NO_SANITIZE
-void Eval6Inputs(CMSREGISTER const cmsUInt16Number Input[],
-                 CMSREGISTER cmsUInt16Number Output[],
-                 CMSREGISTER const cmsInterpParams* p16)
-{
-       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
-       cmsS15Fixed16Number fk;
-       cmsS15Fixed16Number k0, rk;
-       int K0, K1;
-       const cmsUInt16Number* T;
-       cmsUInt32Number i;
-       cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-       fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta[5] * k0;
-       K1 = p16 -> opta[5] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
-
-       p1 = *p16;
-       memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval5Inputs(Input + 1, Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-
-       Eval5Inputs(Input + 1, Tmp2, &p1);
-
-       for (i=0; i < p16 -> nOutputs; i++) {
-
-              Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
-       }
-
-}
-
-
-static
-void Eval6InputsFloat(const cmsFloat32Number Input[],
-                      cmsFloat32Number Output[],
-                      const cmsInterpParams* p)
-{
-       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
-       cmsFloat32Number rest;
-       cmsFloat32Number pk;
-       int k0, K0, K1;
-       const cmsFloat32Number* T;
-       cmsUInt32Number i;
-       cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-       pk = fclamp(Input[0]) * p->Domain[0];
-       k0 = _cmsQuickFloor(pk);
-       rest = pk - (cmsFloat32Number) k0;
-
-       K0 = p -> opta[5] * k0;
-       K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[5]);
-
-       p1 = *p;
-       memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval5InputsFloat(Input + 1,  Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-
-       Eval5InputsFloat(Input + 1,  Tmp2, &p1);
-
-       for (i=0; i < p -> nOutputs; i++) {
-
-              cmsFloat32Number y0 = Tmp1[i];
-              cmsFloat32Number y1 = Tmp2[i];
-
-              Output[i] = y0 + (y1 - y0) * rest;
-       }
-}
-
-
-static CMS_NO_SANITIZE
-void Eval7Inputs(CMSREGISTER const cmsUInt16Number Input[],
-                 CMSREGISTER cmsUInt16Number Output[],
-                 CMSREGISTER const cmsInterpParams* p16)
-{
-       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
-       cmsS15Fixed16Number fk;
-       cmsS15Fixed16Number k0, rk;
-       int K0, K1;
-       const cmsUInt16Number* T;
-       cmsUInt32Number i;
-       cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-
-       fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta[6] * k0;
-       K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
-
-       p1 = *p16;
-       memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval6Inputs(Input + 1, Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-
-       Eval6Inputs(Input + 1, Tmp2, &p1);
-
-       for (i=0; i < p16 -> nOutputs; i++) {
-              Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
-       }
-}
-
-
-static
-void Eval7InputsFloat(const cmsFloat32Number Input[],
-                      cmsFloat32Number Output[],
-                      const cmsInterpParams* p)
-{
-       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
-       cmsFloat32Number rest;
-       cmsFloat32Number pk;
-       int k0, K0, K1;
-       const cmsFloat32Number* T;
-       cmsUInt32Number i;
-       cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-       pk = fclamp(Input[0]) * p->Domain[0];
-       k0 = _cmsQuickFloor(pk);
-       rest = pk - (cmsFloat32Number) k0;
-
-       K0 = p -> opta[6] * k0;
-       K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[6]);
-
-       p1 = *p;
-       memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval6InputsFloat(Input + 1,  Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-
-       Eval6InputsFloat(Input + 1,  Tmp2, &p1);
-
-
-       for (i=0; i < p -> nOutputs; i++) {
-
-              cmsFloat32Number y0 = Tmp1[i];
-              cmsFloat32Number y1 = Tmp2[i];
-
-              Output[i] = y0 + (y1 - y0) * rest;
-
-       }
-}
-
-static CMS_NO_SANITIZE
-void Eval8Inputs(CMSREGISTER const cmsUInt16Number Input[],
-                 CMSREGISTER cmsUInt16Number Output[],
-                 CMSREGISTER const cmsInterpParams* p16)
-{
-       const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table;
-       cmsS15Fixed16Number fk;
-       cmsS15Fixed16Number k0, rk;
-       int K0, K1;
-       const cmsUInt16Number* T;
-       cmsUInt32Number i;
-       cmsUInt16Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-       fk = _cmsToFixedDomain((cmsS15Fixed16Number) Input[0] * p16 -> Domain[0]);
-       k0 = FIXED_TO_INT(fk);
-       rk = FIXED_REST_TO_INT(fk);
-
-       K0 = p16 -> opta[7] * k0;
-       K1 = p16 -> opta[7] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0));
-
-       p1 = *p16;
-       memmove(&p1.Domain[0], &p16 ->Domain[1], 7*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval7Inputs(Input + 1, Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-       Eval7Inputs(Input + 1, Tmp2, &p1);
-
-       for (i=0; i < p16 -> nOutputs; i++) {
-              Output[i] = LinearInterp(rk, Tmp1[i], Tmp2[i]);
-       }
-}
-
-
-
-static
-void Eval8InputsFloat(const cmsFloat32Number Input[],
-                      cmsFloat32Number Output[],
-                      const cmsInterpParams* p)
-{
-       const cmsFloat32Number* LutTable = (cmsFloat32Number*) p -> Table;
-       cmsFloat32Number rest;
-       cmsFloat32Number pk;
-       int k0, K0, K1;
-       const cmsFloat32Number* T;
-       cmsUInt32Number i;
-       cmsFloat32Number Tmp1[MAX_STAGE_CHANNELS], Tmp2[MAX_STAGE_CHANNELS];
-       cmsInterpParams p1;
-
-       pk = fclamp(Input[0]) * p->Domain[0];
-       k0 = _cmsQuickFloor(pk);
-       rest = pk - (cmsFloat32Number) k0;
-
-       K0 = p -> opta[7] * k0;
-       K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[7]);
-
-       p1 = *p;
-       memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number));
-
-       T = LutTable + K0;
-       p1.Table = T;
-
-       Eval7InputsFloat(Input + 1,  Tmp1, &p1);
-
-       T = LutTable + K1;
-       p1.Table = T;
-
-       Eval7InputsFloat(Input + 1,  Tmp2, &p1);
-
-
-       for (i=0; i < p -> nOutputs; i++) {
-
-              cmsFloat32Number y0 = Tmp1[i];
-              cmsFloat32Number y1 = Tmp2[i];
+/**
+* Thanks to Carles Llopis for the templating idea
+*/
+EVAL_FNS(5, 4)
+EVAL_FNS(6, 5)
+EVAL_FNS(7, 6)
+EVAL_FNS(8, 7)
+EVAL_FNS(9, 8)
+EVAL_FNS(10, 9)
+EVAL_FNS(11, 10)
+EVAL_FNS(12, 11)
+EVAL_FNS(13, 12)
+EVAL_FNS(14, 13)
+EVAL_FNS(15, 14)
 
-              Output[i] = y0 + (y1 - y0) * rest;
-       }
-}
 
 // The default factory
 static
@@ -1511,6 +1259,53 @@
                    Interpolation.Lerp16    =  Eval8Inputs;
                break;
 
+           case 9: 
+               if (IsFloat)
+                   Interpolation.LerpFloat = Eval9InputsFloat;
+               else
+                   Interpolation.Lerp16 = Eval9Inputs;
+               break;
+
+           case 10: 
+               if (IsFloat)
+                   Interpolation.LerpFloat = Eval10InputsFloat;
+               else
+                   Interpolation.Lerp16 = Eval10Inputs;
+               break;
+
+           case 11:
+               if (IsFloat)
+                   Interpolation.LerpFloat = Eval11InputsFloat;
+               else
+                   Interpolation.Lerp16 = Eval11Inputs;
+               break;
+
+           case 12: 
+               if (IsFloat)
+                   Interpolation.LerpFloat = Eval12InputsFloat;
+               else
+                   Interpolation.Lerp16 = Eval12Inputs;
+               break;
+
+           case 13: 
+               if (IsFloat)
+                   Interpolation.LerpFloat = Eval13InputsFloat;
+               else
+                   Interpolation.Lerp16 = Eval13Inputs;
+               break;
+
+           case 14: 
+               if (IsFloat)
+                   Interpolation.LerpFloat = Eval14InputsFloat;
+               else
+                   Interpolation.Lerp16 = Eval14Inputs;
+               break;
+
+           case 15: 
+               if (IsFloat)
+                   Interpolation.LerpFloat = Eval15InputsFloat;
+               else
+                   Interpolation.Lerp16 = Eval15Inputs;
                break;
 
            default:
diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c
index 475d62b..743b958 100644
--- a/third_party/lcms/src/cmsio0.c
+++ b/third_party/lcms/src/cmsio0.c
@@ -261,7 +261,7 @@
 
             _cmsFree(ContextID, fm);
             _cmsFree(ContextID, iohandler);
-            cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", size);
+            cmsSignalError(ContextID, cmsERROR_READ, "Couldn't allocate %ld bytes for profile", (long) size);
             return NULL;
         }
 
@@ -1220,25 +1220,28 @@
             // In this case a blind copy of the block data is performed
             if (FileOrig != NULL && Icc -> TagOffsets[i]) {
 
-                cmsUInt32Number TagSize   = FileOrig -> TagSizes[i];
-                cmsUInt32Number TagOffset = FileOrig -> TagOffsets[i];
-                void* Mem;
+                if (FileOrig->IOhandler != NULL)
+                {
+                    cmsUInt32Number TagSize = FileOrig->TagSizes[i];
+                    cmsUInt32Number TagOffset = FileOrig->TagOffsets[i];
+                    void* Mem;
 
-                if (!FileOrig ->IOhandler->Seek(FileOrig ->IOhandler, TagOffset)) return FALSE;
+                    if (!FileOrig->IOhandler->Seek(FileOrig->IOhandler, TagOffset)) return FALSE;
 
-                Mem = _cmsMalloc(Icc ->ContextID, TagSize);
-                if (Mem == NULL) return FALSE;
+                    Mem = _cmsMalloc(Icc->ContextID, TagSize);
+                    if (Mem == NULL) return FALSE;
 
-                if (FileOrig ->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE;
-                if (!io ->Write(io, TagSize, Mem)) return FALSE;
-                _cmsFree(Icc ->ContextID, Mem);
+                    if (FileOrig->IOhandler->Read(FileOrig->IOhandler, Mem, TagSize, 1) != 1) return FALSE;
+                    if (!io->Write(io, TagSize, Mem)) return FALSE;
+                    _cmsFree(Icc->ContextID, Mem);
 
-                Icc -> TagSizes[i] = (io ->UsedSpace - Begin);
+                    Icc->TagSizes[i] = (io->UsedSpace - Begin);
 
 
-                // Align to 32 bit boundary.
-                if (! _cmsWriteAlignment(io))
-                    return FALSE;
+                    // Align to 32 bit boundary.
+                    if (!_cmsWriteAlignment(io))
+                        return FALSE;
+                }
             }
 
             continue;
diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c
index 47f88df..04ece7f 100644
--- a/third_party/lcms/src/cmslut.c
+++ b/third_party/lcms/src/cmslut.c
@@ -1337,7 +1337,7 @@
 
 // Does evaluate the LUT on cmsFloat32Number-basis.
 static
-void _LUTevalFloat(CMSREGISTER const cmsFloat32Number In[], CMSREGISTER cmsFloat32Number Out[], const void* D)
+void _LUTevalFloat(const cmsFloat32Number In[], cmsFloat32Number Out[], const void* D)
 {
     cmsPipeline* lut = (cmsPipeline*) D;
     cmsStage *mpe;
@@ -1658,7 +1658,7 @@
 // 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,
+                                        _cmsPipelineEval16Fn Eval16,
                                         void* PrivateData,
                                         _cmsFreeUserDataFn FreePrivateDataFn,
                                         _cmsDupUserDataFn  DupPrivateDataFn)
diff --git a/third_party/lcms/src/cmsnamed.c b/third_party/lcms/src/cmsnamed.c
index 082a944..c0595dd 100644
--- a/third_party/lcms/src/cmsnamed.c
+++ b/third_party/lcms/src/cmsnamed.c
@@ -180,12 +180,16 @@
 
 // Convert from a 3-char code to a cmsUInt16Number. It is done in this way because some
 // compilers don't properly align beginning of strings
-
 static
 cmsUInt16Number strTo16(const char str[3])
 {   
-    const cmsUInt8Number* ptr8 = (const cmsUInt8Number*)str;
-    cmsUInt16Number n = (cmsUInt16Number)(((cmsUInt16Number)ptr8[0] << 8) | ptr8[1]);
+    const cmsUInt8Number* ptr8;
+    cmsUInt16Number n;
+
+    // For non-existent strings
+    if (str == NULL) return 0;
+    ptr8 = (const cmsUInt8Number*)str;
+    n = (cmsUInt16Number)(((cmsUInt16Number)ptr8[0] << 8) | ptr8[1]);
 
     return n;
 }
@@ -200,6 +204,7 @@
 }
 
 // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
+// In the case the user explicitely sets an empty string, we force a \0
 cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
 {
     cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);
@@ -210,6 +215,12 @@
 
     if (mlu == NULL) return FALSE;
 
+    // len == 0 would prevent operation, so we set a empty string pointing to zero
+    if (len == 0)
+    {
+        len = 1;
+    }
+
     WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len,  sizeof(wchar_t));
     if (WStr == NULL) return FALSE;
 
@@ -247,6 +258,9 @@
     if (WideString == NULL) return FALSE;
 
     len = (cmsUInt32Number) (mywcslen(WideString)) * sizeof(wchar_t);
+    if (len == 0)
+        len = sizeof(wchar_t);
+
     return AddMLUBlock(mlu, len, WideString, Lang, Cntry);
 }
 
diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c
index ca47254..1f1173f 100644
--- a/third_party/lcms/src/cmsopt.c
+++ b/third_party/lcms/src/cmsopt.c
@@ -412,7 +412,20 @@
 
 
     p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16));
+    if (p16->EvalCurveOut16 == NULL)
+    {
+        _cmsFree(ContextID, p16);
+        return NULL;
+    }
+
     p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* ));
+    if (p16->ParamsCurveOut16 == NULL)
+    {
+
+        _cmsFree(ContextID, p16->EvalCurveOut16);
+        _cmsFree(ContextID, p16);
+        return NULL;
+    }
 
     for (i=0; i < nOutputs; i++) {
 
@@ -439,7 +452,9 @@
 // Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for
 // almost any transform. We use floating point precision and then convert from floating point to 16 bits.
 static
-cmsInt32Number XFormSampler16(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
+cmsInt32Number XFormSampler16(CMSREGISTER const cmsUInt16Number In[], 
+                              CMSREGISTER cmsUInt16Number Out[], 
+                              CMSREGISTER void* Cargo)
 {
     cmsPipeline* Lut = (cmsPipeline*) Cargo;
     cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS];
@@ -798,7 +813,7 @@
 
     if (DataSetIn == NULL && DataSetOut == NULL) {
 
-        _cmsPipelineSetOptimizationParameters(Dest, (_cmsOPTeval16Fn) DataCLUT->Params->Interpolation.Lerp16, DataCLUT->Params, NULL, NULL);
+        _cmsPipelineSetOptimizationParameters(Dest, (_cmsPipelineEval16Fn) DataCLUT->Params->Interpolation.Lerp16, DataCLUT->Params, NULL, NULL);
     }
     else {
 
@@ -943,8 +958,8 @@
 #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan])
 static CMS_NO_SANITIZE
 void PrelinEval8(CMSREGISTER const cmsUInt16Number Input[],
-                  CMSREGISTER cmsUInt16Number Output[],
-                  CMSREGISTER const void* D)
+                 CMSREGISTER cmsUInt16Number Output[],
+                 CMSREGISTER const void* D)
 {
 
     cmsUInt8Number         r, g, b;
@@ -961,9 +976,9 @@
     g = (cmsUInt8Number) (Input[1] >> 8);
     b = (cmsUInt8Number) (Input[2] >> 8);
 
-    X0 = X1 = (cmsS15Fixed16Number) p8->X0[r];
-    Y0 = Y1 = (cmsS15Fixed16Number) p8->Y0[g];
-    Z0 = Z1 = (cmsS15Fixed16Number) p8->Z0[b];
+    X0 = (cmsS15Fixed16Number) p8->X0[r];
+    Y0 = (cmsS15Fixed16Number) p8->Y0[g];
+    Z0 = (cmsS15Fixed16Number) p8->Z0[b];
 
     rx = p8 ->rx[r];
     ry = p8 ->ry[g];
@@ -1365,8 +1380,8 @@
 
 static
 void FastEvaluateCurves8(CMSREGISTER const cmsUInt16Number In[],
-                          CMSREGISTER cmsUInt16Number Out[],
-                          CMSREGISTER const void* D)
+                         CMSREGISTER cmsUInt16Number Out[],
+                         CMSREGISTER const void* D)
 {
     Curves16Data* Data = (Curves16Data*) D;
     int x;
@@ -1927,7 +1942,7 @@
 }
 
 // The entry point for LUT optimization
-cmsBool _cmsOptimizePipeline(cmsContext ContextID,
+cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
                              cmsPipeline**    PtrLut,
                              cmsUInt32Number  Intent,
                              cmsUInt32Number* InputFormat,
diff --git a/third_party/lcms/src/cmspack.c b/third_party/lcms/src/cmspack.c
index b8a47c2..9510802 100644
--- a/third_party/lcms/src/cmspack.c
+++ b/third_party/lcms/src/cmspack.c
@@ -2807,7 +2807,7 @@
 
         if (Reverse) v = maximum - v;
 
-        wIn[index] = _cmsQuickSaturateWord(v * maximum);
+        wIn[index] = _cmsQuickSaturateWord((cmsFloat64Number) v * maximum);
     }
 
 
diff --git a/third_party/lcms/src/cmspcs.c b/third_party/lcms/src/cmspcs.c
index c60f716..9f03fc5 100644
--- a/third_party/lcms/src/cmspcs.c
+++ b/third_party/lcms/src/cmspcs.c
@@ -656,7 +656,7 @@
 
 // This function returns a number of gridpoints to be used as LUT table. It assumes same number
 // of gripdpoints in all dimensions. Flags may override the choice.
-cmsUInt32Number _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags)
+cmsUInt32Number CMSEXPORT _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags)
 {
     cmsUInt32Number nChannels;
 
diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c
index 062d9db..2b86b64 100644
--- a/third_party/lcms/src/cmsplugin.c
+++ b/third_party/lcms/src/cmsplugin.c
@@ -498,6 +498,7 @@
     int len;
     cmsUInt8Number Buffer[2048];
     cmsBool rc;
+    cmsUInt8Number* ptr;
 
     _cmsAssert(io != NULL);
     _cmsAssert(frm != NULL);
@@ -510,6 +511,13 @@
         return FALSE;   // Truncated, which is a fatal error for us
     }
 
+    // setlocale may be active, no commas are needed in PS generator
+    // and PS generator is our only client
+    for (ptr = Buffer; *ptr; ptr++)
+    {
+        if (*ptr == ',') *ptr = '.';
+    }
+
     rc = io ->Write(io, (cmsUInt32Number) len, Buffer);
 
     va_end(args);
diff --git a/third_party/lcms/src/cmsps2.c b/third_party/lcms/src/cmsps2.c
index d101e8d..43c9f74 100644
--- a/third_party/lcms/src/cmsps2.c
+++ b/third_party/lcms/src/cmsps2.c
@@ -529,9 +529,10 @@
 // Compare gamma table
 
 static
-cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Number nEntries)
+cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Number nG1, cmsUInt32Number nG2)
 {
-    return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
+    if (nG1 != nG2) return FALSE;
+    return memcmp(g1, g2, nG1 * sizeof(cmsUInt16Number)) == 0;
 }
 
 
@@ -547,12 +548,12 @@
     {
         if (g[i] == NULL) return; // Error
 
-        if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i]->nEntries)) {
+        if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) {
 
             _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1);
         }
         else {
-            snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, i);
+            snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i);
 	    buffer[sizeof(buffer)-1] = '\0';
             Emit1Gamma(m, g[i], buffer);
         }
@@ -807,7 +808,7 @@
 
     if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
 
-        numchans = cmsStageOutputChannels(mpe);
+        numchans = (int) cmsStageOutputChannels(mpe);
         for (i = 0; i < numchans; ++i) {
             snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
             buffer[sizeof(buffer) - 1] = '\0';
diff --git a/third_party/lcms/src/cmssamp.c b/third_party/lcms/src/cmssamp.c
index f785478..6434d53 100644
--- a/third_party/lcms/src/cmssamp.c
+++ b/third_party/lcms/src/cmssamp.c
@@ -83,10 +83,10 @@
         return FALSE;
     }
 
-    // Create a formatter which has n channels and floating point
+    // Create a formatter which has n channels and no floating point
     dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2, FALSE);
 
-   // Try to get black by using black colorant
+    // Try to get black by using black colorant
     Space = cmsGetColorSpace(hInput);
 
     // This function returns darker colorant in 16 bits for several spaces
diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c
index b780436..825b11e 100644
--- a/third_party/lcms/src/cmstypes.c
+++ b/third_party/lcms/src/cmstypes.c
@@ -1866,6 +1866,7 @@
     mpe = NewLUT -> Elements;
     if (mpe ->Type == cmsSigMatrixElemType) {
 
+        if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE;
         MatMPE = (_cmsStageMatrixData*) mpe ->Data;
         mpe = mpe -> Next;
     }
@@ -1891,7 +1892,6 @@
         return FALSE;
     }
 
-
     if (clut == NULL)
         clutPoints = 0;
     else
@@ -1905,16 +1905,14 @@
 	n = NewLUT->InputChannels * NewLUT->OutputChannels;
 
     if (MatMPE != NULL) {
-
-		for (i = 0; i < n; i++)
+        
+		for (i = 0; i < 9; i++)
 		{
 			if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
 		}
     }
     else {
-
-		if (n != 9) return FALSE;
-
+		
         if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
         if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
@@ -2193,7 +2191,7 @@
     if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
 	
     if (MatMPE != NULL) {
-        
+                
 		for (i = 0; i < 9; i++)
 		{
 			if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
@@ -3000,6 +2998,9 @@
     }
 
     List = cmsAllocNamedColorList(self ->ContextID, Count, 0, "", "");
+    if (List == NULL)           
+        return NULL; 
+        
     for (i=0; i < Count; i++) {
 
         if (io ->Read(io, Name, 32, 1) != 1) goto Error;
diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c
index 5a90306..9d182e1 100644
--- a/third_party/lcms/src/cmsxform.c
+++ b/third_party/lcms/src/cmsxform.c
@@ -273,7 +273,7 @@
     strideIn = 0;
     strideOut = 0;
     memset(fIn, 0, sizeof(fIn));
-    memset(fOut, 0, sizeof(fIn));
+    memset(fOut, 0, sizeof(fOut));
 
     for (i = 0; i < LineCount; i++) {
 
@@ -447,7 +447,7 @@
     p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
     if (wOutOfGamut >= 1) {
 
-        cmsUInt16Number i;
+        cmsUInt32Number i;
         _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);        
 
         for (i=0; i < p ->Lut->OutputChannels; i++) {
@@ -774,6 +774,12 @@
      if (ToOutput)  *ToOutput  = CMMcargo ->ToOutputFloat;
 }
 
+// returns original flags
+cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo)
+{
+    _cmsAssert(CMMcargo != NULL);
+    return CMMcargo->dwOriginalFlags;
+}
 
 // Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
 // for separated transforms. If this is the case,
diff --git a/third_party/lcms/src/lcms2_internal.h b/third_party/lcms/src/lcms2_internal.h
index fe1243e..9560fc4 100644
--- a/third_party/lcms/src/lcms2_internal.h
+++ b/third_party/lcms/src/lcms2_internal.h
@@ -908,13 +908,7 @@
 
 
 // For curve set only
-cmsToneCurve**     _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
-
-
-// Pipeline Evaluator (in floating point)
-typedef void (* _cmsPipelineEvalFloatFn)(const cmsFloat32Number In[],
-                                         cmsFloat32Number Out[],
-                                         const void* Data);
+cmsToneCurve**  _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
 
 struct _cmsPipeline_struct {
 
@@ -924,7 +918,7 @@
     // Data & evaluators
     void *Data;
 
-   _cmsOPTeval16Fn         Eval16Fn;
+   _cmsPipelineEval16Fn    Eval16Fn;
    _cmsPipelineEvalFloatFn EvalFloatFn;
    _cmsFreeUserDataFn      FreeDataFn;
    _cmsDupUserDataFn       DupDataFn;
@@ -971,14 +965,14 @@
 
 CMSCHECKPOINT cmsUInt16Number  CMSEXPORT _cmsQuantizeVal(cmsFloat64Number i, cmsUInt32Number MaxSamples);
 
-cmsUInt32Number  _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags);
+CMSAPI cmsUInt32Number  CMSEXPORT _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags);
 
 cmsBool          _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
                                       cmsUInt16Number **White,
                                       cmsUInt16Number **Black,
                                       cmsUInt32Number *nOutputs);
 
-cmsBool          _cmsOptimizePipeline(cmsContext ContextID,
+CMSAPI cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
                                       cmsPipeline**    Lut,
                                       cmsUInt32Number  Intent,
                                       cmsUInt32Number* InputFormat,