Home | History | Annotate | Download | only in src
      1 //---------------------------------------------------------------------------------
      2 //
      3 //  Little Color Management System
      4 //  Copyright (c) 1998-2010 Marti Maria Saguer
      5 //
      6 // Permission is hereby granted, free of charge, to any person obtaining
      7 // a copy of this software and associated documentation files (the "Software"),
      8 // to deal in the Software without restriction, including without limitation
      9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10 // and/or sell copies of the Software, and to permit persons to whom the Software
     11 // is furnished to do so, subject to the following conditions:
     12 //
     13 // The above copyright notice and this permission notice shall be included in
     14 // all copies or substantial portions of the Software.
     15 //
     16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
     18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23 //
     24 //---------------------------------------------------------------------------------
     25 //
     26 
     27 #include "lcms2_internal.h"
     28 
     29 
     30 // ----------------------------------------------------------------------------------
     31 // Encoding & Decoding support functions
     32 // ----------------------------------------------------------------------------------
     33 
     34 //      Little-Endian to Big-Endian
     35 
     36 // Adjust a word value after being readed/ before being written from/to an ICC profile
     37 cmsUInt16Number CMSEXPORT  _cmsAdjustEndianess16(cmsUInt16Number Word)
     38 {
     39 #ifndef CMS_USE_BIG_ENDIAN
     40 
     41     cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
     42     cmsUInt8Number tmp;
     43 
     44     tmp = pByte[0];
     45     pByte[0] = pByte[1];
     46     pByte[1] = tmp;
     47 #endif
     48 
     49     return Word;
     50 }
     51 
     52 
     53 // Transports to properly encoded values - note that icc profiles does use big endian notation.
     54 
     55 // 1 2 3 4
     56 // 4 3 2 1
     57 
     58 cmsUInt32Number CMSEXPORT  _cmsAdjustEndianess32(cmsUInt32Number DWord)
     59 {
     60 #ifndef CMS_USE_BIG_ENDIAN
     61 
     62     cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
     63     cmsUInt8Number temp1;
     64     cmsUInt8Number temp2;
     65 
     66     temp1 = *pByte++;
     67     temp2 = *pByte++;
     68     *(pByte-1) = *pByte;
     69     *pByte++ = temp2;
     70     *(pByte-3) = *pByte;
     71     *pByte = temp1;
     72 #endif
     73     return DWord;
     74 }
     75 
     76 // 1 2 3 4 5 6 7 8
     77 // 8 7 6 5 4 3 2 1
     78 
     79 void CMSEXPORT  _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord)
     80 {
     81 
     82 #ifndef CMS_USE_BIG_ENDIAN
     83 
     84     cmsUInt8Number* pIn  = (cmsUInt8Number*) QWord;
     85     cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
     86 
     87     _cmsAssert(Result != NULL);
     88 
     89     pOut[7] = pIn[0];
     90     pOut[6] = pIn[1];
     91     pOut[5] = pIn[2];
     92     pOut[4] = pIn[3];
     93     pOut[3] = pIn[4];
     94     pOut[2] = pIn[5];
     95     pOut[1] = pIn[6];
     96     pOut[0] = pIn[7];
     97 
     98 #else
     99     _cmsAssert(Result != NULL);
    100 
    101 #  ifdef CMS_DONT_USE_INT64
    102     (*Result)[0] = QWord[0];
    103     (*Result)[1] = QWord[1];
    104 #  else
    105     *Result = *QWord;
    106 #  endif
    107 #endif
    108 }
    109 
    110 // Auxiliar -- read 8, 16 and 32-bit numbers
    111 cmsBool CMSEXPORT  _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
    112 {
    113     cmsUInt8Number tmp;
    114 
    115     _cmsAssert(io != NULL);
    116 
    117     if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
    118             return FALSE;
    119 
    120     if (n != NULL) *n = tmp;
    121     return TRUE;
    122 }
    123 
    124 cmsBool CMSEXPORT  _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
    125 {
    126     cmsUInt16Number tmp;
    127 
    128     _cmsAssert(io != NULL);
    129 
    130     if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
    131             return FALSE;
    132 
    133     if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
    134     return TRUE;
    135 }
    136 
    137 cmsBool CMSEXPORT  _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
    138 {
    139     cmsUInt32Number i;
    140 
    141     _cmsAssert(io != NULL);
    142 
    143     for (i=0; i < n; i++) {
    144 
    145         if (Array != NULL) {
    146             if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
    147         }
    148         else {
    149             if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
    150         }
    151 
    152     }
    153     return TRUE;
    154 }
    155 
    156 cmsBool CMSEXPORT  _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
    157 {
    158     cmsUInt32Number tmp;
    159 
    160     _cmsAssert(io != NULL);
    161 
    162     if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
    163             return FALSE;
    164 
    165     if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
    166     return TRUE;
    167 }
    168 
    169 cmsBool CMSEXPORT  _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
    170 {
    171     cmsUInt32Number tmp;
    172 
    173     _cmsAssert(io != NULL);
    174 
    175     if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
    176             return FALSE;
    177 
    178     if (n != NULL) {
    179 
    180         tmp = _cmsAdjustEndianess32(tmp);
    181         *n = *(cmsFloat32Number*) &tmp;
    182         if (isnan(*n))
    183             return FALSE;
    184     }
    185 
    186     // fpclassify() required by C99
    187     return (fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL);
    188 }
    189 
    190 
    191 cmsBool CMSEXPORT   _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
    192 {
    193     cmsUInt64Number tmp;
    194 
    195     _cmsAssert(io != NULL);
    196 
    197     if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
    198             return FALSE;
    199 
    200     if (n != NULL) _cmsAdjustEndianess64(n, &tmp);
    201     return TRUE;
    202 }
    203 
    204 
    205 cmsBool CMSEXPORT  _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
    206 {
    207     cmsUInt32Number tmp;
    208 
    209     _cmsAssert(io != NULL);
    210 
    211     if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
    212             return FALSE;
    213 
    214     if (n != NULL) {
    215         *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
    216     }
    217 
    218     return TRUE;
    219 }
    220 
    221 
    222 // Jun-21-2000: Some profiles (those that comes with W2K) comes
    223 // with the media white (media black?) x 100. Add a sanity check
    224 
    225 static
    226 void NormalizeXYZ(cmsCIEXYZ* Dest)
    227 {
    228     while (Dest -> X > 2. &&
    229            Dest -> Y > 2. &&
    230            Dest -> Z > 2.) {
    231 
    232                Dest -> X /= 10.;
    233                Dest -> Y /= 10.;
    234                Dest -> Z /= 10.;
    235        }
    236 }
    237 
    238 cmsBool CMSEXPORT  _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
    239 {
    240     cmsEncodedXYZNumber xyz;
    241 
    242     _cmsAssert(io != NULL);
    243 
    244     if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
    245 
    246     if (XYZ != NULL) {
    247 
    248         XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
    249         XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
    250         XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
    251 
    252         NormalizeXYZ(XYZ);
    253     }
    254     return TRUE;
    255 }
    256 
    257 cmsBool CMSEXPORT  _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
    258 {
    259     _cmsAssert(io != NULL);
    260 
    261     if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
    262             return FALSE;
    263 
    264     return TRUE;
    265 }
    266 
    267 cmsBool CMSEXPORT  _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
    268 {
    269     cmsUInt16Number tmp;
    270 
    271     _cmsAssert(io != NULL);
    272 
    273     tmp = _cmsAdjustEndianess16(n);
    274     if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
    275             return FALSE;
    276 
    277     return TRUE;
    278 }
    279 
    280 cmsBool CMSEXPORT  _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
    281 {
    282     cmsUInt32Number i;
    283 
    284     _cmsAssert(io != NULL);
    285     _cmsAssert(Array != NULL);
    286 
    287     for (i=0; i < n; i++) {
    288         if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
    289     }
    290 
    291     return TRUE;
    292 }
    293 
    294 cmsBool CMSEXPORT  _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
    295 {
    296     cmsUInt32Number tmp;
    297 
    298     _cmsAssert(io != NULL);
    299 
    300     tmp = _cmsAdjustEndianess32(n);
    301     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
    302             return FALSE;
    303 
    304     return TRUE;
    305 }
    306 
    307 
    308 cmsBool CMSEXPORT  _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
    309 {
    310     cmsUInt32Number tmp;
    311 
    312     _cmsAssert(io != NULL);
    313 
    314     tmp = *(cmsUInt32Number*) &n;
    315     tmp = _cmsAdjustEndianess32(tmp);
    316     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
    317             return FALSE;
    318 
    319     return TRUE;
    320 }
    321 
    322 cmsBool CMSEXPORT  _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
    323 {
    324     cmsUInt64Number tmp;
    325 
    326     _cmsAssert(io != NULL);
    327 
    328     _cmsAdjustEndianess64(&tmp, n);
    329     if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
    330             return FALSE;
    331 
    332     return TRUE;
    333 }
    334 
    335 cmsBool CMSEXPORT  _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
    336 {
    337     cmsUInt32Number tmp;
    338 
    339     _cmsAssert(io != NULL);
    340 
    341     tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
    342     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
    343             return FALSE;
    344 
    345     return TRUE;
    346 }
    347 
    348 cmsBool CMSEXPORT  _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
    349 {
    350     cmsEncodedXYZNumber xyz;
    351 
    352     _cmsAssert(io != NULL);
    353     _cmsAssert(XYZ != NULL);
    354 
    355     xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
    356     xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
    357     xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
    358 
    359     return io -> Write(io,  sizeof(cmsEncodedXYZNumber), &xyz);
    360 }
    361 
    362 // from Fixed point 8.8 to double
    363 cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
    364 {
    365        cmsUInt8Number  msb, lsb;
    366 
    367        lsb = (cmsUInt8Number) (fixed8 & 0xff);
    368        msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
    369 
    370        return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
    371 }
    372 
    373 cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
    374 {
    375     cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
    376     return  (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
    377 }
    378 
    379 // from Fixed point 15.16 to double
    380 cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
    381 {
    382     cmsFloat64Number floater, sign, mid;
    383     int Whole, FracPart;
    384 
    385     sign  = (fix32 < 0 ? -1 : 1);
    386     fix32 = abs(fix32);
    387 
    388     Whole     = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
    389     FracPart  = (cmsUInt16Number)(fix32 & 0xffff);
    390 
    391     mid     = (cmsFloat64Number) FracPart / 65536.0;
    392     floater = (cmsFloat64Number) Whole + mid;
    393 
    394     return sign * floater;
    395 }
    396 
    397 // from double to Fixed point 15.16
    398 cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
    399 {
    400     return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
    401 }
    402 
    403 // Date/Time functions
    404 
    405 void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
    406 {
    407 
    408     _cmsAssert(Dest != NULL);
    409     _cmsAssert(Source != NULL);
    410 
    411     Dest->tm_sec   = _cmsAdjustEndianess16(Source->seconds);
    412     Dest->tm_min   = _cmsAdjustEndianess16(Source->minutes);
    413     Dest->tm_hour  = _cmsAdjustEndianess16(Source->hours);
    414     Dest->tm_mday  = _cmsAdjustEndianess16(Source->day);
    415     Dest->tm_mon   = _cmsAdjustEndianess16(Source->month) - 1;
    416     Dest->tm_year  = _cmsAdjustEndianess16(Source->year) - 1900;
    417     Dest->tm_wday  = -1;
    418     Dest->tm_yday  = -1;
    419     Dest->tm_isdst = 0;
    420 }
    421 
    422 void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
    423 {
    424     _cmsAssert(Dest != NULL);
    425     _cmsAssert(Source != NULL);
    426 
    427     Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
    428     Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
    429     Dest->hours   = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
    430     Dest->day     = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
    431     Dest->month   = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
    432     Dest->year    = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
    433 }
    434 
    435 // Read base and return type base
    436 cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
    437 {
    438     _cmsTagBase Base;
    439 
    440     _cmsAssert(io != NULL);
    441 
    442     if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
    443         return (cmsTagTypeSignature) 0;
    444 
    445     return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
    446 }
    447 
    448 // Setup base marker
    449 cmsBool  CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
    450 {
    451     _cmsTagBase  Base;
    452 
    453     _cmsAssert(io != NULL);
    454 
    455     Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
    456     memset(&Base.reserved, 0, sizeof(Base.reserved));
    457     return io -> Write(io, sizeof(_cmsTagBase), &Base);
    458 }
    459 
    460 cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
    461 {
    462     cmsUInt8Number  Buffer[4];
    463     cmsUInt32Number NextAligned, At;
    464     cmsUInt32Number BytesToNextAlignedPos;
    465 
    466     _cmsAssert(io != NULL);
    467 
    468     At = io -> Tell(io);
    469     NextAligned = _cmsALIGNLONG(At);
    470     BytesToNextAlignedPos = NextAligned - At;
    471     if (BytesToNextAlignedPos == 0) return TRUE;
    472     if (BytesToNextAlignedPos > 4)  return FALSE;
    473 
    474     return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
    475 }
    476 
    477 cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
    478 {
    479     cmsUInt8Number  Buffer[4];
    480     cmsUInt32Number NextAligned, At;
    481     cmsUInt32Number BytesToNextAlignedPos;
    482 
    483     _cmsAssert(io != NULL);
    484 
    485     At = io -> Tell(io);
    486     NextAligned = _cmsALIGNLONG(At);
    487     BytesToNextAlignedPos = NextAligned - At;
    488     if (BytesToNextAlignedPos == 0) return TRUE;
    489     if (BytesToNextAlignedPos > 4)  return FALSE;
    490 
    491     memset(Buffer, 0, BytesToNextAlignedPos);
    492     return io -> Write(io, BytesToNextAlignedPos, Buffer);
    493 }
    494 
    495 
    496 // To deal with text streams. 2K at most
    497 cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
    498 {
    499     va_list args;
    500     int len;
    501     cmsUInt8Number Buffer[2048];
    502     cmsBool rc;
    503 
    504     _cmsAssert(io != NULL);
    505     _cmsAssert(frm != NULL);
    506 
    507     va_start(args, frm);
    508 
    509     len = vsnprintf((char*) Buffer, 2047, frm, args);
    510     if (len < 0) return FALSE;   // Truncated, which is a fatal error for us
    511 
    512     rc = io ->Write(io, len, Buffer);
    513 
    514     va_end(args);
    515 
    516     return rc;
    517 }
    518 
    519 
    520 // Plugin memory management -------------------------------------------------------------------------------------------------
    521 
    522 // Specialized malloc for plug-ins, that is freed upon exit.
    523 void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
    524 {
    525     struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
    526 
    527     if (ctx ->MemPool == NULL) {
    528 
    529         if (ContextID == NULL) {
    530 
    531             ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
    532         }
    533         else {
    534             cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
    535             return NULL;
    536         }
    537     }
    538 
    539     return _cmsSubAlloc(ctx->MemPool, size);
    540 }
    541 
    542 
    543 // Main plug-in dispatcher
    544 cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
    545 {
    546     return cmsPluginTHR(NULL, Plug_in);
    547 }
    548 
    549 cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
    550 {
    551     cmsPluginBase* Plugin;
    552 
    553     for (Plugin = (cmsPluginBase*) Plug_in;
    554          Plugin != NULL;
    555          Plugin = Plugin -> Next) {
    556 
    557             if (Plugin -> Magic != cmsPluginMagicNumber) {
    558                 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
    559                 return FALSE;
    560             }
    561 
    562             if (Plugin ->ExpectedVersion > LCMS_VERSION) {
    563                 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
    564                     Plugin ->ExpectedVersion, LCMS_VERSION);
    565                 return FALSE;
    566             }
    567 
    568             switch (Plugin -> Type) {
    569 
    570                 case cmsPluginMemHandlerSig:
    571                     if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
    572                     break;
    573 
    574                 case cmsPluginInterpolationSig:
    575                     if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
    576                     break;
    577 
    578                 case cmsPluginTagTypeSig:
    579                     if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
    580                     break;
    581 
    582                 case cmsPluginTagSig:
    583                     if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
    584                     break;
    585 
    586                 case cmsPluginFormattersSig:
    587                     if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
    588                     break;
    589 
    590                 case cmsPluginRenderingIntentSig:
    591                     if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
    592                     break;
    593 
    594                 case cmsPluginParametricCurveSig:
    595                     if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
    596                     break;
    597 
    598                 case cmsPluginMultiProcessElementSig:
    599                     if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
    600                     break;
    601 
    602                 case cmsPluginOptimizationSig:
    603                     if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;
    604                     break;
    605 
    606                 case cmsPluginTransformSig:
    607                     if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
    608                     break;
    609 
    610                 case cmsPluginMutexSig:
    611                     if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
    612                     break;
    613 
    614                 default:
    615                     cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
    616                     return FALSE;
    617             }
    618     }
    619 
    620     // Keep a reference to the plug-in
    621     return TRUE;
    622 }
    623 
    624 
    625 // Revert all plug-ins to default
    626 void CMSEXPORT cmsUnregisterPlugins(void)
    627 {
    628     cmsUnregisterPluginsTHR(NULL);
    629 }
    630 
    631 
    632 // The Global storage for system context. This is the one and only global variable
    633 // pointers structure. All global vars are referenced here.
    634 static struct _cmsContext_struct globalContext = {
    635 
    636     NULL,                              // Not in the linked list
    637     NULL,                              // No suballocator
    638     {
    639         NULL,                          //  UserPtr,
    640         &_cmsLogErrorChunk,            //  Logger,
    641         &_cmsAlarmCodesChunk,          //  AlarmCodes,
    642         &_cmsAdaptationStateChunk,     //  AdaptationState,
    643         &_cmsMemPluginChunk,           //  MemPlugin,
    644         &_cmsInterpPluginChunk,        //  InterpPlugin,
    645         &_cmsCurvesPluginChunk,        //  CurvesPlugin,
    646         &_cmsFormattersPluginChunk,    //  FormattersPlugin,
    647         &_cmsTagTypePluginChunk,       //  TagTypePlugin,
    648         &_cmsTagPluginChunk,           //  TagPlugin,
    649         &_cmsIntentsPluginChunk,       //  IntentPlugin,
    650         &_cmsMPETypePluginChunk,       //  MPEPlugin,
    651         &_cmsOptimizationPluginChunk,  //  OptimizationPlugin,
    652         &_cmsTransformPluginChunk,     //  TransformPlugin,
    653         &_cmsMutexPluginChunk          //  MutexPlugin
    654     },
    655 
    656     { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
    657 };
    658 
    659 
    660 // The context pool (linked list head)
    661 static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
    662 static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
    663 
    664 // Internal, get associated pointer, with guessing. Never returns NULL.
    665 struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
    666 {
    667     struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
    668     struct _cmsContext_struct* ctx;
    669 
    670 
    671     // On 0, use global settings
    672     if (id == NULL)
    673         return &globalContext;
    674 
    675     // Search
    676     for (ctx = _cmsContextPoolHead;
    677          ctx != NULL;
    678          ctx = ctx ->Next) {
    679 
    680             // Found it?
    681             if (id == ctx)
    682                 return ctx; // New-style context,
    683     }
    684 
    685     return &globalContext;
    686 }
    687 
    688 
    689 // Internal: get the memory area associanted with each context client
    690 // Returns the block assigned to the specific zone.
    691 void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
    692 {
    693     struct _cmsContext_struct* ctx;
    694     void *ptr;
    695 
    696     if (mc >= MemoryClientMax) {
    697         cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client");
    698         return NULL;
    699     }
    700 
    701     ctx = _cmsGetContext(ContextID);
    702     ptr = ctx ->chunks[mc];
    703 
    704     if (ptr != NULL)
    705         return ptr;
    706 
    707     // A null ptr means no special settings for that context, and this
    708     // reverts to Context0 globals
    709     return globalContext.chunks[mc];
    710 }
    711 
    712 
    713 // This function returns the given context its default pristine state,
    714 // as no plug-ins were declared. There is no way to unregister a single
    715 // plug-in, as a single call to cmsPluginTHR() function may register
    716 // many different plug-ins simultaneously, then there is no way to
    717 // identify which plug-in to unregister.
    718 void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
    719 {
    720     _cmsRegisterMemHandlerPlugin(ContextID, NULL);
    721     _cmsRegisterInterpPlugin(ContextID, NULL);
    722     _cmsRegisterTagTypePlugin(ContextID, NULL);
    723     _cmsRegisterTagPlugin(ContextID, NULL);
    724     _cmsRegisterFormattersPlugin(ContextID, NULL);
    725     _cmsRegisterRenderingIntentPlugin(ContextID, NULL);
    726     _cmsRegisterParametricCurvesPlugin(ContextID, NULL);
    727     _cmsRegisterMultiProcessElementPlugin(ContextID, NULL);
    728     _cmsRegisterOptimizationPlugin(ContextID, NULL);
    729     _cmsRegisterTransformPlugin(ContextID, NULL);
    730     _cmsRegisterMutexPlugin(ContextID, NULL);
    731 }
    732 
    733 
    734 // Returns the memory manager plug-in, if any, from the Plug-in bundle
    735 static
    736 cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
    737 {
    738     cmsPluginBase* Plugin;
    739 
    740     for (Plugin = (cmsPluginBase*) PluginBundle;
    741         Plugin != NULL;
    742         Plugin = Plugin -> Next) {
    743 
    744             if (Plugin -> Magic == cmsPluginMagicNumber &&
    745                 Plugin -> ExpectedVersion <= LCMS_VERSION &&
    746                 Plugin -> Type == cmsPluginMemHandlerSig) {
    747 
    748                     // Found!
    749                     return (cmsPluginMemHandler*) Plugin;
    750             }
    751     }
    752 
    753     // Nope, revert to defaults
    754     return NULL;
    755 }
    756 
    757 
    758 // Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined
    759 // data that will be forwarded to plug-ins and logger.
    760 cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
    761 {
    762     struct _cmsContext_struct* ctx;
    763     struct _cmsContext_struct  fakeContext;
    764 
    765     _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
    766 
    767     fakeContext.chunks[UserPtr]     = UserData;
    768     fakeContext.chunks[MemPlugin]   = &fakeContext.DefaultMemoryManager;
    769 
    770     // Create the context structure.
    771     ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
    772     if (ctx == NULL)
    773         return NULL;     // Something very wrong happened!
    774 
    775     // Init the structure and the memory manager
    776     memset(ctx, 0, sizeof(struct _cmsContext_struct));
    777 
    778     // Keep memory manager
    779     memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
    780 
    781     // Maintain the linked list (with proper locking)
    782     _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
    783        ctx ->Next = _cmsContextPoolHead;
    784        _cmsContextPoolHead = ctx;
    785     _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
    786 
    787     ctx ->chunks[UserPtr]     = UserData;
    788     ctx ->chunks[MemPlugin]   = &ctx->DefaultMemoryManager;
    789 
    790     // Now we can allocate the pool by using default memory manager
    791     ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));  // default size about 32 pointers
    792     if (ctx ->MemPool == NULL) {
    793 
    794          cmsDeleteContext(ctx);
    795         return NULL;
    796     }
    797 
    798     _cmsAllocLogErrorChunk(ctx, NULL);
    799     _cmsAllocAlarmCodesChunk(ctx, NULL);
    800     _cmsAllocAdaptationStateChunk(ctx, NULL);
    801     _cmsAllocMemPluginChunk(ctx, NULL);
    802     _cmsAllocInterpPluginChunk(ctx, NULL);
    803     _cmsAllocCurvesPluginChunk(ctx, NULL);
    804     _cmsAllocFormattersPluginChunk(ctx, NULL);
    805     _cmsAllocTagTypePluginChunk(ctx, NULL);
    806     _cmsAllocMPETypePluginChunk(ctx, NULL);
    807     _cmsAllocTagPluginChunk(ctx, NULL);
    808     _cmsAllocIntentsPluginChunk(ctx, NULL);
    809     _cmsAllocOptimizationPluginChunk(ctx, NULL);
    810     _cmsAllocTransformPluginChunk(ctx, NULL);
    811     _cmsAllocMutexPluginChunk(ctx, NULL);
    812 
    813     // Setup the plug-ins
    814     if (!cmsPluginTHR(ctx, Plugin)) {
    815 
    816         cmsDeleteContext(ctx);
    817         return NULL;
    818     }
    819 
    820     return (cmsContext) ctx;
    821 }
    822 
    823 // Duplicates a context with all associated plug-ins.
    824 // Caller may specify an optional pointer to user-defined
    825 // data that will be forwarded to plug-ins and logger.
    826 cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
    827 {
    828     int i;
    829     struct _cmsContext_struct* ctx;
    830     const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
    831 
    832     void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
    833 
    834 
    835     ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
    836     if (ctx == NULL)
    837         return NULL;     // Something very wrong happened
    838 
    839     // Setup default memory allocators
    840     memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
    841 
    842     // Maintain the linked list
    843     _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
    844        ctx ->Next = _cmsContextPoolHead;
    845        _cmsContextPoolHead = ctx;
    846     _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
    847 
    848     ctx ->chunks[UserPtr]    = userData;
    849     ctx ->chunks[MemPlugin]  = &ctx->DefaultMemoryManager;
    850 
    851     ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
    852     if (ctx ->MemPool == NULL) {
    853 
    854          cmsDeleteContext(ctx);
    855         return NULL;
    856     }
    857 
    858     // Allocate all required chunks.
    859     _cmsAllocLogErrorChunk(ctx, src);
    860     _cmsAllocAlarmCodesChunk(ctx, src);
    861     _cmsAllocAdaptationStateChunk(ctx, src);
    862     _cmsAllocMemPluginChunk(ctx, src);
    863     _cmsAllocInterpPluginChunk(ctx, src);
    864     _cmsAllocCurvesPluginChunk(ctx, src);
    865     _cmsAllocFormattersPluginChunk(ctx, src);
    866     _cmsAllocTagTypePluginChunk(ctx, src);
    867     _cmsAllocMPETypePluginChunk(ctx, src);
    868     _cmsAllocTagPluginChunk(ctx, src);
    869     _cmsAllocIntentsPluginChunk(ctx, src);
    870     _cmsAllocOptimizationPluginChunk(ctx, src);
    871     _cmsAllocTransformPluginChunk(ctx, src);
    872     _cmsAllocMutexPluginChunk(ctx, src);
    873 
    874     // Make sure no one failed
    875     for (i=Logger; i < MemoryClientMax; i++) {
    876 
    877         if (src ->chunks[i] == NULL) {
    878             cmsDeleteContext((cmsContext) ctx);
    879             return NULL;
    880         }
    881     }
    882 
    883     return (cmsContext) ctx;
    884 }
    885 
    886 
    887 
    888 static
    889 struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
    890 {
    891     struct _cmsContext_struct* prev;
    892 
    893     // Search for previous
    894     for (prev = _cmsContextPoolHead;
    895              prev != NULL;
    896              prev = prev ->Next)
    897     {
    898         if (prev ->Next == id)
    899             return prev;
    900     }
    901 
    902     return NULL;  // List is empty or only one element!
    903 }
    904 
    905 // Frees any resources associated with the given context,
    906 // and destroys the context placeholder.
    907 // The ContextID can no longer be used in any THR operation.
    908 void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
    909 {
    910     if (ContextID != NULL) {
    911 
    912         struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
    913         struct _cmsContext_struct  fakeContext;
    914         struct _cmsContext_struct* prev;
    915 
    916         memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
    917 
    918         fakeContext.chunks[UserPtr]     = ctx ->chunks[UserPtr];
    919         fakeContext.chunks[MemPlugin]   = &fakeContext.DefaultMemoryManager;
    920 
    921         // Get rid of plugins
    922         cmsUnregisterPluginsTHR(ContextID);
    923 
    924         // Since all memory is allocated in the private pool, all what we need to do is destroy the pool
    925         if (ctx -> MemPool != NULL)
    926               _cmsSubAllocDestroy(ctx ->MemPool);
    927         ctx -> MemPool = NULL;
    928 
    929         // Maintain list
    930         _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
    931         if (_cmsContextPoolHead == ctx) {
    932 
    933             _cmsContextPoolHead = ctx->Next;
    934         }
    935         else {
    936 
    937             // Search for previous
    938             for (prev = _cmsContextPoolHead;
    939                 prev != NULL;
    940                 prev = prev ->Next)
    941             {
    942                 if (prev -> Next == ctx) {
    943                     prev -> Next = ctx ->Next;
    944                     break;
    945                 }
    946             }
    947         }
    948         _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
    949 
    950         // free the memory block itself
    951         _cmsFree(&fakeContext, ctx);
    952     }
    953 }
    954 
    955 // Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
    956 void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
    957 {
    958     return _cmsContextGetClientChunk(ContextID, UserPtr);
    959 }
    960