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