text: /*
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  // This file is available under and governed by the GNU General Public
  // License version 2 only, as published by the Free Software Foundation.
  // However, the following notice accompanied the original version of this
  // file:
  //
  
  //
  //  Little Color Management System
  //  Copyright (c) 1998-2020 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
  // is furnished to do so, subject to the following conditions:
  //
  // 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
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  //---------------------------------------------------------------------------------
  //
  
  #ifndef _lcms_internal_H
  
  // Include plug-in foundation
  #ifndef _lcms_plugin_H
  #   include "lcms2_plugin.h"
  #endif
  
  // ctype is part of C99 as per 7.1.2
  #include <ctype.h>
  
  // assert macro is part of C99 as per 7.2
  #include <assert.h>
  
  // Some needed constants
  #ifndef M_PI
  #       define M_PI        3.14159265358979323846
  #endif
  
  #ifndef M_LOG10E
  #       define M_LOG10E    0.434294481903251827651
  #endif
  
  // BorlandC 5.5, VC2003 are broken on that
  #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER < 1400)) // 1400 == VC++ 8.0
  #define sinf(x) (float)sin((float)x)
  #define sqrtf(x) (float)sqrt((float)x)
  #endif
  
  
  // Alignment of ICC file format uses 4 bytes (cmsUInt32Number)
  #define _cmsALIGNLONG(x) (((x)+(sizeof(cmsUInt32Number)-1)) & ~(sizeof(cmsUInt32Number)-1))
  
  // Alignment to memory pointer
  
  // (Ultra)SPARC with gcc requires ptr alignment of 8 bytes
  // even though sizeof(void *) is only four: for greatest flexibility
  // allow the build to specify ptr alignment.
  #ifndef CMS_PTR_ALIGNMENT
  # define CMS_PTR_ALIGNMENT sizeof(void *)
  #endif
  
  #define _cmsALIGNMEM(x)  (((x)+(CMS_PTR_ALIGNMENT - 1)) & ~(CMS_PTR_ALIGNMENT - 1))
  
  // Maximum encodeable values in floating point
  #define MAX_ENCODEABLE_XYZ  (1.0 + 32767.0/32768.0)
  #define MIN_ENCODEABLE_ab2  (-128.0)
  #define MAX_ENCODEABLE_ab2  ((65535.0/256.0) - 128.0)
  #define MIN_ENCODEABLE_ab4  (-128.0)
  #define MAX_ENCODEABLE_ab4  (127.0)
  
  // Maximum of channels for internal pipeline evaluation
  #define MAX_STAGE_CHANNELS  128
  
  // Unused parameter warning suppression
  #define cmsUNUSED_PARAMETER(x) ((void)x)
  
  // The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999).
  // unfortunately VisualC++ does not conform that
  #if defined(_MSC_VER) || defined(__BORLANDC__)
  #   define cmsINLINE __inline
  #else
  #   define cmsINLINE static inline
  #endif
  
  // Allow signed overflow, we know this is harmless in this particular context
  #if defined(__clang__)
  #   define CMS_NO_SANITIZE __attribute__((no_sanitize("signed-integer-overflow")))
  #else
  #   define CMS_NO_SANITIZE
  #endif
  
  // Other replacement functions
  #ifdef _MSC_VER
  # ifndef snprintf
  #       define snprintf  _snprintf
  # endif
  # ifndef vsnprintf
  #       define vsnprintf  _vsnprintf
  # endif
  
  /// Properly define some macros to accommodate
  /// older MSVC versions.
  # if defined(_MSC_VER) && _MSC_VER <= 1700
          #include <float.h>
          #define isnan _isnan
          #define isinf(x) (!_finite((x)))
  # endif
  
  #if !defined(_MSC_VER) && (defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L)
          #if !defined(isinf)
          #define isinf(x) (!finite((x)))
          #endif
  #endif
  
  
  #endif
  
  // A fast way to convert from/to 16 <-> 8 bits
  #define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb))
  #define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((cmsUInt32Number)(rgb) * 65281U + 8388608U) >> 24) & 0xFFU)
  
  // Code analysis is broken on asserts
  #ifdef _MSC_VER
  #    if (_MSC_VER >= 1500)
  #            define _cmsAssert(a)  { assert((a)); __analysis_assume((a)); }
  #     else
  #            define _cmsAssert(a)   assert((a))
  #     endif
  #else
  #      define _cmsAssert(a)   assert((a))
  #endif
  
  //---------------------------------------------------------------------------------
  
  // Determinant lower than that are assumed zero (used on matrix invert)
  #define MATRIX_DET_TOLERANCE    0.0001
  
  //---------------------------------------------------------------------------------
  
  // Fixed point
  #define FIXED_TO_INT(x)         ((x)>>16)
  #define FIXED_REST_TO_INT(x)    ((x)&0xFFFFU)
  #define ROUND_FIXED_TO_INT(x)   (((x)+0x8000)>>16)
  
  cmsINLINE cmsS15Fixed16Number _cmsToFixedDomain(int a)                   { return a + ((a + 0x7fff) / 0xffff); }
  cmsINLINE int                 _cmsFromFixedDomain(cmsS15Fixed16Number a) { return a - ((a + 0x7fff) >> 16); }
  
  // -----------------------------------------------------------------------------------------------------------
  
  // Fast floor conversion logic. Thanks to Sree Kotay and Stuart Nixon
  // note than this only works in the range ..-32767...+32767 because
  // mantissa is interpreted as 15.16 fixed point.
  // The union is to avoid pointer aliasing overoptimization.
  cmsINLINE int _cmsQuickFloor(cmsFloat64Number val)
  {
  #ifdef CMS_DONT_USE_FAST_FLOOR
      return (int) floor(val);
  #else
      const cmsFloat64Number _lcms_double2fixmagic = 68719476736.0 * 1.5;  // 2^36 * 1.5, (52-16=36) uses limited precision to floor
      union {
          cmsFloat64Number val;
          int halves[2];
      } temp;
  
      temp.val = val + _lcms_double2fixmagic;
  
  #ifdef CMS_USE_BIG_ENDIAN
      return temp.halves[1] >> 16;
  #else
      return temp.halves[0] >> 16;
  #endif
  #endif
  }
  
  // Fast floor restricted to 0..65535.0
  cmsINLINE cmsUInt16Number _cmsQuickFloorWord(cmsFloat64Number d)
  {
      return (cmsUInt16Number) _cmsQuickFloor(d - 32767.0) + 32767U;
  }
  
  // Floor to word, taking care of saturation
  cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
  {
      d += 0.5;
      if (d <= 0) return 0;
      if (d >= 65535.0) return 0xffff;
  
      return _cmsQuickFloorWord(d);
  }
  
  // Test bed entry points---------------------------------------------------------------
  #define CMSCHECKPOINT CMSAPI
  
  // Pthread support --------------------------------------------------------------------
  #ifndef CMS_NO_PTHREADS
  
  // This is the threading support. Unfortunately, it has to be platform-dependent because
  // windows does not support pthreads.
  #ifdef CMS_IS_WINDOWS_
  
  #define WIN32_LEAN_AND_MEAN 1
  #include <windows.h>
  
  
  // The locking scheme in LCMS requires a single 'top level' mutex
  // to work. This is actually implemented on Windows as a
  // CriticalSection, because they are lighter weight. With
  // pthreads, this is statically inited. Unfortunately, windows
  // can't officially statically init critical sections.
  //
  // We can work around this in 2 ways.
  //
  // 1) We can use a proper mutex purely to protect the init
  // of the CriticalSection. This in turns requires us to protect
  // the Mutex creation, which we can do using the snappily
  // named InterlockedCompareExchangePointer API (present on
  // windows XP and above).
  //
  // 2) In cases where we want to work on pre-Windows XP, we
  // can use an even more horrible hack described below.
  //
  // So why wouldn't we always use 2)? Because not calling
  // the init function for a critical section means it fails
  // testing with ApplicationVerifier (and presumably similar
  // tools).
  //
  // We therefore default to 1, and people who want to be able
  // to run on pre-Windows XP boxes can build with:
  //     CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
  // defined. This is automatically set for builds using
  // versions of MSVC that don't have this API available.
  //
  // From: http://locklessinc.com/articles/pthreads_on_windows/
  // The pthreads API has an initialization macro that has no correspondence to anything in
  // the windows API. By investigating the internal definition of the critical section type,
  // one may work out how to initialize one without calling InitializeCriticalSection().
  // The trick here is that InitializeCriticalSection() is not allowed to fail. It tries
  // to allocate a critical section debug object, but if no memory is available, it sets
  // the pointer to a specific value. (One would expect that value to be NULL, but it is
  // actually (void *)-1 for some reason.) Thus we can use this special value for that
  // pointer, and the critical section code will work.
  
  // The other important part of the critical section type to initialize is the number
  // of waiters. This controls whether or not the mutex is locked. Fortunately, this
  // part of the critical section is unlikely to change. Apparently, many programs
  // already test critical sections to see if they are locked using this value, so
  // Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical
  // section, even when they changed the underlying algorithm to be more scalable.
  // The final parts of the critical section object are unimportant, and can be set
  // to zero for their defaults. This yields to an initialization macro:
  
  typedef CRITICAL_SECTION _cmsMutex;
  
  #ifdef _MSC_VER
  #    if (_MSC_VER >= 1800)
  #          pragma warning(disable : 26135)
  #    endif
  #endif
  
  #ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
  // If we are building with a version of MSVC smaller
  // than 1400 (i.e. before VS2005) then we don't have
  // the InterlockedCompareExchangePointer API, so use
  // the old version.
  #    ifdef _MSC_VER
  #       if _MSC_VER < 1400
  #          define CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
  #       endif
  #    endif
  #endif
  
  #ifdef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
  #      define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG) -1,-1,0,0,0,0}
  #else
  #      define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG)NULL,-1,0,0,0,0}
  #endif
  
  cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
  {
          EnterCriticalSection(m);
          return 0;
  }
  
  cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
  {
          LeaveCriticalSection(m);
          return 0;
  }
  
  cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
  {
          InitializeCriticalSection(m);
          return 0;
  }
  
  cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
  {
          DeleteCriticalSection(m);
          return 0;
  }
  
  cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
  {
          EnterCriticalSection(m);
          return 0;
  }
  
  cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
  {
          LeaveCriticalSection(m);
          return 0;
  }
  
  #else
  
  // Rest of the wide world
  #include <pthread.h>
  
  #define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
  typedef pthread_mutex_t _cmsMutex;
  
  
  cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
  {
          return pthread_mutex_lock(m);
  }
  
  cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
  {
          return pthread_mutex_unlock(m);
  }
  
  cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
  {
          return pthread_mutex_init(m, NULL);
  }
  
  cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
  {
          return pthread_mutex_destroy(m);
  }
  
  cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
  {
          return pthread_mutex_lock(m);
  }
  
  cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
  {
          return pthread_mutex_unlock(m);
  }
  
  #endif
  #else
  
  #define CMS_MUTEX_INITIALIZER 0
  typedef int _cmsMutex;
  
  
  cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
  {
      cmsUNUSED_PARAMETER(m);
          return 0;
  }
  
  cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
  {
      cmsUNUSED_PARAMETER(m);
          return 0;
  }
  
  cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
  {
      cmsUNUSED_PARAMETER(m);
          return 0;
  }
  
  cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
  {
      cmsUNUSED_PARAMETER(m);
          return 0;
  }
  
  cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
  {
      cmsUNUSED_PARAMETER(m);
          return 0;
  }
  
  cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
  {
      cmsUNUSED_PARAMETER(m);
          return 0;
  }
  #endif
  
  // Plug-In registration ---------------------------------------------------------------
  
  // Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once.
  void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size);
  
  // Memory management
  cmsBool   _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Interpolation
  cmsBool  _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Parametric curves
  cmsBool  _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Formatters management
  cmsBool  _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Tag type management
  cmsBool  _cmsRegisterTagTypePlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Tag management
  cmsBool  _cmsRegisterTagPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Intent management
  cmsBool  _cmsRegisterRenderingIntentPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Multi Process elements
  cmsBool  _cmsRegisterMultiProcessElementPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Optimization
  cmsBool  _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Transform
  cmsBool  _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // Mutex
  cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
  
  // ---------------------------------------------------------------------------------------------------------
  
  // Suballocators.
  typedef struct _cmsSubAllocator_chunk_st {
  
      cmsUInt8Number* Block;
      cmsUInt32Number BlockSize;
      cmsUInt32Number Used;
  
      struct _cmsSubAllocator_chunk_st* next;
  
  } _cmsSubAllocator_chunk;
  
  
  typedef struct {
  
      cmsContext ContextID;
      _cmsSubAllocator_chunk* h;
  
  } _cmsSubAllocator;
  
  
  _cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial);
  void              _cmsSubAllocDestroy(_cmsSubAllocator* s);
  void*             _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size);
  void*             _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size);
  
  // ----------------------------------------------------------------------------------
  
  // The context clients.
  typedef enum {
  
      UserPtr,            // User-defined pointer
      Logger,
      AlarmCodesContext,
      AdaptationStateContext,
      MemPlugin,
      InterpPlugin,
      CurvesPlugin,
      FormattersPlugin,
      TagTypePlugin,
      TagPlugin,
      IntentPlugin,
      MPEPlugin,
      OptimizationPlugin,
      TransformPlugin,
      MutexPlugin,
  
      // Last in list
      MemoryClientMax
  
  } _cmsMemoryClient;
  
  
  // Container for memory management plug-in.
  typedef struct {
  
      _cmsMallocFnPtrType     MallocPtr;
      _cmsMalloZerocFnPtrType MallocZeroPtr;
      _cmsFreeFnPtrType       FreePtr;
      _cmsReallocFnPtrType    ReallocPtr;
      _cmsCallocFnPtrType     CallocPtr;
      _cmsDupFnPtrType        DupPtr;
  
  } _cmsMemPluginChunkType;
  
  // Copy memory management function pointers from plug-in to chunk, taking care of missing routines
  void  _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr);
  
  // Internal structure for context
  struct _cmsContext_struct {
  
      struct _cmsContext_struct* Next;  // Points to next context in the new style
      _cmsSubAllocator* MemPool;        // The memory pool that stores context data
  
      void* chunks[MemoryClientMax];    // array of pointers to client chunks. Memory itself is hold in the suballocator.
                                        // If NULL, then it reverts to global Context0
  
      _cmsMemPluginChunkType DefaultMemoryManager;  // The allocators used for creating the context itself. Cannot be overridden
  };
  
  // Returns a pointer to a valid context structure, including the global one if id is zero.
  // Verifies the magic number.
  struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID);
  
  // Returns the block assigned to the specific zone.
  void*     _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc);
  
  
  // Chunks of context memory by plug-in client -------------------------------------------------------
  
  // Those structures encapsulates all variables needed by the several context clients (mostly plug-ins)
  
  // Container for error logger -- not a plug-in
  typedef struct {
  
      cmsLogErrorHandlerFunction LogErrorHandler;  // Set to NULL for Context0 fallback
  
  } _cmsLogErrorChunkType;
  
  // The global Context0 storage for error logger
  extern  _cmsLogErrorChunkType  _cmsLogErrorChunk;
  
  // Allocate and init error logger container.
  void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx,
                              const struct _cmsContext_struct* src);
  
  // Container for alarm codes -- not a plug-in
  typedef struct {
  
      cmsUInt16Number AlarmCodes[cmsMAXCHANNELS];
  
  } _cmsAlarmCodesChunkType;
  
  // The global Context0 storage for alarm codes
  extern  _cmsAlarmCodesChunkType _cmsAlarmCodesChunk;
  
  // Allocate and init alarm codes container.
  void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
                              const struct _cmsContext_struct* src);
  
  // Container for adaptation state -- not a plug-in
  typedef struct {
  
      cmsFloat64Number  AdaptationState;
  
  } _cmsAdaptationStateChunkType;
  
  // The global Context0 storage for adaptation state
  extern  _cmsAdaptationStateChunkType    _cmsAdaptationStateChunk;
  
  // Allocate and init adaptation state container.
  void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
                                     const struct _cmsContext_struct* src);
  
  
  // The global Context0 storage for memory management
  extern  _cmsMemPluginChunkType _cmsMemPluginChunk;
  
  // Allocate and init memory management container.
  void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx,
                               const struct _cmsContext_struct* src);
  
  // Container for interpolation plug-in
  typedef struct {
  
      cmsInterpFnFactory Interpolators;
  
  } _cmsInterpPluginChunkType;
  
  // The global Context0 storage for interpolation plug-in
  extern  _cmsInterpPluginChunkType _cmsInterpPluginChunk;
  
  // Allocate and init interpolation container.
  void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx,
                                  const struct _cmsContext_struct* src);
  
  // Container for parametric curves plug-in
  typedef struct {
  
      struct _cmsParametricCurvesCollection_st* ParametricCurves;
  
  } _cmsCurvesPluginChunkType;
  
  // The global Context0 storage for tone curves plug-in
  extern  _cmsCurvesPluginChunkType _cmsCurvesPluginChunk;
  
  // Allocate and init parametric curves container.
  void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx,
                                                        const struct _cmsContext_struct* src);
  
  // Container for formatters plug-in
  typedef struct {
  
      struct _cms_formatters_factory_list* FactoryList;
  
  } _cmsFormattersPluginChunkType;
  
  // The global Context0 storage for formatters plug-in
  extern  _cmsFormattersPluginChunkType _cmsFormattersPluginChunk;
  
  // Allocate and init formatters container.
  void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
                                                         const struct _cmsContext_struct* src);
  
  // This chunk type is shared by TagType plug-in and MPE Plug-in
  typedef struct {
  
      struct _cmsTagTypeLinkedList_st* TagTypes;
  
  } _cmsTagTypePluginChunkType;
  
  
  // The global Context0 storage for tag types plug-in
  extern  _cmsTagTypePluginChunkType      _cmsTagTypePluginChunk;
  
  
  // The global Context0 storage for mult process elements plug-in
  extern  _cmsTagTypePluginChunkType      _cmsMPETypePluginChunk;
  
  // Allocate and init Tag types container.
  void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx,
                                                          const struct _cmsContext_struct* src);
  // Allocate and init MPE container.
  void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx,
                                                          const struct _cmsContext_struct* src);
  // Container for tag plug-in
  typedef struct {
  
      struct _cmsTagLinkedList_st* Tag;
  
  } _cmsTagPluginChunkType;
  
  
  // The global Context0 storage for tag plug-in
  extern  _cmsTagPluginChunkType _cmsTagPluginChunk;
  
  // Allocate and init Tag container.
  void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx,
                                                        const struct _cmsContext_struct* src);
  
  // Container for intents plug-in
  typedef struct {
  
      struct _cms_intents_list* Intents;
  
  } _cmsIntentsPluginChunkType;
  
  
  // The global Context0 storage for intents plug-in
  extern  _cmsIntentsPluginChunkType _cmsIntentsPluginChunk;
  
  // Allocate and init intents container.
  void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx,
                                                          const struct _cmsContext_struct* src);
  
  // Container for optimization plug-in
  typedef struct {
  
      struct _cmsOptimizationCollection_st* OptimizationCollection;
  
  } _cmsOptimizationPluginChunkType;
  
  
  // The global Context0 storage for optimizers plug-in
  extern  _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk;
  
  // Allocate and init optimizers container.
  void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx,
                                           const struct _cmsContext_struct* src);
  
  // Container for transform plug-in
  typedef struct {
  
      struct _cmsTransformCollection_st* TransformCollection;
  
  } _cmsTransformPluginChunkType;
  
  // The global Context0 storage for full-transform replacement plug-in
  extern  _cmsTransformPluginChunkType _cmsTransformPluginChunk;
  
  // Allocate and init transform container.
  void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
                                          const struct _cmsContext_struct* src);
  
  // Container for mutex plug-in
  typedef struct {
  
      _cmsCreateMutexFnPtrType  CreateMutexPtr;
      _cmsDestroyMutexFnPtrType DestroyMutexPtr;
      _cmsLockMutexFnPtrType    LockMutexPtr;
      _cmsUnlockMutexFnPtrType  UnlockMutexPtr;
  
  } _cmsMutexPluginChunkType;
  
  // The global Context0 storage for mutex plug-in
  extern  _cmsMutexPluginChunkType _cmsMutexPluginChunk;
  
  // Allocate and init mutex container.
  void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,
                                          const struct _cmsContext_struct* src);
  
  // ----------------------------------------------------------------------------------
  // MLU internal representation
  typedef struct {
  
      cmsUInt16Number Language;
      cmsUInt16Number Country;
  
      cmsUInt32Number StrW;       // Offset to current unicode string
      cmsUInt32Number Len;        // Length in bytes
  
  } _cmsMLUentry;
  
  struct _cms_MLU_struct {
  
      cmsContext ContextID;
  
      // The directory
      cmsUInt32Number  AllocatedEntries;
      cmsUInt32Number  UsedEntries;
      _cmsMLUentry* Entries;     // Array of pointers to strings allocated in MemPool
  
      // The Pool
      cmsUInt32Number PoolSize;  // The maximum allocated size
      cmsUInt32Number PoolUsed;  // The used size
      void*  MemPool;            // Pointer to begin of memory pool
  };
  
  // Named color list internal representation
  typedef struct {
  
      char Name[cmsMAX_PATH];
      cmsUInt16Number PCS[3];
      cmsUInt16Number DeviceColorant[cmsMAXCHANNELS];
  
  } _cmsNAMEDCOLOR;
  
  struct _cms_NAMEDCOLORLIST_struct {
  
      cmsUInt32Number nColors;
      cmsUInt32Number Allocated;
      cmsUInt32Number ColorantCount;
  
      char Prefix[33];      // Prefix and suffix are defined to be 32 characters at most
      char Suffix[33];
  
      _cmsNAMEDCOLOR* List;
  
      cmsContext ContextID;
  };
  
  
  // ----------------------------------------------------------------------------------
  
  // This is the internal struct holding profile details.
  
  // Maximum supported tags in a profile
  #define MAX_TABLE_TAG       100
  
  typedef struct _cms_iccprofile_struct {
  
      // I/O handler
      cmsIOHANDLER*            IOhandler;
  
      // The thread ID
      cmsContext               ContextID;
  
      // Creation time
      struct tm                Created;
  
      // Only most important items found in ICC profiles
      cmsUInt32Number          Version;
      cmsProfileClassSignature DeviceClass;
      cmsColorSpaceSignature   ColorSpace;
      cmsColorSpaceSignature   PCS;
      cmsUInt32Number          RenderingIntent;
  
      cmsUInt32Number          flags;
      cmsUInt32Number          manufacturer, model;
      cmsUInt64Number          attributes;
      cmsUInt32Number          creator;
  
      cmsProfileID             ProfileID;
  
      // Dictionary
      cmsUInt32Number          TagCount;
      cmsTagSignature          TagNames[MAX_TABLE_TAG];
      cmsTagSignature          TagLinked[MAX_TABLE_TAG];           // The tag to which is linked (0=none)
      cmsUInt32Number          TagSizes[MAX_TABLE_TAG];            // Size on disk
      cmsUInt32Number          TagOffsets[MAX_TABLE_TAG];
      cmsBool                  TagSaveAsRaw[MAX_TABLE_TAG];        // True to write uncooked
      void *                   TagPtrs[MAX_TABLE_TAG];
      cmsTagTypeHandler*       TagTypeHandlers[MAX_TABLE_TAG];     // Same structure may be serialized on different types
                                                                   // depending on profile version, so we keep track of the
                                                                   // type handler for each tag in the list.
      // Special
      cmsBool                  IsWrite;
  
      // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin
      void *                   UsrMutex;
  
  } _cmsICCPROFILE;
  
  // IO helpers for profiles
  cmsBool              _cmsReadHeader(_cmsICCPROFILE* Icc);
  cmsBool              _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace);
  int                  _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks);
  
  // Tag types
  cmsTagTypeHandler*   _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig);
  cmsTagTypeSignature  _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig);
  cmsTagDescriptor*    _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig);
  
  // Error logging ---------------------------------------------------------------------------------------------------------
  
  void                 _cmsTagSignature2String(char String[5], cmsTagSignature sig);
  
  // Interpolation ---------------------------------------------------------------------------------------------------------
  
  CMSCHECKPOINT cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples, cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags);
  cmsInterpParams*                         _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags);
  CMSCHECKPOINT void             CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p);
  cmsBool                                  _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p);
  
  // Curves ----------------------------------------------------------------------------------------------------------------
  
  // This struct holds information about a segment, plus a pointer to the function that implements the evaluation.
  // In the case of table-based, Eval pointer is set to NULL
  
  // The gamma function main structure
  struct _cms_curve_struct {
  
      cmsInterpParams*  InterpParams;  // Private optimizations for interpolation
  
      cmsUInt32Number   nSegments;     // Number of segments in the curve. Zero for a 16-bit based tables
      cmsCurveSegment*  Segments;      // The segments
      cmsInterpParams** SegInterp;     // Array of private optimizations for interpolation in table-based segments
  
      cmsParametricCurveEvaluator* Evals;  // Evaluators (one per segment)
  
      // 16 bit Table-based representation follows
      cmsUInt32Number    nEntries;      // Number of table elements
      cmsUInt16Number*   Table16;       // The table itself.
  };
  
  
  //  Pipelines & Stages ---------------------------------------------------------------------------------------------
  
  // A single stage
  struct _cmsStage_struct {
  
      cmsContext          ContextID;
  
      cmsStageSignature   Type;           // Identifies the stage
      cmsStageSignature   Implements;     // Identifies the *function* of the stage (for optimizations)
  
      cmsUInt32Number     InputChannels;  // Input channels -- for optimization purposes
      cmsUInt32Number     OutputChannels; // Output channels -- for optimization purposes
  
      _cmsStageEvalFn     EvalPtr;        // Points to fn that evaluates the stage (always in floating point)
      _cmsStageDupElemFn  DupElemPtr;     // Points to a fn that duplicates the *data* of the stage
      _cmsStageFreeElemFn FreePtr;        // Points to a fn that sets the *data* of the stage free
  
      // A generic pointer to whatever memory needed by the stage
      void*               Data;
  
      // Maintains linked list (used internally)
      struct _cmsStage_struct* Next;
  };
  
  
  // Special Stages (cannot be saved)
  CMSCHECKPOINT cmsStage*  CMSEXPORT _cmsStageAllocLab2XYZ(cmsContext ContextID);
  CMSCHECKPOINT cmsStage*  CMSEXPORT _cmsStageAllocXYZ2Lab(cmsContext ContextID);
  cmsStage*                          _cmsStageAllocLabPrelin(cmsContext ContextID);
  CMSCHECKPOINT cmsStage*  CMSEXPORT _cmsStageAllocLabV2ToV4(cmsContext ContextID);
  cmsStage*                          _cmsStageAllocLabV2ToV4curves(cmsContext ContextID);
  CMSCHECKPOINT cmsStage*  CMSEXPORT _cmsStageAllocLabV4ToV2(cmsContext ContextID);
  CMSCHECKPOINT cmsStage*  CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS);
  CMSCHECKPOINT cmsStage*  CMSEXPORT _cmsStageAllocIdentityCurves(cmsContext ContextID, cmsUInt32Number nChannels);
  CMSCHECKPOINT cmsStage*  CMSEXPORT _cmsStageAllocIdentityCLut(cmsContext ContextID, cmsUInt32Number nChan);
  cmsStage*                          _cmsStageNormalizeFromLabFloat(cmsContext ContextID);
  cmsStage*                          _cmsStageNormalizeFromXyzFloat(cmsContext ContextID);
  cmsStage*                          _cmsStageNormalizeToLabFloat(cmsContext ContextID);
  cmsStage*                          _cmsStageNormalizeToXyzFloat(cmsContext ContextID);
  cmsStage*                          _cmsStageClipNegatives(cmsContext ContextID, cmsUInt32Number nChannels);
  
  
  // For curve set only
  cmsToneCurve**  _cmsStageGetPtrToCurveSet(const cmsStage* mpe);
  
  struct _cmsPipeline_struct {
  
      cmsStage* Elements;                                // Points to elements chain
      cmsUInt32Number InputChannels, OutputChannels;
  
      // Data & evaluators
      void *Data;
  
     _cmsPipelineEval16Fn    Eval16Fn;
     _cmsPipelineEvalFloatFn EvalFloatFn;
     _cmsFreeUserDataFn      FreeDataFn;
     _cmsDupUserDataFn       DupDataFn;
  
      cmsContext ContextID;            // Environment
  
      cmsBool  SaveAs8Bits;            // Implementation-specific: save as 8 bits if possible
  };
  
  // LUT reading & creation -------------------------------------------------------------------------------------------
  
  // Read tags using low-level function, provide necessary glue code to adapt versions, etc. All those return a brand new copy
  // of the LUTS, since ownership of original is up to the profile. The user should free allocated resources.
  
  CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadInputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent);
  CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent);
  CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent);
  
  // Special values
  cmsBool           _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile);
  cmsBool           _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile);
  
  // Profile linker --------------------------------------------------------------------------------------------------
  
  // Link several profiles to obtain a single LUT modelling the whole color transform. Intents, Black point
  // compensation and Adaptation parameters may vary across profiles. BPC and Adaptation refers to the PCS
  // after the profile. I.e, BPC[0] refers to connexion between profile(0) and profile(1)
  cmsPipeline* _cmsLinkProfiles(cmsContext         ContextID,
                                cmsUInt32Number    nProfiles,
                                cmsUInt32Number    TheIntents[],
                                cmsHPROFILE        hProfiles[],
                                cmsBool            BPC[],
                                cmsFloat64Number   AdaptationStates[],
                                cmsUInt32Number    dwFlags);
  
  // Sequence --------------------------------------------------------------------------------------------------------
  
  cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile);
  cmsBool _cmsWriteProfileSequence(cmsHPROFILE hProfile, const cmsSEQ* seq);
  cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[]);
  
  
  // LUT optimization ------------------------------------------------------------------------------------------------
  
  CMSCHECKPOINT cmsUInt16Number  CMSEXPORT _cmsQuantizeVal(cmsFloat64Number i, cmsUInt32Number MaxSamples);
  
  CMSAPI cmsUInt32Number  CMSEXPORT _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags);
  
  cmsBool          _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
                                        cmsUInt16Number **White,
                                        cmsUInt16Number **Black,
                                        cmsUInt32Number *nOutputs);
  
  CMSAPI cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
                                        cmsPipeline**    Lut,
                                        cmsUInt32Number  Intent,
                                        cmsUInt32Number* InputFormat,
                                        cmsUInt32Number* OutputFormat,
                                        cmsUInt32Number* dwFlags );
  
  
  // Hi level LUT building ----------------------------------------------------------------------------------------------
  
  cmsPipeline*     _cmsCreateGamutCheckPipeline(cmsContext ContextID,
                                                cmsHPROFILE hProfiles[],
                                                cmsBool  BPC[],
                                                cmsUInt32Number Intents[],
                                                cmsFloat64Number AdaptationStates[],
                                                cmsUInt32Number nGamutPCSposition,
                                                cmsHPROFILE hGamut);
  
  
  // Formatters ------------------------------------------------------------------------------------------------------------
  
  #define cmsFLAGS_CAN_CHANGE_FORMATTER     0x02000000   // Allow change buffer format
  
  cmsBool         _cmsFormatterIsFloat(cmsUInt32Number Type);
  cmsBool         _cmsFormatterIs8bit(cmsUInt32Number Type);
  
  CMSCHECKPOINT cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID,
                                                        cmsUInt32Number Type,          // Specific type, i.e. TYPE_RGB_8
                                                        cmsFormatterDirection Dir,
                                                        cmsUInt32Number dwFlags);
  
  
  #ifndef CMS_NO_HALF_SUPPORT
  
  // Half float
  CMSCHECKPOINT cmsFloat32Number CMSEXPORT _cmsHalf2Float(cmsUInt16Number h);
  CMSCHECKPOINT cmsUInt16Number  CMSEXPORT _cmsFloat2Half(cmsFloat32Number flt);
  
  #endif
  
  // Transform logic ------------------------------------------------------------------------------------------------------
  
  struct _cmstransform_struct;
  
  typedef struct {
  
      // 1-pixel cache (16 bits only)
      cmsUInt16Number CacheIn[cmsMAXCHANNELS];
      cmsUInt16Number CacheOut[cmsMAXCHANNELS];
  
  } _cmsCACHE;
  
  
  
  // Transformation
  typedef struct _cmstransform_struct {
  
      cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference
  
      // Points to transform code
      _cmsTransform2Fn xform;
  
      // Formatters, cannot be embedded into LUT because cache
      cmsFormatter16 FromInput;
      cmsFormatter16 ToOutput;
  
      cmsFormatterFloat FromInputFloat;
      cmsFormatterFloat ToOutputFloat;
  
      // 1-pixel cache seed for zero as input (16 bits, read only)
      _cmsCACHE Cache;
  
      // A Pipeline holding the full (optimized) transform
      cmsPipeline* Lut;
  
      // A Pipeline holding the gamut check. It goes from the input space to bilevel
      cmsPipeline* GamutCheck;
  
      // Colorant tables
      cmsNAMEDCOLORLIST* InputColorant;       // Input Colorant table
      cmsNAMEDCOLORLIST* OutputColorant;      // Colorant table (for n chans > CMYK)
  
      // Informational only
      cmsColorSpaceSignature EntryColorSpace;
      cmsColorSpaceSignature ExitColorSpace;
  
      // White points (informative only)
      cmsCIEXYZ EntryWhitePoint;
      cmsCIEXYZ ExitWhitePoint;
  
      // Profiles used to create the transform
      cmsSEQ* Sequence;
  
      cmsUInt32Number  dwOriginalFlags;
      cmsFloat64Number AdaptationState;
  
      // The intent of this transform. That is usually the last intent in the profilechain, but may differ
      cmsUInt32Number RenderingIntent;
  
      // An id that uniquely identifies the running context. May be null.
      cmsContext ContextID;
  
      // A user-defined pointer that can be used to store data for transform plug-ins
      void* UserData;
      _cmsFreeUserDataFn FreeUserData;
  
      // A way to provide backwards compatibility with full xform plugins
      _cmsTransformFn OldXform;
  
  } _cmsTRANSFORM;
  
  // Copies extra channels from input to output if the original flags in the transform structure
  // instructs to do so. This function is called on all standard transform functions.
  void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
                               void* out,
                               cmsUInt32Number PixelsPerLine,
                               cmsUInt32Number LineCount,
                               const cmsStride* Stride);
  
  // -----------------------------------------------------------------------------------------------------------------------
  
  cmsHTRANSFORM _cmsChain2Lab(cmsContext             ContextID,
                              cmsUInt32Number        nProfiles,
                              cmsUInt32Number        InputFormat,
                              cmsUInt32Number        OutputFormat,
                              const cmsUInt32Number  Intents[],
                              const cmsHPROFILE      hProfiles[],
                              const cmsBool          BPC[],
                              const cmsFloat64Number AdaptationStates[],
                              cmsUInt32Number        dwFlags);
  
  
  cmsToneCurve* _cmsBuildKToneCurve(cmsContext       ContextID,
                              cmsUInt32Number        nPoints,
                              cmsUInt32Number        nProfiles,
                              const cmsUInt32Number  Intents[],
                              const cmsHPROFILE      hProfiles[],
                              const cmsBool          BPC[],
                              const cmsFloat64Number AdaptationStates[],
                              cmsUInt32Number        dwFlags);
  
  cmsBool   _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsCIEXYZ* FromIll, const cmsCIEXYZ* ToIll);
  
  cmsBool   _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries);
  
  
  #define _lcms_internal_H
  #endif
  