1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2023 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 //---------------------------------------------------------------------------------
26 #include "lcms2_internal.h"
29 // This function is here to help applications to prevent mixing lcms versions on header and shared objects.
30 int CMSEXPORT
cmsGetEncodedCMMversion(void)
35 // I am so tired about incompatibilities on those functions that here are some replacements
36 // that hopefully would be fully portable.
38 // compare two strings ignoring case
39 int CMSEXPORT
cmsstrcasecmp(const char* s1
, const char* s2
)
41 CMSREGISTER
const unsigned char *us1
= (const unsigned char *)s1
,
42 *us2
= (const unsigned char *)s2
;
44 while (toupper(*us1
) == toupper(*us2
++))
48 return (toupper(*us1
) - toupper(*--us2
));
51 // long int because C99 specifies ftell in such way (7.19.9.2)
52 long int CMSEXPORT
cmsfilelength(FILE* f
)
56 p
= ftell(f
); // register current file position
60 if (fseek(f
, 0, SEEK_END
) != 0) {
65 fseek(f
, p
, SEEK_SET
); // file position restored
71 // Memory handling ------------------------------------------------------------------
73 // This is the interface to low-level memory management routines. By default a simple
74 // wrapping to malloc/free/realloc is provided, although there is a limit on the max
75 // amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent
76 // bogus or evil code to allocate huge blocks that otherwise lcms would never need.
78 #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
80 // User may override this behaviour by using a memory plug-in, which basically replaces
81 // the default memory management functions. In this case, no check is performed and it
82 // is up to the plug-in writer to keep in the safe side. There are only three functions
83 // required to be implemented: malloc, realloc and free, although the user may want to
84 // replace the optional mallocZero, calloc and dup as well.
86 cmsBool
_cmsRegisterMemHandlerPlugin(cmsContext ContextID
, cmsPluginBase
* Plugin
);
88 // *********************************************************************************
90 // This is the default memory allocation function. It does a very coarse
91 // check of amount of memory, just to prevent exploits
93 void* _cmsMallocDefaultFn(cmsContext ContextID
, cmsUInt32Number size
)
95 if (size
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never allow over maximum
97 return (void*) malloc(size
);
99 cmsUNUSED_PARAMETER(ContextID
);
102 // Generic allocate & zero
104 void* _cmsMallocZeroDefaultFn(cmsContext ContextID
, cmsUInt32Number size
)
106 void *pt
= _cmsMalloc(ContextID
, size
);
107 if (pt
== NULL
) return NULL
;
114 // The default free function. The only check proformed is against NULL pointers
116 void _cmsFreeDefaultFn(cmsContext ContextID
, void *Ptr
)
118 // free(NULL) is defined a no-op by C99, therefore it is safe to
119 // avoid the check, but it is here just in case...
123 cmsUNUSED_PARAMETER(ContextID
);
126 // The default realloc function. Again it checks for exploits. If Ptr is NULL,
127 // realloc behaves the same way as malloc and allocates a new block of size bytes.
129 void* _cmsReallocDefaultFn(cmsContext ContextID
, void* Ptr
, cmsUInt32Number size
)
132 if (size
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never realloc over 512Mb
134 return realloc(Ptr
, size
);
136 cmsUNUSED_PARAMETER(ContextID
);
140 // The default calloc function. Allocates an array of num elements, each one of size bytes
141 // all memory is initialized to zero.
143 void* _cmsCallocDefaultFn(cmsContext ContextID
, cmsUInt32Number num
, cmsUInt32Number size
)
145 cmsUInt32Number Total
= num
* size
;
147 // Preserve calloc behaviour
148 if (Total
== 0) return NULL
;
150 // Safe check for overflow.
151 if (num
>= UINT_MAX
/ size
) return NULL
;
153 // Check for overflow
154 if (Total
< num
|| Total
< size
) {
158 if (Total
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never alloc over 512Mb
160 return _cmsMallocZero(ContextID
, Total
);
163 // Generic block duplication
165 void* _cmsDupDefaultFn(cmsContext ContextID
, const void* Org
, cmsUInt32Number size
)
169 if (size
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never dup over 512Mb
171 mem
= _cmsMalloc(ContextID
, size
);
173 if (mem
!= NULL
&& Org
!= NULL
)
174 memmove(mem
, Org
, size
);
180 // Pointers to memory manager functions in Context0
181 _cmsMemPluginChunkType _cmsMemPluginChunk
= { _cmsMallocDefaultFn
, _cmsMallocZeroDefaultFn
, _cmsFreeDefaultFn
,
182 _cmsReallocDefaultFn
, _cmsCallocDefaultFn
, _cmsDupDefaultFn
186 // Reset and duplicate memory manager
187 void _cmsAllocMemPluginChunk(struct _cmsContext_struct
* ctx
, const struct _cmsContext_struct
* src
)
189 _cmsAssert(ctx
!= NULL
);
194 ctx
->chunks
[MemPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, src
->chunks
[MemPlugin
], sizeof(_cmsMemPluginChunkType
));
198 // To reset it, we use the default allocators, which cannot be overridden
199 ctx
->chunks
[MemPlugin
] = &ctx
->DefaultMemoryManager
;
203 // Auxiliary to fill memory management functions from plugin (or context 0 defaults)
204 void _cmsInstallAllocFunctions(cmsPluginMemHandler
* Plugin
, _cmsMemPluginChunkType
* ptr
)
206 if (Plugin
== NULL
) {
208 memcpy(ptr
, &_cmsMemPluginChunk
, sizeof(_cmsMemPluginChunk
));
212 ptr
->MallocPtr
= Plugin
-> MallocPtr
;
213 ptr
->FreePtr
= Plugin
-> FreePtr
;
214 ptr
->ReallocPtr
= Plugin
-> ReallocPtr
;
216 // Make sure we revert to defaults
217 ptr
->MallocZeroPtr
= _cmsMallocZeroDefaultFn
;
218 ptr
->CallocPtr
= _cmsCallocDefaultFn
;
219 ptr
->DupPtr
= _cmsDupDefaultFn
;
221 if (Plugin
->MallocZeroPtr
!= NULL
) ptr
->MallocZeroPtr
= Plugin
-> MallocZeroPtr
;
222 if (Plugin
->CallocPtr
!= NULL
) ptr
->CallocPtr
= Plugin
-> CallocPtr
;
223 if (Plugin
->DupPtr
!= NULL
) ptr
->DupPtr
= Plugin
-> DupPtr
;
229 // Plug-in replacement entry
230 cmsBool
_cmsRegisterMemHandlerPlugin(cmsContext ContextID
, cmsPluginBase
*Data
)
232 cmsPluginMemHandler
* Plugin
= (cmsPluginMemHandler
*) Data
;
233 _cmsMemPluginChunkType
* ptr
;
235 // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure.
236 // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the
237 // context internal data should be malloce'd by using those functions.
240 struct _cmsContext_struct
* ctx
= ( struct _cmsContext_struct
*) ContextID
;
242 // Return to the default allocators
243 if (ContextID
!= NULL
) {
244 ctx
->chunks
[MemPlugin
] = (void*) &ctx
->DefaultMemoryManager
;
249 // Check for required callbacks
250 if (Plugin
-> MallocPtr
== NULL
||
251 Plugin
-> FreePtr
== NULL
||
252 Plugin
-> ReallocPtr
== NULL
) return FALSE
;
254 // Set replacement functions
255 ptr
= (_cmsMemPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MemPlugin
);
259 _cmsInstallAllocFunctions(Plugin
, ptr
);
264 void* CMSEXPORT
_cmsMalloc(cmsContext ContextID
, cmsUInt32Number size
)
266 _cmsMemPluginChunkType
* ptr
= (_cmsMemPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MemPlugin
);
267 return ptr
->MallocPtr(ContextID
, size
);
270 // Generic allocate & zero
271 void* CMSEXPORT
_cmsMallocZero(cmsContext ContextID
, cmsUInt32Number size
)
273 _cmsMemPluginChunkType
* ptr
= (_cmsMemPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MemPlugin
);
274 return ptr
->MallocZeroPtr(ContextID
, size
);
278 void* CMSEXPORT
_cmsCalloc(cmsContext ContextID
, cmsUInt32Number num
, cmsUInt32Number size
)
280 _cmsMemPluginChunkType
* ptr
= (_cmsMemPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MemPlugin
);
281 return ptr
->CallocPtr(ContextID
, num
, size
);
284 // Generic reallocate
285 void* CMSEXPORT
_cmsRealloc(cmsContext ContextID
, void* Ptr
, cmsUInt32Number size
)
287 _cmsMemPluginChunkType
* ptr
= (_cmsMemPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MemPlugin
);
288 return ptr
->ReallocPtr(ContextID
, Ptr
, size
);
291 // Generic free memory
292 void CMSEXPORT
_cmsFree(cmsContext ContextID
, void* Ptr
)
295 _cmsMemPluginChunkType
* ptr
= (_cmsMemPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MemPlugin
);
296 ptr
->FreePtr(ContextID
, Ptr
);
300 // Generic block duplication
301 void* CMSEXPORT
_cmsDupMem(cmsContext ContextID
, const void* Org
, cmsUInt32Number size
)
303 _cmsMemPluginChunkType
* ptr
= (_cmsMemPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MemPlugin
);
304 return ptr
->DupPtr(ContextID
, Org
, size
);
307 // ********************************************************************************************
309 // Sub allocation takes care of many pointers of small size. The memory allocated in
310 // this way have be freed at once. Next function allocates a single chunk for linked list
311 // I prefer this method over realloc due to the big impact on xput realloc may have if
312 // memory is being swapped to disk. This approach is safer (although that may not be true on all platforms)
314 _cmsSubAllocator_chunk
* _cmsCreateSubAllocChunk(cmsContext ContextID
, cmsUInt32Number Initial
)
316 _cmsSubAllocator_chunk
* chunk
;
322 // Create the container
323 chunk
= (_cmsSubAllocator_chunk
*) _cmsMallocZero(ContextID
, sizeof(_cmsSubAllocator_chunk
));
324 if (chunk
== NULL
) return NULL
;
327 chunk
->Block
= (cmsUInt8Number
*) _cmsMalloc(ContextID
, Initial
);
328 if (chunk
->Block
== NULL
) {
330 // Something went wrong
331 _cmsFree(ContextID
, chunk
);
335 chunk
->BlockSize
= Initial
;
342 // The suballocated is nothing but a pointer to the first element in the list. We also keep
343 // the thread ID in this structure.
344 _cmsSubAllocator
* _cmsCreateSubAlloc(cmsContext ContextID
, cmsUInt32Number Initial
)
346 _cmsSubAllocator
* sub
;
348 // Create the container
349 sub
= (_cmsSubAllocator
*) _cmsMallocZero(ContextID
, sizeof(_cmsSubAllocator
));
350 if (sub
== NULL
) return NULL
;
352 sub
->ContextID
= ContextID
;
354 sub
->h
= _cmsCreateSubAllocChunk(ContextID
, Initial
);
355 if (sub
->h
== NULL
) {
356 _cmsFree(ContextID
, sub
);
364 // Get rid of whole linked list
365 void _cmsSubAllocDestroy(_cmsSubAllocator
* sub
)
367 _cmsSubAllocator_chunk
*chunk
, *n
;
369 for (chunk
= sub
->h
; chunk
!= NULL
; chunk
= n
) {
372 if (chunk
->Block
!= NULL
) _cmsFree(sub
->ContextID
, chunk
->Block
);
373 _cmsFree(sub
->ContextID
, chunk
);
377 _cmsFree(sub
->ContextID
, sub
);
381 // Get a pointer to small memory block.
382 void* _cmsSubAlloc(_cmsSubAllocator
* sub
, cmsUInt32Number size
)
384 cmsUInt32Number Free
= sub
-> h
->BlockSize
- sub
-> h
-> Used
;
387 size
= _cmsALIGNMEM(size
);
389 // Check for memory. If there is no room, allocate a new chunk of double memory size.
392 _cmsSubAllocator_chunk
* chunk
;
393 cmsUInt32Number newSize
;
395 newSize
= sub
-> h
->BlockSize
* 2;
396 if (newSize
< size
) newSize
= size
;
398 chunk
= _cmsCreateSubAllocChunk(sub
-> ContextID
, newSize
);
399 if (chunk
== NULL
) return NULL
;
402 chunk
->next
= sub
->h
;
407 ptr
= sub
-> h
->Block
+ sub
-> h
->Used
;
408 sub
-> h
-> Used
+= size
;
414 void* _cmsSubAllocDup(_cmsSubAllocator
* s
, const void *ptr
, cmsUInt32Number size
)
418 // Dup of null pointer is also NULL
422 NewPtr
= _cmsSubAlloc(s
, size
);
424 if (ptr
!= NULL
&& NewPtr
!= NULL
) {
425 memcpy(NewPtr
, ptr
, size
);
433 // Error logging ******************************************************************
435 // There is no error handling at all. When a function fails, it returns proper value.
436 // For example, all create functions does return NULL on failure. Other return FALSE
437 // It may be interesting, for the developer, to know why the function is failing.
438 // for that reason, lcms2 does offer a logging function. This function does receive
439 // a ENGLISH string with some clues on what is going wrong. You can show this
440 // info to the end user, or just create some sort of log.
441 // The logging function should NOT terminate the program, as this obviously can leave
442 // resources. It is the programmer's responsibility to check each function return code
443 // to make sure it didn't fail.
445 // Error messages are limited to MAX_ERROR_MESSAGE_LEN
447 #define MAX_ERROR_MESSAGE_LEN 1024
449 // ---------------------------------------------------------------------------------------------------------
451 // This is our default log error
452 static void DefaultLogErrorHandlerFunction(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *Text
);
454 // Context0 storage, which is global
455 _cmsLogErrorChunkType _cmsLogErrorChunk
= { DefaultLogErrorHandlerFunction
};
457 // Allocates and inits error logger container for a given context. If src is NULL, only initializes the value
458 // to the default. Otherwise, it duplicates the value. The interface is standard across all context clients
459 void _cmsAllocLogErrorChunk(struct _cmsContext_struct
* ctx
,
460 const struct _cmsContext_struct
* src
)
462 static _cmsLogErrorChunkType LogErrorChunk
= { DefaultLogErrorHandlerFunction
};
466 from
= src
->chunks
[Logger
];
469 from
= &LogErrorChunk
;
472 ctx
->chunks
[Logger
] = _cmsSubAllocDup(ctx
->MemPool
, from
, sizeof(_cmsLogErrorChunkType
));
475 // The default error logger does nothing.
477 void DefaultLogErrorHandlerFunction(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *Text
)
479 // fprintf(stderr, "[lcms]: %s\n", Text);
482 cmsUNUSED_PARAMETER(ContextID
);
483 cmsUNUSED_PARAMETER(ErrorCode
);
484 cmsUNUSED_PARAMETER(Text
);
487 // Change log error, context based
488 void CMSEXPORT
cmsSetLogErrorHandlerTHR(cmsContext ContextID
, cmsLogErrorHandlerFunction Fn
)
490 _cmsLogErrorChunkType
* lhg
= (_cmsLogErrorChunkType
*) _cmsContextGetClientChunk(ContextID
, Logger
);
495 lhg
-> LogErrorHandler
= DefaultLogErrorHandlerFunction
;
497 lhg
-> LogErrorHandler
= Fn
;
501 // Change log error, legacy
502 void CMSEXPORT
cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn
)
504 cmsSetLogErrorHandlerTHR(NULL
, Fn
);
508 // ErrorText is a text holding an english description of error.
509 void CMSEXPORT
cmsSignalError(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *ErrorText
, ...)
512 char Buffer
[MAX_ERROR_MESSAGE_LEN
];
513 _cmsLogErrorChunkType
* lhg
;
516 va_start(args
, ErrorText
);
517 vsnprintf(Buffer
, MAX_ERROR_MESSAGE_LEN
-1, ErrorText
, args
);
520 // Check for the context, if specified go there. If not, go for the global
521 lhg
= (_cmsLogErrorChunkType
*) _cmsContextGetClientChunk(ContextID
, Logger
);
522 if (lhg
->LogErrorHandler
) {
523 lhg
->LogErrorHandler(ContextID
, ErrorCode
, Buffer
);
527 // Utility function to print signatures
528 void _cmsTagSignature2String(char String
[5], cmsTagSignature sig
)
532 // Convert to big endian
533 be
= _cmsAdjustEndianess32((cmsUInt32Number
) sig
);
536 memmove(String
, &be
, 4);
538 // Make sure of terminator
542 //--------------------------------------------------------------------------------------------------
546 void* defMtxCreate(cmsContext id
)
548 _cmsMutex
* ptr_mutex
= (_cmsMutex
*) _cmsMalloc(id
, sizeof(_cmsMutex
));
549 _cmsInitMutexPrimitive(ptr_mutex
);
550 return (void*) ptr_mutex
;
554 void defMtxDestroy(cmsContext id
, void* mtx
)
556 _cmsDestroyMutexPrimitive((_cmsMutex
*) mtx
);
561 cmsBool
defMtxLock(cmsContext id
, void* mtx
)
563 cmsUNUSED_PARAMETER(id
);
564 return _cmsLockPrimitive((_cmsMutex
*) mtx
) == 0;
568 void defMtxUnlock(cmsContext id
, void* mtx
)
570 cmsUNUSED_PARAMETER(id
);
571 _cmsUnlockPrimitive((_cmsMutex
*) mtx
);
576 // Pointers to memory manager functions in Context0
577 _cmsMutexPluginChunkType _cmsMutexPluginChunk
= { defMtxCreate
, defMtxDestroy
, defMtxLock
, defMtxUnlock
};
579 // Allocate and init mutex container.
580 void _cmsAllocMutexPluginChunk(struct _cmsContext_struct
* ctx
,
581 const struct _cmsContext_struct
* src
)
583 static _cmsMutexPluginChunkType MutexChunk
= {defMtxCreate
, defMtxDestroy
, defMtxLock
, defMtxUnlock
};
587 from
= src
->chunks
[MutexPlugin
];
593 ctx
->chunks
[MutexPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, from
, sizeof(_cmsMutexPluginChunkType
));
596 // Register new ways to transform
597 cmsBool
_cmsRegisterMutexPlugin(cmsContext ContextID
, cmsPluginBase
* Data
)
599 cmsPluginMutex
* Plugin
= (cmsPluginMutex
*) Data
;
600 _cmsMutexPluginChunkType
* ctx
= ( _cmsMutexPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MutexPlugin
);
605 ctx
->CreateMutexPtr
= NULL
;
606 ctx
->DestroyMutexPtr
= NULL
;
607 ctx
->LockMutexPtr
= NULL
;
608 ctx
->UnlockMutexPtr
= NULL
;
612 // Factory callback is required
613 if (Plugin
->CreateMutexPtr
== NULL
|| Plugin
->DestroyMutexPtr
== NULL
||
614 Plugin
->LockMutexPtr
== NULL
|| Plugin
->UnlockMutexPtr
== NULL
) return FALSE
;
616 ctx
->CreateMutexPtr
= Plugin
->CreateMutexPtr
;
617 ctx
->DestroyMutexPtr
= Plugin
->DestroyMutexPtr
;
618 ctx
->LockMutexPtr
= Plugin
->LockMutexPtr
;
619 ctx
->UnlockMutexPtr
= Plugin
->UnlockMutexPtr
;
626 void* CMSEXPORT
_cmsCreateMutex(cmsContext ContextID
)
628 _cmsMutexPluginChunkType
* ptr
= (_cmsMutexPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MutexPlugin
);
630 if (ptr
->CreateMutexPtr
== NULL
) return NULL
;
632 return ptr
->CreateMutexPtr(ContextID
);
635 void CMSEXPORT
_cmsDestroyMutex(cmsContext ContextID
, void* mtx
)
637 _cmsMutexPluginChunkType
* ptr
= (_cmsMutexPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MutexPlugin
);
639 if (ptr
->DestroyMutexPtr
!= NULL
) {
641 ptr
->DestroyMutexPtr(ContextID
, mtx
);
645 cmsBool CMSEXPORT
_cmsLockMutex(cmsContext ContextID
, void* mtx
)
647 _cmsMutexPluginChunkType
* ptr
= (_cmsMutexPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MutexPlugin
);
649 if (ptr
->LockMutexPtr
== NULL
) return TRUE
;
651 return ptr
->LockMutexPtr(ContextID
, mtx
);
654 void CMSEXPORT
_cmsUnlockMutex(cmsContext ContextID
, void* mtx
)
656 _cmsMutexPluginChunkType
* ptr
= (_cmsMutexPluginChunkType
*) _cmsContextGetClientChunk(ContextID
, MutexPlugin
);
658 if (ptr
->UnlockMutexPtr
!= NULL
) {
660 ptr
->UnlockMutexPtr(ContextID
, mtx
);
664 // The global Context0 storage for parallelization plug-in
665 _cmsParallelizationPluginChunkType _cmsParallelizationPluginChunk
= { 0 };
667 // Allocate parallelization container.
668 void _cmsAllocParallelizationPluginChunk(struct _cmsContext_struct
* ctx
,
669 const struct _cmsContext_struct
* src
)
672 void* from
= src
->chunks
[ParallelizationPlugin
];
673 ctx
->chunks
[ParallelizationPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, from
, sizeof(_cmsParallelizationPluginChunkType
));
676 _cmsParallelizationPluginChunkType ParallelizationPluginChunk
= { 0 };
677 ctx
->chunks
[ParallelizationPlugin
] = _cmsSubAllocDup(ctx
->MemPool
, &ParallelizationPluginChunk
, sizeof(_cmsParallelizationPluginChunkType
));
681 // Register parallel processing
682 cmsBool
_cmsRegisterParallelizationPlugin(cmsContext ContextID
, cmsPluginBase
* Data
)
684 cmsPluginParalellization
* Plugin
= (cmsPluginParalellization
*)Data
;
685 _cmsParallelizationPluginChunkType
* ctx
= (_cmsParallelizationPluginChunkType
*)_cmsContextGetClientChunk(ContextID
, ParallelizationPlugin
);
689 // No parallelization routines
691 ctx
->WorkerFlags
= 0;
692 ctx
->SchedulerFn
= NULL
;
696 // callback is required
697 if (Plugin
->SchedulerFn
== NULL
) return FALSE
;
699 ctx
->MaxWorkers
= Plugin
->MaxWorkers
;
700 ctx
->WorkerFlags
= Plugin
->WorkerFlags
;
701 ctx
->SchedulerFn
= Plugin
->SchedulerFn
;