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