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