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