1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2010 Marti Maria Saguer
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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
30 // ----------------------------------------------------------------------------------
31 // Encoding & Decoding support functions
32 // ----------------------------------------------------------------------------------
34 // Little-Endian to Big-Endian
36 // Adjust a word value after being readed/ before being written from/to an ICC profile
37 cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word)
39 #ifndef CMS_USE_BIG_ENDIAN
41 cmsUInt8Number* pByte = (cmsUInt8Number*) &Word;
53 // Transports to properly encoded values - note that icc profiles does use big endian notation.
58 cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord)
60 #ifndef CMS_USE_BIG_ENDIAN
62 cmsUInt8Number* pByte = (cmsUInt8Number*) &DWord;
79 void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord)
82 #ifndef CMS_USE_BIG_ENDIAN
84 cmsUInt8Number* pIn = (cmsUInt8Number*) QWord;
85 cmsUInt8Number* pOut = (cmsUInt8Number*) Result;
87 _cmsAssert(Result != NULL);
99 _cmsAssert(Result != NULL);
101 # ifdef CMS_DONT_USE_INT64
102 (*Result)[0] = QWord[0];
103 (*Result)[1] = QWord[1];
110 // Auxiliar -- read 8, 16 and 32-bit numbers
111 cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n)
115 _cmsAssert(io != NULL);
117 if (io -> Read(io, &tmp, sizeof(cmsUInt8Number), 1) != 1)
120 if (n != NULL) *n = tmp;
124 cmsBool CMSEXPORT _cmsReadUInt16Number(cmsIOHANDLER* io, cmsUInt16Number* n)
128 _cmsAssert(io != NULL);
130 if (io -> Read(io, &tmp, sizeof(cmsUInt16Number), 1) != 1)
133 if (n != NULL) *n = _cmsAdjustEndianess16(tmp);
137 cmsBool CMSEXPORT _cmsReadUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, cmsUInt16Number* Array)
141 _cmsAssert(io != NULL);
143 for (i=0; i < n; i++) {
146 if (!_cmsReadUInt16Number(io, Array + i)) return FALSE;
149 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
156 cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n)
160 _cmsAssert(io != NULL);
162 if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
165 if (n != NULL) *n = _cmsAdjustEndianess32(tmp);
169 cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
173 _cmsAssert(io != NULL);
175 if (io -> Read(io, &tmp, sizeof(cmsFloat32Number), 1) != 1)
180 tmp = _cmsAdjustEndianess32(tmp);
181 *n = *(cmsFloat32Number*) &tmp;
187 cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
191 _cmsAssert(io != NULL);
193 if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
196 if (n != NULL) _cmsAdjustEndianess64(n, &tmp);
201 cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n)
205 _cmsAssert(io != NULL);
207 if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
211 *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
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
222 void NormalizeXYZ(cmsCIEXYZ* Dest)
224 while (Dest -> X > 2. &&
234 cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
236 cmsEncodedXYZNumber xyz;
238 _cmsAssert(io != NULL);
240 if (io ->Read(io, &xyz, sizeof(cmsEncodedXYZNumber), 1) != 1) return FALSE;
244 XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
245 XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
246 XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
253 cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUInt8Number n)
255 _cmsAssert(io != NULL);
257 if (io -> Write(io, sizeof(cmsUInt8Number), &n) != 1)
263 cmsBool CMSEXPORT _cmsWriteUInt16Number(cmsIOHANDLER* io, cmsUInt16Number n)
267 _cmsAssert(io != NULL);
269 tmp = _cmsAdjustEndianess16(n);
270 if (io -> Write(io, sizeof(cmsUInt16Number), &tmp) != 1)
276 cmsBool CMSEXPORT _cmsWriteUInt16Array(cmsIOHANDLER* io, cmsUInt32Number n, const cmsUInt16Number* Array)
280 _cmsAssert(io != NULL);
281 _cmsAssert(Array != NULL);
283 for (i=0; i < n; i++) {
284 if (!_cmsWriteUInt16Number(io, Array[i])) return FALSE;
290 cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n)
294 _cmsAssert(io != NULL);
296 tmp = _cmsAdjustEndianess32(n);
297 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
304 cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
308 _cmsAssert(io != NULL);
310 tmp = *(cmsUInt32Number*) &n;
311 tmp = _cmsAdjustEndianess32(tmp);
312 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
318 cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
322 _cmsAssert(io != NULL);
324 _cmsAdjustEndianess64(&tmp, n);
325 if (io -> Write(io, sizeof(cmsUInt64Number), &tmp) != 1)
331 cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n)
335 _cmsAssert(io != NULL);
337 tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
338 if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
344 cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
346 cmsEncodedXYZNumber xyz;
348 _cmsAssert(io != NULL);
349 _cmsAssert(XYZ != NULL);
351 xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
352 xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
353 xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
355 return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);
358 // from Fixed point 8.8 to double
359 cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
361 cmsUInt8Number msb, lsb;
363 lsb = (cmsUInt8Number) (fixed8 & 0xff);
364 msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
366 return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
369 cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
371 cmsS15Fixed16Number GammaFixed32 = _cmsDoubleTo15Fixed16(val);
372 return (cmsUInt16Number) ((GammaFixed32 >> 8) & 0xFFFF);
375 // from Fixed point 15.16 to double
376 cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
378 cmsFloat64Number floater, sign, mid;
381 sign = (fix32 < 0 ? -1 : 1);
384 Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
385 FracPart = (cmsUInt16Number)(fix32 & 0xffff);
387 mid = (cmsFloat64Number) FracPart / 65536.0;
388 floater = (cmsFloat64Number) Whole + mid;
390 return sign * floater;
393 // from double to Fixed point 15.16
394 cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v)
396 return ((cmsS15Fixed16Number) floor((v)*65536.0 + 0.5));
399 // Date/Time functions
401 void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeNumber *Source, struct tm *Dest)
404 _cmsAssert(Dest != NULL);
405 _cmsAssert(Source != NULL);
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;
418 void CMSEXPORT _cmsEncodeDateTimeNumber(cmsDateTimeNumber *Dest, const struct tm *Source)
420 _cmsAssert(Dest != NULL);
421 _cmsAssert(Source != NULL);
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));
431 // Read base and return type base
432 cmsTagTypeSignature CMSEXPORT _cmsReadTypeBase(cmsIOHANDLER* io)
436 _cmsAssert(io != NULL);
438 if (io -> Read(io, &Base, sizeof(_cmsTagBase), 1) != 1)
439 return (cmsTagTypeSignature) 0;
441 return (cmsTagTypeSignature) _cmsAdjustEndianess32(Base.sig);
445 cmsBool CMSEXPORT _cmsWriteTypeBase(cmsIOHANDLER* io, cmsTagTypeSignature sig)
449 _cmsAssert(io != NULL);
451 Base.sig = (cmsTagTypeSignature) _cmsAdjustEndianess32(sig);
452 memset(&Base.reserved, 0, sizeof(Base.reserved));
453 return io -> Write(io, sizeof(_cmsTagBase), &Base);
456 cmsBool CMSEXPORT _cmsReadAlignment(cmsIOHANDLER* io)
458 cmsUInt8Number Buffer[4];
459 cmsUInt32Number NextAligned, At;
460 cmsUInt32Number BytesToNextAlignedPos;
462 _cmsAssert(io != NULL);
465 NextAligned = _cmsALIGNLONG(At);
466 BytesToNextAlignedPos = NextAligned - At;
467 if (BytesToNextAlignedPos == 0) return TRUE;
468 if (BytesToNextAlignedPos > 4) return FALSE;
470 return (io ->Read(io, Buffer, BytesToNextAlignedPos, 1) == 1);
473 cmsBool CMSEXPORT _cmsWriteAlignment(cmsIOHANDLER* io)
475 cmsUInt8Number Buffer[4];
476 cmsUInt32Number NextAligned, At;
477 cmsUInt32Number BytesToNextAlignedPos;
479 _cmsAssert(io != NULL);
482 NextAligned = _cmsALIGNLONG(At);
483 BytesToNextAlignedPos = NextAligned - At;
484 if (BytesToNextAlignedPos == 0) return TRUE;
485 if (BytesToNextAlignedPos > 4) return FALSE;
487 memset(Buffer, 0, BytesToNextAlignedPos);
488 return io -> Write(io, BytesToNextAlignedPos, Buffer);
492 // To deal with text streams. 2K at most
493 cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
497 cmsUInt8Number Buffer[2048];
500 _cmsAssert(io != NULL);
501 _cmsAssert(frm != NULL);
505 len = vsnprintf((char*) Buffer, 2047, frm, args);
506 if (len < 0) return FALSE; // Truncated, which is a fatal error for us
508 rc = io ->Write(io, len, Buffer);
516 // Plugin memory management -------------------------------------------------------------------------------------------------
518 // Specialized malloc for plug-ins, that is freed upon exit.
519 void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
521 struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
523 if (ctx ->MemPool == NULL) {
525 if (ContextID == NULL) {
527 ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
530 cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
535 return _cmsSubAlloc(ctx->MemPool, size);
539 // Main plug-in dispatcher
540 cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
542 return cmsPluginTHR(NULL, Plug_in);
545 cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
547 cmsPluginBase* Plugin;
549 for (Plugin = (cmsPluginBase*) Plug_in;
551 Plugin = Plugin -> Next) {
553 if (Plugin -> Magic != cmsPluginMagicNumber) {
554 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
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);
564 switch (Plugin -> Type) {
566 case cmsPluginMemHandlerSig:
567 if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
570 case cmsPluginInterpolationSig:
571 if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
574 case cmsPluginTagTypeSig:
575 if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE;
578 case cmsPluginTagSig:
579 if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE;
582 case cmsPluginFormattersSig:
583 if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE;
586 case cmsPluginRenderingIntentSig:
587 if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE;
590 case cmsPluginParametricCurveSig:
591 if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE;
594 case cmsPluginMultiProcessElementSig:
595 if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE;
598 case cmsPluginOptimizationSig:
599 if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE;
602 case cmsPluginTransformSig:
603 if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
606 case cmsPluginMutexSig:
607 if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
611 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
616 // Keep a reference to the plug-in
621 // Revert all plug-ins to default
622 void CMSEXPORT cmsUnregisterPlugins(void)
624 cmsUnregisterPluginsTHR(NULL);
628 // The Global storage for system context. This is the one and only global variable
629 // pointers structure. All global vars are referenced here.
630 static struct _cmsContext_struct globalContext = {
632 NULL, // Not in the linked list
633 NULL, // No suballocator
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
652 { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
656 // The context pool (linked list head)
657 static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
658 static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
660 // Internal, get associated pointer, with guessing. Never returns NULL.
661 struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
663 struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
664 struct _cmsContext_struct* ctx;
667 // On 0, use global settings
669 return &globalContext;
672 for (ctx = _cmsContextPoolHead;
678 return ctx; // New-style context,
681 return &globalContext;
685 // Internal: get the memory area associanted with each context client
686 // Returns the block assigned to the specific zone.
687 void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
689 struct _cmsContext_struct* ctx;
692 if (mc < 0 || mc >= MemoryClientMax) {
693 cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client");
697 ctx = _cmsGetContext(ContextID);
698 ptr = ctx ->chunks[mc];
703 // A null ptr means no special settings for that context, and this
704 // reverts to Context0 globals
705 return globalContext.chunks[mc];
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.
714 void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
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);
730 // Returns the memory manager plug-in, if any, from the Plug-in bundle
732 cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
734 cmsPluginBase* Plugin;
736 for (Plugin = (cmsPluginBase*) PluginBundle;
738 Plugin = Plugin -> Next) {
740 if (Plugin -> Magic == cmsPluginMagicNumber &&
741 Plugin -> ExpectedVersion <= LCMS_VERSION &&
742 Plugin -> Type == cmsPluginMemHandlerSig) {
745 return (cmsPluginMemHandler*) Plugin;
749 // Nope, revert to defaults
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.
756 cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
758 struct _cmsContext_struct* ctx;
759 struct _cmsContext_struct fakeContext;
761 _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
763 fakeContext.chunks[UserPtr] = UserData;
764 fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
766 // Create the context structure.
767 ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
769 return NULL; // Something very wrong happened!
771 // Init the structure and the memory manager
772 memset(ctx, 0, sizeof(struct _cmsContext_struct));
774 // Keep memory manager
775 memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
777 // Maintain the linked list (with proper locking)
778 _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
779 ctx ->Next = _cmsContextPoolHead;
780 _cmsContextPoolHead = ctx;
781 _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
783 ctx ->chunks[UserPtr] = UserData;
784 ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
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) {
790 cmsDeleteContext(ctx);
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);
809 // Setup the plug-ins
810 if (!cmsPluginTHR(ctx, Plugin)) {
812 cmsDeleteContext(ctx);
816 return (cmsContext) ctx;
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.
822 cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
825 struct _cmsContext_struct* ctx;
826 const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
828 void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
831 ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
833 return NULL; // Something very wrong happened
835 // Setup default memory allocators
836 memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
838 // Maintain the linked list
839 _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
840 ctx ->Next = _cmsContextPoolHead;
841 _cmsContextPoolHead = ctx;
842 _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
844 ctx ->chunks[UserPtr] = userData;
845 ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
847 ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
848 if (ctx ->MemPool == NULL) {
850 cmsDeleteContext(ctx);
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);
870 // Make sure no one failed
871 for (i=Logger; i < MemoryClientMax; i++) {
873 if (src ->chunks[i] == NULL) {
874 cmsDeleteContext((cmsContext) ctx);
879 return (cmsContext) ctx;
885 struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
887 struct _cmsContext_struct* prev;
889 // Search for previous
890 for (prev = _cmsContextPoolHead;
894 if (prev ->Next == id)
898 return NULL; // List is empty or only one element!
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.
904 void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
906 if (ContextID != NULL) {
908 struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
909 struct _cmsContext_struct fakeContext;
910 struct _cmsContext_struct* prev;
912 memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
914 fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
915 fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
917 // Get rid of plugins
918 cmsUnregisterPluginsTHR(ContextID);
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;
926 _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
927 if (_cmsContextPoolHead == ctx) {
929 _cmsContextPoolHead = ctx->Next;
933 // Search for previous
934 for (prev = _cmsContextPoolHead;
938 if (prev -> Next == ctx) {
939 prev -> Next = ctx ->Next;
944 _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
946 // free the memory block itself
947 _cmsFree(&fakeContext, ctx);
951 // Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
952 void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
954 return _cmsContextGetClientChunk(ContextID, UserPtr);