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-2010 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 readed/ 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 // Auxiliar -- 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(cmsFloat32Number), 1) != 1)
 205             return FALSE;
 206 
 207     if (n != NULL) {
 208 
 209         tmp = _cmsAdjustEndianess32(tmp);
 210         *n = *(cmsFloat32Number*) &tmp;
 211     }
 212     return TRUE;
 213 }
 214 
 215 
 216 cmsBool CMSEXPORT   _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
 217 {
 218     cmsUInt64Number tmp;
 219 
 220     _cmsAssert(io != NULL);
 221 
 222     if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
 223             return FALSE;
 224 
 225     if (n != NULL) _cmsAdjustEndianess64(n, &tmp);
 226     return TRUE;
 227 }
 228 
 229 
 230 cmsBool CMSEXPORT  _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
 231 {
 232     cmsUInt32Number tmp;
 233 
 234     _cmsAssert(io != NULL);
 235 
 236     if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
 237             return FALSE;
 238 
 239     if (n != NULL) {
 240         *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
 241     }
 242 
 243     return TRUE;
 244 }
 245 
 246 
 247 // Jun-21-2000: Some profiles (those that comes with W2K) comes
 248 // with the media white (media black?) x 100. Add a sanity check
 249 
 250 static
 251 void NormalizeXYZ(cmsCIEXYZ* Dest)
 252 {
 253     while (Dest -> X > 2. &&
 254            Dest -> Y > 2. &&
 255            Dest -> Z > 2.) {
 256 
 257                Dest -> X /= 10.;
 258                Dest -> Y /= 10.;
 259                Dest -> Z /= 10.;
 260        }
 261 }
 262 
 263 cmsBool CMSEXPORT  _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
 264 {
 265     cmsEncodedXYZNumber xyz;
 266 
 267     _cmsAssert(io != NULL);
 268 
 269     if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
 270 
 271     if (XYZ != NULL) {
 272 
 273         XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
 274         XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
 275         XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
 276 
 277         NormalizeXYZ(XYZ);
 278     }
 279     return TRUE;
 280 }
 281 
 282 cmsBool CMSEXPORT  _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
 283 {
 284     _cmsAssert(io != NULL);
 285 
 286     if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
 287             return FALSE;
 288 
 289     return TRUE;
 290 }
 291 
 292 cmsBool CMSEXPORT  _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
 293 {
 294     cmsUInt16Number tmp;
 295 
 296     _cmsAssert(io != NULL);
 297 
 298     tmp = _cmsAdjustEndianess16(n);
 299     if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
 300             return FALSE;
 301 
 302     return TRUE;
 303 }
 304 
 305 cmsBool CMSEXPORT  _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
 306 {
 307     cmsUInt32Number i;
 308 
 309     _cmsAssert(io != NULL);
 310     _cmsAssert(Array != NULL);
 311 
 312     for (i=0; i < n; i++) {
 313         if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
 314     }
 315 
 316     return TRUE;
 317 }
 318 
 319 cmsBool CMSEXPORT  _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
 320 {
 321     cmsUInt32Number tmp;
 322 
 323     _cmsAssert(io != NULL);
 324 
 325     tmp = _cmsAdjustEndianess32(n);
 326     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
 327             return FALSE;
 328 
 329     return TRUE;
 330 }
 331 
 332 
 333 cmsBool CMSEXPORT  _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
 334 {
 335     cmsUInt32Number tmp;
 336 
 337     _cmsAssert(io != NULL);
 338 
 339     tmp = *(cmsUInt32Number*) &n;
 340     tmp = _cmsAdjustEndianess32(tmp);
 341     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
 342             return FALSE;
 343 
 344     return TRUE;
 345 }
 346 
 347 cmsBool CMSEXPORT  _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
 348 {
 349     cmsUInt64Number tmp;
 350 
 351     _cmsAssert(io != NULL);
 352 
 353     _cmsAdjustEndianess64(&tmp, n);
 354     if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
 355             return FALSE;
 356 
 357     return TRUE;
 358 }
 359 
 360 cmsBool CMSEXPORT  _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
 361 {
 362     cmsUInt32Number tmp;
 363 
 364     _cmsAssert(io != NULL);
 365 
 366     tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
 367     if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
 368             return FALSE;
 369 
 370     return TRUE;
 371 }
 372 
 373 cmsBool CMSEXPORT  _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
 374 {
 375     cmsEncodedXYZNumber xyz;
 376 
 377     _cmsAssert(io != NULL);
 378     _cmsAssert(XYZ != NULL);
 379 
 380     xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
 381     xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
 382     xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
 383 
 384     return io -> Write(io,  sizeof(cmsEncodedXYZNumber), &xyz);
 385 }
 386 
 387 // from Fixed point 8.8 to double
 388 cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
 389 {
 390        cmsUInt8Number  msb, lsb;
 391 
 392        lsb = (cmsUInt8Number) (fixed8 & 0xff);
 393        msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
 394 
 395        return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
 396 }
 397 
 398 cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
 399 {
 400     cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
 401     return  (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
 402 }
 403 
 404 // from Fixed point 15.16 to double
 405 cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
 406 {
 407     cmsFloat64Number floater, sign, mid;
 408     int Whole, FracPart;
 409 
 410     sign  = (fix32 < 0 ? -1 : 1);
 411     fix32 = abs(fix32);
 412 
 413     Whole     = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
 414     FracPart  = (cmsUInt16Number)(fix32 & 0xffff);
 415 
 416     mid     = (cmsFloat64Number) FracPart / 65536.0;
 417     floater = (cmsFloat64Number) Whole + mid;
 418 
 419     return sign * floater;
 420 }
 421 
 422 // from double to Fixed point 15.16
 423 cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
 424 {
 425     return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
 426 }
 427 
 428 // Date/Time functions
 429 
 430 void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
 431 {
 432 
 433     _cmsAssert(Dest != NULL);
 434     _cmsAssert(Source != NULL);
 435 
 436     Dest->tm_sec   = _cmsAdjustEndianess16(Source->seconds);
 437     Dest->tm_min   = _cmsAdjustEndianess16(Source->minutes);
 438     Dest->tm_hour  = _cmsAdjustEndianess16(Source->hours);
 439     Dest->tm_mday  = _cmsAdjustEndianess16(Source->day);
 440     Dest->tm_mon   = _cmsAdjustEndianess16(Source->month) - 1;
 441     Dest->tm_year  = _cmsAdjustEndianess16(Source->year) - 1900;
 442     Dest->tm_wday  = -1;
 443     Dest->tm_yday  = -1;
 444     Dest->tm_isdst = 0;
 445 }
 446 
 447 void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
 448 {
 449     _cmsAssert(Dest != NULL);
 450     _cmsAssert(Source != NULL);
 451 
 452     Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec);
 453     Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min);
 454     Dest->hours   = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour);
 455     Dest->day     = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday);
 456     Dest->month   = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1));
 457     Dest->year    = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900));
 458 }
 459 
 460 // Read base and return type base
 461 cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
 462 {
 463     _cmsTagBase Base;
 464 
 465     _cmsAssert(io != NULL);
 466 
 467     if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
 468         return (cmsTagTypeSignature) 0;
 469 
 470     return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
 471 }
 472 
 473 // Setup base marker
 474 cmsBool  CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
 475 {
 476     _cmsTagBase  Base;
 477 
 478     _cmsAssert(io != NULL);
 479 
 480     Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
 481     memset(&Base.reserved, 0, sizeof(Base.reserved));
 482     return io -> Write(io, sizeof(_cmsTagBase), &Base);
 483 }
 484 
 485 cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
 486 {
 487     cmsUInt8Number  Buffer[4];
 488     cmsUInt32Number NextAligned, At;
 489     cmsUInt32Number BytesToNextAlignedPos;
 490 
 491     _cmsAssert(io != NULL);
 492 
 493     At = io -> Tell(io);
 494     NextAligned = _cmsALIGNLONG(At);
 495     BytesToNextAlignedPos = NextAligned - At;
 496     if (BytesToNextAlignedPos == 0) return TRUE;
 497     if (BytesToNextAlignedPos > 4)  return FALSE;
 498 
 499     return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
 500 }
 501 
 502 cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
 503 {
 504     cmsUInt8Number  Buffer[4];
 505     cmsUInt32Number NextAligned, At;
 506     cmsUInt32Number BytesToNextAlignedPos;
 507 
 508     _cmsAssert(io != NULL);
 509 
 510     At = io -> Tell(io);
 511     NextAligned = _cmsALIGNLONG(At);
 512     BytesToNextAlignedPos = NextAligned - At;
 513     if (BytesToNextAlignedPos == 0) return TRUE;
 514     if (BytesToNextAlignedPos > 4)  return FALSE;
 515 
 516     memset(Buffer, 0, BytesToNextAlignedPos);
 517     return io -> Write(io, BytesToNextAlignedPos, Buffer);
 518 }
 519 
 520 
 521 // To deal with text streams. 2K at most
 522 cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
 523 {
 524     va_list args;
 525     int len;
 526     cmsUInt8Number Buffer[2048];
 527     cmsBool rc;
 528 
 529     _cmsAssert(io != NULL);
 530     _cmsAssert(frm != NULL);
 531 
 532     va_start(args, frm);
 533 
 534     len = vsnprintf((char*) Buffer, 2047, frm, args);
 535     if (len < 0) return FALSE;   // Truncated, which is a fatal error for us
 536 
 537     rc = io ->Write(io, len, Buffer);
 538 
 539     va_end(args);
 540 
 541     return rc;
 542 }
 543 
 544 
 545 // Plugin memory management -------------------------------------------------------------------------------------------------
 546 
 547 // Specialized malloc for plug-ins, that is freed upon exit.
 548 void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
 549 {
 550     struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
 551 
 552     if (ctx ->MemPool == NULL) {
 553 
 554         if (ContextID == NULL) {
 555 
 556             ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
 557         }
 558         else {
 559             cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
 560             return NULL;
 561         }
 562     }
 563 
 564     return _cmsSubAlloc(ctx->MemPool, size);
 565 }
 566 
 567 
 568 // Main plug-in dispatcher
 569 cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
 570 {
 571     return cmsPluginTHR(NULL, Plug_in);
 572 }
 573 
 574 cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
 575 {
 576     cmsPluginBase* Plugin;
 577 
 578     for (Plugin = (cmsPluginBase*) Plug_in;
 579          Plugin != NULL;
 580          Plugin = Plugin -> Next) {
 581 
 582             if (Plugin -> Magic != cmsPluginMagicNumber) {
 583                 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
 584                 return FALSE;
 585             }
 586 
 587             if (Plugin ->ExpectedVersion > LCMS_VERSION) {
 588                 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
 589                     Plugin ->ExpectedVersion, LCMS_VERSION);
 590                 return FALSE;
 591             }
 592 
 593             switch (Plugin -> Type) {
 594 
 595                 case cmsPluginMemHandlerSig:
 596                     if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
 597                     break;
 598 
 599                 case cmsPluginInterpolationSig:
 600                     if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
 601                     break;
 602 
 603                 case cmsPluginTagTypeSig:
 604                     if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
 605                     break;
 606 
 607                 case cmsPluginTagSig:
 608                     if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
 609                     break;
 610 
 611                 case cmsPluginFormattersSig:
 612                     if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
 613                     break;
 614 
 615                 case cmsPluginRenderingIntentSig:
 616                     if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
 617                     break;
 618 
 619                 case cmsPluginParametricCurveSig:
 620                     if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
 621                     break;
 622 
 623                 case cmsPluginMultiProcessElementSig:
 624                     if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
 625                     break;
 626 
 627                 case cmsPluginOptimizationSig:
 628                     if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;
 629                     break;
 630 
 631                 case cmsPluginTransformSig:
 632                     if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
 633                     break;
 634 
 635                 case cmsPluginMutexSig:
 636                     if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
 637                     break;
 638 
 639                 default:
 640                     cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
 641                     return FALSE;
 642             }
 643     }
 644 
 645     // Keep a reference to the plug-in
 646     return TRUE;
 647 }
 648 
 649 
 650 // Revert all plug-ins to default
 651 void CMSEXPORT cmsUnregisterPlugins(void)
 652 {
 653     cmsUnregisterPluginsTHR(NULL);
 654 }
 655 
 656 
 657 // The Global storage for system context. This is the one and only global variable
 658 // pointers structure. All global vars are referenced here.
 659 static struct _cmsContext_struct globalContext = {
 660 
 661     NULL,                              // Not in the linked list
 662     NULL,                              // No suballocator
 663     {
 664         NULL,                          //  UserPtr,
 665         &_cmsLogErrorChunk,            //  Logger,
 666         &_cmsAlarmCodesChunk,          //  AlarmCodes,
 667         &_cmsAdaptationStateChunk,     //  AdaptationState,
 668         &_cmsMemPluginChunk,           //  MemPlugin,
 669         &_cmsInterpPluginChunk,        //  InterpPlugin,
 670         &_cmsCurvesPluginChunk,        //  CurvesPlugin,
 671         &_cmsFormattersPluginChunk,    //  FormattersPlugin,
 672         &_cmsTagTypePluginChunk,       //  TagTypePlugin,
 673         &_cmsTagPluginChunk,           //  TagPlugin,
 674         &_cmsIntentsPluginChunk,       //  IntentPlugin,
 675         &_cmsMPETypePluginChunk,       //  MPEPlugin,
 676         &_cmsOptimizationPluginChunk,  //  OptimizationPlugin,
 677         &_cmsTransformPluginChunk,     //  TransformPlugin,
 678         &_cmsMutexPluginChunk          //  MutexPlugin
 679     },
 680 
 681     { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
 682 };
 683 
 684 
 685 // The context pool (linked list head)
 686 static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
 687 static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
 688 
 689 // Internal, get associated pointer, with guessing. Never returns NULL.
 690 struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
 691 {
 692     struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
 693     struct _cmsContext_struct* ctx;
 694 
 695 
 696     // On 0, use global settings
 697     if (id == NULL)
 698         return &globalContext;
 699 
 700     // Search
 701     for (ctx = _cmsContextPoolHead;
 702          ctx != NULL;
 703          ctx = ctx ->Next) {
 704 
 705             // Found it?
 706             if (id == ctx)
 707                 return ctx; // New-style context,
 708     }
 709 
 710     return &globalContext;
 711 }
 712 
 713 
 714 // Internal: get the memory area associanted with each context client
 715 // Returns the block assigned to the specific zone. Never return NULL.
 716 void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
 717 {
 718     struct _cmsContext_struct* ctx;
 719     void *ptr;
 720 
 721     if ((int) mc < 0 || mc >= MemoryClientMax) {
 722 
 723            cmsSignalError(ContextID, cmsERROR_INTERNAL, "Bad context client -- possible corruption");
 724 
 725            // This is catastrophic. Should never reach here
 726            _cmsAssert(0);
 727 
 728            // Reverts to global context
 729            return globalContext.chunks[UserPtr];
 730     }
 731 
 732     ctx = _cmsGetContext(ContextID);
 733     ptr = ctx ->chunks[mc];
 734 
 735     if (ptr != NULL)
 736         return ptr;
 737 
 738     // A null ptr means no special settings for that context, and this
 739     // reverts to Context0 globals
 740     return globalContext.chunks[mc];
 741 }
 742 
 743 
 744 // This function returns the given context its default pristine state,
 745 // as no plug-ins were declared. There is no way to unregister a single
 746 // plug-in, as a single call to cmsPluginTHR() function may register
 747 // many different plug-ins simultaneously, then there is no way to
 748 // identify which plug-in to unregister.
 749 void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
 750 {
 751     _cmsRegisterMemHandlerPlugin(ContextID, NULL);
 752     _cmsRegisterInterpPlugin(ContextID, NULL);
 753     _cmsRegisterTagTypePlugin(ContextID, NULL);
 754     _cmsRegisterTagPlugin(ContextID, NULL);
 755     _cmsRegisterFormattersPlugin(ContextID, NULL);
 756     _cmsRegisterRenderingIntentPlugin(ContextID, NULL);
 757     _cmsRegisterParametricCurvesPlugin(ContextID, NULL);
 758     _cmsRegisterMultiProcessElementPlugin(ContextID, NULL);
 759     _cmsRegisterOptimizationPlugin(ContextID, NULL);
 760     _cmsRegisterTransformPlugin(ContextID, NULL);
 761     _cmsRegisterMutexPlugin(ContextID, NULL);
 762 }
 763 
 764 
 765 // Returns the memory manager plug-in, if any, from the Plug-in bundle
 766 static
 767 cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
 768 {
 769     cmsPluginBase* Plugin;
 770 
 771     for (Plugin = (cmsPluginBase*) PluginBundle;
 772         Plugin != NULL;
 773         Plugin = Plugin -> Next) {
 774 
 775             if (Plugin -> Magic == cmsPluginMagicNumber &&
 776                 Plugin -> ExpectedVersion <= LCMS_VERSION &&
 777                 Plugin -> Type == cmsPluginMemHandlerSig) {
 778 
 779                     // Found!
 780                     return (cmsPluginMemHandler*) Plugin;
 781             }
 782     }
 783 
 784     // Nope, revert to defaults
 785     return NULL;
 786 }
 787 
 788 
 789 // Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined
 790 // data that will be forwarded to plug-ins and logger.
 791 cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
 792 {
 793     struct _cmsContext_struct* ctx;
 794     struct _cmsContext_struct  fakeContext;
 795 
 796     _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
 797 
 798     fakeContext.chunks[UserPtr]     = UserData;
 799     fakeContext.chunks[MemPlugin]   = &fakeContext.DefaultMemoryManager;
 800 
 801     // Create the context structure.
 802     ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
 803     if (ctx == NULL)
 804         return NULL;     // Something very wrong happened!
 805 
 806     // Init the structure and the memory manager
 807     memset(ctx, 0, sizeof(struct _cmsContext_struct));
 808 
 809     // Keep memory manager
 810     memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
 811 
 812     // Maintain the linked list (with proper locking)
 813     _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
 814        ctx ->Next = _cmsContextPoolHead;
 815        _cmsContextPoolHead = ctx;
 816     _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
 817 
 818     ctx ->chunks[UserPtr]     = UserData;
 819     ctx ->chunks[MemPlugin]   = &ctx->DefaultMemoryManager;
 820 
 821     // Now we can allocate the pool by using default memory manager
 822     ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));  // default size about 32 pointers
 823     if (ctx ->MemPool == NULL) {
 824 
 825          cmsDeleteContext(ctx);
 826         return NULL;
 827     }
 828 
 829     _cmsAllocLogErrorChunk(ctx, NULL);
 830     _cmsAllocAlarmCodesChunk(ctx, NULL);
 831     _cmsAllocAdaptationStateChunk(ctx, NULL);
 832     _cmsAllocMemPluginChunk(ctx, NULL);
 833     _cmsAllocInterpPluginChunk(ctx, NULL);
 834     _cmsAllocCurvesPluginChunk(ctx, NULL);
 835     _cmsAllocFormattersPluginChunk(ctx, NULL);
 836     _cmsAllocTagTypePluginChunk(ctx, NULL);
 837     _cmsAllocMPETypePluginChunk(ctx, NULL);
 838     _cmsAllocTagPluginChunk(ctx, NULL);
 839     _cmsAllocIntentsPluginChunk(ctx, NULL);
 840     _cmsAllocOptimizationPluginChunk(ctx, NULL);
 841     _cmsAllocTransformPluginChunk(ctx, NULL);
 842     _cmsAllocMutexPluginChunk(ctx, NULL);
 843 
 844     // Setup the plug-ins
 845     if (!cmsPluginTHR(ctx, Plugin)) {
 846 
 847         cmsDeleteContext(ctx);
 848         return NULL;
 849     }
 850 
 851     return (cmsContext) ctx;
 852 }
 853 
 854 // Duplicates a context with all associated plug-ins.
 855 // Caller may specify an optional pointer to user-defined
 856 // data that will be forwarded to plug-ins and logger.
 857 cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
 858 {
 859     int i;
 860     struct _cmsContext_struct* ctx;
 861     const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
 862 
 863     void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
 864 
 865 
 866     ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
 867     if (ctx == NULL)
 868         return NULL;     // Something very wrong happened
 869 
 870     // Setup default memory allocators
 871     memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
 872 
 873     // Maintain the linked list
 874     _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
 875        ctx ->Next = _cmsContextPoolHead;
 876        _cmsContextPoolHead = ctx;
 877     _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
 878 
 879     ctx ->chunks[UserPtr]    = userData;
 880     ctx ->chunks[MemPlugin]  = &ctx->DefaultMemoryManager;
 881 
 882     ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
 883     if (ctx ->MemPool == NULL) {
 884 
 885          cmsDeleteContext(ctx);
 886         return NULL;
 887     }
 888 
 889     // Allocate all required chunks.
 890     _cmsAllocLogErrorChunk(ctx, src);
 891     _cmsAllocAlarmCodesChunk(ctx, src);
 892     _cmsAllocAdaptationStateChunk(ctx, src);
 893     _cmsAllocMemPluginChunk(ctx, src);
 894     _cmsAllocInterpPluginChunk(ctx, src);
 895     _cmsAllocCurvesPluginChunk(ctx, src);
 896     _cmsAllocFormattersPluginChunk(ctx, src);
 897     _cmsAllocTagTypePluginChunk(ctx, src);
 898     _cmsAllocMPETypePluginChunk(ctx, src);
 899     _cmsAllocTagPluginChunk(ctx, src);
 900     _cmsAllocIntentsPluginChunk(ctx, src);
 901     _cmsAllocOptimizationPluginChunk(ctx, src);
 902     _cmsAllocTransformPluginChunk(ctx, src);
 903     _cmsAllocMutexPluginChunk(ctx, src);
 904 
 905     // Make sure no one failed
 906     for (i=Logger; i < MemoryClientMax; i++) {
 907 
 908         if (src ->chunks[i] == NULL) {
 909             cmsDeleteContext((cmsContext) ctx);
 910             return NULL;
 911         }
 912     }
 913 
 914     return (cmsContext) ctx;
 915 }
 916 
 917 
 918 /*
 919 static
 920 struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
 921 {
 922     struct _cmsContext_struct* prev;
 923 
 924     // Search for previous
 925     for (prev = _cmsContextPoolHead;
 926              prev != NULL;
 927              prev = prev ->Next)
 928     {
 929         if (prev ->Next == id)
 930             return prev;
 931     }
 932 
 933     return NULL;  // List is empty or only one element!
 934 }
 935 */
 936 
 937 // Frees any resources associated with the given context,
 938 // and destroys the context placeholder.
 939 // The ContextID can no longer be used in any THR operation.
 940 void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
 941 {
 942     if (ContextID != NULL) {
 943 
 944         struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
 945         struct _cmsContext_struct  fakeContext;
 946         struct _cmsContext_struct* prev;
 947 
 948         memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
 949 
 950         fakeContext.chunks[UserPtr]     = ctx ->chunks[UserPtr];
 951         fakeContext.chunks[MemPlugin]   = &fakeContext.DefaultMemoryManager;
 952 
 953         // Get rid of plugins
 954         cmsUnregisterPluginsTHR(ContextID);
 955 
 956         // Since all memory is allocated in the private pool, all what we need to do is destroy the pool
 957         if (ctx -> MemPool != NULL)
 958               _cmsSubAllocDestroy(ctx ->MemPool);
 959         ctx -> MemPool = NULL;
 960 
 961         // Maintain list
 962         _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
 963         if (_cmsContextPoolHead == ctx) {
 964 
 965             _cmsContextPoolHead = ctx->Next;
 966         }
 967         else {
 968 
 969             // Search for previous
 970             for (prev = _cmsContextPoolHead;
 971                  prev != NULL;
 972                  prev = prev ->Next)
 973             {
 974                 if (prev -> Next == ctx) {
 975                     prev -> Next = ctx ->Next;
 976                     break;
 977                 }
 978             }
 979         }
 980         _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
 981 
 982         // free the memory block itself
 983         _cmsFree(&fakeContext, ctx);
 984     }
 985 }
 986 
 987 // Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
 988 void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
 989 {
 990     return _cmsContextGetClientChunk(ContextID, UserPtr);
 991 }
 992 
 993