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 129 _cmsAssert(Result != NULL); 130 131 *Result = *QWord; 132 #endif 133 } 134 135 // Auxiliar -- read 8, 16 and 32-bit numbers 136 cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n) 137 { 138 cmsUInt8Number tmp; 139 140 _cmsAssert(io != NULL); 141 142 if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1) 143 return FALSE; 144 145 if (n != NULL) *n = tmp; 146 return TRUE; 147 } 148 149 cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n) 150 { 151 cmsUInt16Number tmp; 152 153 _cmsAssert(io != NULL); 154 155 if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1) 156 return FALSE; 157 158 if (n != NULL) *n = _cmsAdjustEndianess16(tmp); 159 return TRUE; 160 } 161 162 cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array) 163 { 164 cmsUInt32Number i; 165 166 _cmsAssert(io != NULL); 167 168 for (i=0; i < n; i++) { 169 170 if (Array != NULL) { 171 if (!_cmsReadUInt16Number(io, Array + i)) return FALSE; 172 } 173 else { 174 if (!_cmsReadUInt16Number(io, NULL)) return FALSE; 175 } 176 177 } 178 return TRUE; 179 } 180 181 cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n) 182 { 183 cmsUInt32Number tmp; 184 185 _cmsAssert(io != NULL); 186 187 if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) 188 return FALSE; 189 190 if (n != NULL) *n = _cmsAdjustEndianess32(tmp); 191 return TRUE; 192 } 193 194 cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n) 195 { 196 cmsUInt32Number tmp; 197 198 _cmsAssert(io != NULL); 199 200 if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1) 201 return FALSE; 202 203 if (n != NULL) { 204 205 tmp = _cmsAdjustEndianess32(tmp); 206 *n = *(cmsFloat32Number*) &tmp; 207 } 208 return TRUE; 209 } 210 211 212 cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) 213 { 214 cmsUInt64Number tmp; 215 216 _cmsAssert(io != NULL); 217 218 if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1) 219 return FALSE; 220 221 if (n != NULL) _cmsAdjustEndianess64(n, &tmp); 222 return TRUE; 223 } 224 225 226 cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n) 227 { 228 cmsUInt32Number tmp; 229 230 _cmsAssert(io != NULL); 231 232 if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1) 233 return FALSE; 234 235 if (n != NULL) { 236 *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp)); 237 } 238 239 return TRUE; 240 } 241 242 243 // Jun-21-2000: Some profiles (those that comes with W2K) comes 244 // with the media white (media black?) x 100. Add a sanity check 245 246 static 247 void NormalizeXYZ(cmsCIEXYZ* Dest) 248 { 249 while (Dest -> X > 2. && 250 Dest -> Y > 2. && 251 Dest -> Z > 2.) { 252 253 Dest -> X /= 10.; 254 Dest -> Y /= 10.; 255 Dest -> Z /= 10.; 256 } 257 } 258 259 cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ) 260 { 261 cmsEncodedXYZNumber xyz; 262 263 _cmsAssert(io != NULL); 264 265 if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE; 266 267 if (XYZ != NULL) { 268 269 XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X)); 270 XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y)); 271 XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z)); 272 273 NormalizeXYZ(XYZ); 274 } 275 return TRUE; 276 } 277 278 cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n) 279 { 280 _cmsAssert(io != NULL); 281 282 if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1) 283 return FALSE; 284 285 return TRUE; 286 } 287 288 cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n) 289 { 290 cmsUInt16Number tmp; 291 292 _cmsAssert(io != NULL); 293 294 tmp = _cmsAdjustEndianess16(n); 295 if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1) 296 return FALSE; 297 298 return TRUE; 299 } 300 301 cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array) 302 { 303 cmsUInt32Number i; 304 305 _cmsAssert(io != NULL); 306 _cmsAssert(Array != NULL); 307 308 for (i=0; i < n; i++) { 309 if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE; 310 } 311 312 return TRUE; 313 } 314 315 cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n) 316 { 317 cmsUInt32Number tmp; 318 319 _cmsAssert(io != NULL); 320 321 tmp = _cmsAdjustEndianess32(n); 322 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) 323 return FALSE; 324 325 return TRUE; 326 } 327 328 329 cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) 330 { 331 cmsUInt32Number tmp; 332 333 _cmsAssert(io != NULL); 334 335 tmp = *(cmsUInt32Number*) &n; 336 tmp = _cmsAdjustEndianess32(tmp); 337 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) 338 return FALSE; 339 340 return TRUE; 341 } 342 343 cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) 344 { 345 cmsUInt64Number tmp; 346 347 _cmsAssert(io != NULL); 348 349 _cmsAdjustEndianess64(&tmp, n); 350 if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1) 351 return FALSE; 352 353 return TRUE; 354 } 355 356 cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n) 357 { 358 cmsUInt32Number tmp; 359 360 _cmsAssert(io != NULL); 361 362 tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n)); 363 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) 364 return FALSE; 365 366 return TRUE; 367 } 368 369 cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) 370 { 371 cmsEncodedXYZNumber xyz; 372 373 _cmsAssert(io != NULL); 374 _cmsAssert(XYZ != NULL); 375 376 xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X)); 377 xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y)); 378 xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z)); 379 380 return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz); 381 } 382 383 // from Fixed point 8.8 to double 384 cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) 385 { 386 cmsUInt8Number msb, lsb; 387 388 lsb = (cmsUInt8Number) (fixed8 & 0xff); 389 msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff); 390 391 return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0)); 392 } 393 394 cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) 395 { 396 cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val); 397 return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF); 398 } 399 400 // from Fixed point 15.16 to double 401 cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) 402 { 403 cmsFloat64Number floater, sign, mid; 404 int Whole, FracPart; 405 406 sign = (fix32 < 0 ? -1 : 1); 407 fix32 = abs(fix32); 408 409 Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff; 410 FracPart = (cmsUInt16Number)(fix32 & 0xffff); 411 412 mid = (cmsFloat64Number) FracPart / 65536.0; 413 floater = (cmsFloat64Number) Whole + mid; 414 415 return sign * floater; 416 } 417 418 // from double to Fixed point 15.16 419 cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v) 420 { 421 return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5)); 422 } 423 424 // Date/Time functions 425 426 void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest) 427 { 428 429 _cmsAssert(Dest != NULL); 430 _cmsAssert(Source != NULL); 431 432 Dest->tm_sec = _cmsAdjustEndianess16(Source->seconds); 433 Dest->tm_min = _cmsAdjustEndianess16(Source->minutes); 434 Dest->tm_hour = _cmsAdjustEndianess16(Source->hours); 435 Dest->tm_mday = _cmsAdjustEndianess16(Source->day); 436 Dest->tm_mon = _cmsAdjustEndianess16(Source->month) - 1; 437 Dest->tm_year = _cmsAdjustEndianess16(Source->year) - 1900; 438 Dest->tm_wday = -1; 439 Dest->tm_yday = -1; 440 Dest->tm_isdst = 0; 441 } 442 443 void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source) 444 { 445 _cmsAssert(Dest != NULL); 446 _cmsAssert(Source != NULL); 447 448 Dest->seconds = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_sec); 449 Dest->minutes = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_min); 450 Dest->hours = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_hour); 451 Dest->day = _cmsAdjustEndianess16((cmsUInt16Number) Source->tm_mday); 452 Dest->month = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_mon + 1)); 453 Dest->year = _cmsAdjustEndianess16((cmsUInt16Number) (Source->tm_year + 1900)); 454 } 455 456 // Read base and return type base 457 cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io) 458 { 459 _cmsTagBase Base; 460 461 _cmsAssert(io != NULL); 462 463 if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1) 464 return (cmsTagTypeSignature) 0; 465 466 return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig); 467 } 468 469 // Setup base marker 470 cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig) 471 { 472 _cmsTagBase Base; 473 474 _cmsAssert(io != NULL); 475 476 Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig); 477 memset(&Base.reserved, 0, sizeof(Base.reserved)); 478 return io -> Write(io, sizeof(_cmsTagBase), &Base); 479 } 480 481 cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io) 482 { 483 cmsUInt8Number Buffer[4]; 484 cmsUInt32Number NextAligned, At; 485 cmsUInt32Number BytesToNextAlignedPos; 486 487 _cmsAssert(io != NULL); 488 489 At = io -> Tell(io); 490 NextAligned = _cmsALIGNLONG(At); 491 BytesToNextAlignedPos = NextAligned - At; 492 if (BytesToNextAlignedPos == 0) return TRUE; 493 if (BytesToNextAlignedPos > 4) return FALSE; 494 495 return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1); 496 } 497 498 cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io) 499 { 500 cmsUInt8Number Buffer[4]; 501 cmsUInt32Number NextAligned, At; 502 cmsUInt32Number BytesToNextAlignedPos; 503 504 _cmsAssert(io != NULL); 505 506 At = io -> Tell(io); 507 NextAligned = _cmsALIGNLONG(At); 508 BytesToNextAlignedPos = NextAligned - At; 509 if (BytesToNextAlignedPos == 0) return TRUE; 510 if (BytesToNextAlignedPos > 4) return FALSE; 511 512 memset(Buffer, 0, BytesToNextAlignedPos); 513 return io -> Write(io, BytesToNextAlignedPos, Buffer); 514 } 515 516 517 // To deal with text streams. 2K at most 518 cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...) 519 { 520 va_list args; 521 int len; 522 cmsUInt8Number Buffer[2048]; 523 cmsBool rc; 524 525 _cmsAssert(io != NULL); 526 _cmsAssert(frm != NULL); 527 528 va_start(args, frm); 529 530 len = vsnprintf((char*) Buffer, 2047, frm, args); 531 if (len < 0) return FALSE; // Truncated, which is a fatal error for us 532 533 rc = io ->Write(io, len, Buffer); 534 535 va_end(args); 536 537 return rc; 538 } 539 540 541 // Plugin memory management ------------------------------------------------------------------------------------------------- 542 543 static _cmsSubAllocator* PluginPool = NULL; 544 545 // Specialized malloc for plug-ins, that is freed upon exit. 546 void* _cmsPluginMalloc(cmsUInt32Number size) 547 { 548 if (PluginPool == NULL) 549 PluginPool = _cmsCreateSubAlloc(0, 4*1024); 550 551 return _cmsSubAlloc(PluginPool, size); 552 } 553 554 555 // Main plug-in dispatcher 556 cmsBool CMSEXPORT cmsPlugin(void* Plug_in) 557 { 558 cmsPluginBase* Plugin; 559 560 for (Plugin = (cmsPluginBase*) Plug_in; 561 Plugin != NULL; 562 Plugin = Plugin -> Next) { 563 564 if (Plugin -> Magic != cmsPluginMagicNumber) { 565 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin"); 566 return FALSE; 567 } 568 569 if (Plugin ->ExpectedVersion > LCMS_VERSION) { 570 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", 571 Plugin ->ExpectedVersion, LCMS_VERSION); 572 return FALSE; 573 } 574 575 switch (Plugin -> Type) { 576 577 case cmsPluginMemHandlerSig: 578 if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE; 579 break; 580 581 case cmsPluginInterpolationSig: 582 if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE; 583 break; 584 585 case cmsPluginTagTypeSig: 586 if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE; 587 break; 588 589 case cmsPluginTagSig: 590 if (!_cmsRegisterTagPlugin(Plugin)) return FALSE; 591 break; 592 593 case cmsPluginFormattersSig: 594 if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE; 595 break; 596 597 case cmsPluginRenderingIntentSig: 598 if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE; 599 break; 600 601 case cmsPluginParametricCurveSig: 602 if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE; 603 break; 604 605 case cmsPluginMultiProcessElementSig: 606 if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE; 607 break; 608 609 case cmsPluginOptimizationSig: 610 if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE; 611 break; 612 613 case cmsPluginTransformSig: 614 if (!_cmsRegisterTransformPlugin(Plugin)) return FALSE; 615 break; 616 617 default: 618 cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); 619 return FALSE; 620 } 621 } 622 623 // Keep a reference to the plug-in 624 return TRUE; 625 } 626 627 628 // Revert all plug-ins to default 629 void CMSEXPORT cmsUnregisterPlugins(void) 630 { 631 _cmsRegisterMemHandlerPlugin(NULL); 632 _cmsRegisterInterpPlugin(NULL); 633 _cmsRegisterTagTypePlugin(NULL); 634 _cmsRegisterTagPlugin(NULL); 635 _cmsRegisterFormattersPlugin(NULL); 636 _cmsRegisterRenderingIntentPlugin(NULL); 637 _cmsRegisterParametricCurvesPlugin(NULL); 638 _cmsRegisterMultiProcessElementPlugin(NULL); 639 _cmsRegisterOptimizationPlugin(NULL); 640 _cmsRegisterTransformPlugin(NULL); 641 642 if (PluginPool != NULL) 643 _cmsSubAllocDestroy(PluginPool); 644 645 PluginPool = NULL; 646 }