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