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