/work/workdir/UnpackedTarball/lcms2/src/cmserr.c
Line | Count | Source (jump to first uncovered line) |
1 | | //--------------------------------------------------------------------------------- |
2 | | // |
3 | | // Little Color Management System |
4 | | // Copyright (c) 1998-2024 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 | | #include "lcms2_internal.h" |
27 | | |
28 | | |
29 | | // This function is here to help applications to prevent mixing lcms versions on header and shared objects. |
30 | | int CMSEXPORT cmsGetEncodedCMMversion(void) |
31 | 0 | { |
32 | 0 | return LCMS_VERSION; |
33 | 0 | } |
34 | | |
35 | | // I am so tired about incompatibilities on those functions that here are some replacements |
36 | | // that hopefully would be fully portable. |
37 | | |
38 | | // compare two strings ignoring case |
39 | | int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) |
40 | 0 | { |
41 | 0 | CMSREGISTER const unsigned char *us1 = (const unsigned char *)s1, |
42 | 0 | *us2 = (const unsigned char *)s2; |
43 | |
|
44 | 0 | while (toupper(*us1) == toupper(*us2++)) |
45 | 0 | if (*us1++ == '\0') |
46 | 0 | return 0; |
47 | | |
48 | 0 | return (toupper(*us1) - toupper(*--us2)); |
49 | 0 | } |
50 | | |
51 | | // long int because C99 specifies ftell in such way (7.19.9.2) |
52 | | long int CMSEXPORT cmsfilelength(FILE* f) |
53 | 0 | { |
54 | 0 | long int p , n; |
55 | |
|
56 | 0 | p = ftell(f); // register current file position |
57 | 0 | if (p == -1L) |
58 | 0 | return -1L; |
59 | | |
60 | 0 | if (fseek(f, 0, SEEK_END) != 0) { |
61 | 0 | return -1L; |
62 | 0 | } |
63 | | |
64 | 0 | n = ftell(f); |
65 | 0 | fseek(f, p, SEEK_SET); // file position restored |
66 | |
|
67 | 0 | return n; |
68 | 0 | } |
69 | | |
70 | | |
71 | | // Memory handling ------------------------------------------------------------------ |
72 | | // |
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 memory 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. |
77 | | |
78 | 0 | #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) |
79 | | |
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. |
85 | | |
86 | | cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin); |
87 | | |
88 | | // ********************************************************************************* |
89 | | |
90 | | // This is the default memory allocation function. It does a very coarse |
91 | | // check of amount of memory, just to prevent exploits |
92 | | static |
93 | | void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) |
94 | 0 | { |
95 | | // Never allow 0 or over maximum |
96 | 0 | if (size == 0 || size > MAX_MEMORY_FOR_ALLOC) return NULL; |
97 | | |
98 | 0 | return (void*) malloc(size); |
99 | | |
100 | 0 | cmsUNUSED_PARAMETER(ContextID); |
101 | 0 | } |
102 | | |
103 | | // Generic allocate & zero |
104 | | static |
105 | | void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size) |
106 | 0 | { |
107 | 0 | void *pt = _cmsMalloc(ContextID, size); |
108 | 0 | if (pt == NULL) return NULL; |
109 | | |
110 | 0 | memset(pt, 0, size); |
111 | 0 | return pt; |
112 | 0 | } |
113 | | |
114 | | |
115 | | // The default free function. The only check proformed is against NULL pointers |
116 | | static |
117 | | void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) |
118 | 0 | { |
119 | | // free(NULL) is defined a no-op by C99, therefore it is safe to |
120 | | // avoid the check, but it is here just in case... |
121 | |
|
122 | 0 | if (Ptr) free(Ptr); |
123 | |
|
124 | 0 | cmsUNUSED_PARAMETER(ContextID); |
125 | 0 | } |
126 | | |
127 | | // The default realloc function. Again it checks for exploits. If Ptr is NULL, |
128 | | // realloc behaves the same way as malloc and allocates a new block of size bytes. |
129 | | static |
130 | | void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) |
131 | 0 | { |
132 | |
|
133 | 0 | if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb |
134 | | |
135 | 0 | return realloc(Ptr, size); |
136 | | |
137 | 0 | cmsUNUSED_PARAMETER(ContextID); |
138 | 0 | } |
139 | | |
140 | | |
141 | | // The default calloc function. Allocates an array of num elements, each one of size bytes |
142 | | // all memory is initialized to zero. |
143 | | static |
144 | | void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) |
145 | 0 | { |
146 | 0 | cmsUInt32Number Total = num * size; |
147 | | |
148 | | // Preserve calloc behaviour |
149 | 0 | if (Total == 0) return NULL; |
150 | | |
151 | | // Safe check for overflow. |
152 | 0 | if (num >= UINT_MAX / size) return NULL; |
153 | | |
154 | | // Check for overflow |
155 | 0 | if (Total < num || Total < size) { |
156 | 0 | return NULL; |
157 | 0 | } |
158 | | |
159 | 0 | if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb |
160 | | |
161 | 0 | return _cmsMallocZero(ContextID, Total); |
162 | 0 | } |
163 | | |
164 | | // Generic block duplication |
165 | | static |
166 | | void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) |
167 | 0 | { |
168 | 0 | void* mem; |
169 | |
|
170 | 0 | if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb |
171 | | |
172 | 0 | mem = _cmsMalloc(ContextID, size); |
173 | |
|
174 | 0 | if (mem != NULL && Org != NULL) |
175 | 0 | memmove(mem, Org, size); |
176 | |
|
177 | 0 | return mem; |
178 | 0 | } |
179 | | |
180 | | |
181 | | // Pointers to memory manager functions in Context0 |
182 | | _cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, |
183 | | _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn |
184 | | }; |
185 | | |
186 | | |
187 | | // Reset and duplicate memory manager |
188 | | void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) |
189 | 0 | { |
190 | 0 | _cmsAssert(ctx != NULL); |
191 | | |
192 | 0 | if (src != NULL) { |
193 | | |
194 | | // Duplicate |
195 | 0 | ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); |
196 | 0 | } |
197 | 0 | else { |
198 | | |
199 | | // To reset it, we use the default allocators, which cannot be overridden |
200 | 0 | ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | | // Auxiliary to fill memory management functions from plugin (or context 0 defaults) |
205 | | void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) |
206 | 0 | { |
207 | 0 | if (Plugin == NULL) { |
208 | |
|
209 | 0 | memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); |
210 | 0 | } |
211 | 0 | else { |
212 | |
|
213 | 0 | ptr ->MallocPtr = Plugin -> MallocPtr; |
214 | 0 | ptr ->FreePtr = Plugin -> FreePtr; |
215 | 0 | ptr ->ReallocPtr = Plugin -> ReallocPtr; |
216 | | |
217 | | // Make sure we revert to defaults |
218 | 0 | ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; |
219 | 0 | ptr ->CallocPtr = _cmsCallocDefaultFn; |
220 | 0 | ptr ->DupPtr = _cmsDupDefaultFn; |
221 | | |
222 | 0 | if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; |
223 | 0 | if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; |
224 | 0 | if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; |
225 | | |
226 | 0 | } |
227 | 0 | } |
228 | | |
229 | | |
230 | | // Plug-in replacement entry |
231 | | cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) |
232 | 0 | { |
233 | 0 | cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; |
234 | 0 | _cmsMemPluginChunkType* ptr; |
235 | | |
236 | | // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. |
237 | | // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the |
238 | | // context internal data should be malloc'ed by using those functions. |
239 | 0 | if (Data == NULL) { |
240 | |
|
241 | 0 | struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; |
242 | | |
243 | | // Return to the default allocators |
244 | 0 | if (ContextID != NULL) { |
245 | 0 | ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; |
246 | 0 | } |
247 | 0 | return TRUE; |
248 | 0 | } |
249 | | |
250 | | // Check for required callbacks |
251 | 0 | if (Plugin -> MallocPtr == NULL || |
252 | 0 | Plugin -> FreePtr == NULL || |
253 | 0 | Plugin -> ReallocPtr == NULL) return FALSE; |
254 | | |
255 | | // Set replacement functions |
256 | 0 | ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
257 | 0 | if (ptr == NULL) |
258 | 0 | return FALSE; |
259 | | |
260 | 0 | _cmsInstallAllocFunctions(Plugin, ptr); |
261 | 0 | return TRUE; |
262 | 0 | } |
263 | | |
264 | | // Generic allocate |
265 | | void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) |
266 | 0 | { |
267 | 0 | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
268 | 0 | return ptr ->MallocPtr(ContextID, size); |
269 | 0 | } |
270 | | |
271 | | // Generic allocate & zero |
272 | | void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) |
273 | 0 | { |
274 | 0 | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
275 | 0 | return ptr->MallocZeroPtr(ContextID, size); |
276 | 0 | } |
277 | | |
278 | | // Generic calloc |
279 | | void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) |
280 | 0 | { |
281 | 0 | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
282 | 0 | return ptr->CallocPtr(ContextID, num, size); |
283 | 0 | } |
284 | | |
285 | | // Generic reallocate |
286 | | void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) |
287 | 0 | { |
288 | 0 | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
289 | 0 | return ptr->ReallocPtr(ContextID, Ptr, size); |
290 | 0 | } |
291 | | |
292 | | // Generic free memory |
293 | | void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) |
294 | 0 | { |
295 | 0 | if (Ptr != NULL) { |
296 | 0 | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
297 | 0 | ptr ->FreePtr(ContextID, Ptr); |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | | // Generic block duplication |
302 | | void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) |
303 | 0 | { |
304 | 0 | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
305 | 0 | return ptr ->DupPtr(ContextID, Org, size); |
306 | 0 | } |
307 | | |
308 | | // ******************************************************************************************** |
309 | | |
310 | | // Sub allocation takes care of many pointers of small size. The memory allocated in |
311 | | // this way have be freed at once. Next function allocates a single chunk for linked list |
312 | | // I prefer this method over realloc due to the big impact on xput realloc may have if |
313 | | // memory is being swapped to disk. This approach is safer (although that may not be true on all platforms) |
314 | | static |
315 | | _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) |
316 | 0 | { |
317 | 0 | _cmsSubAllocator_chunk* chunk; |
318 | | |
319 | | // 20K by default |
320 | 0 | if (Initial == 0) |
321 | 0 | Initial = 20*1024; |
322 | | |
323 | | // Create the container |
324 | 0 | chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk)); |
325 | 0 | if (chunk == NULL) return NULL; |
326 | | |
327 | | // Initialize values |
328 | 0 | chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial); |
329 | 0 | if (chunk ->Block == NULL) { |
330 | | |
331 | | // Something went wrong |
332 | 0 | _cmsFree(ContextID, chunk); |
333 | 0 | return NULL; |
334 | 0 | } |
335 | | |
336 | 0 | chunk ->BlockSize = Initial; |
337 | 0 | chunk ->Used = 0; |
338 | 0 | chunk ->next = NULL; |
339 | |
|
340 | 0 | return chunk; |
341 | 0 | } |
342 | | |
343 | | // The suballocated is nothing but a pointer to the first element in the list. We also keep |
344 | | // the thread ID in this structure. |
345 | | _cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial) |
346 | 0 | { |
347 | 0 | _cmsSubAllocator* sub; |
348 | | |
349 | | // Create the container |
350 | 0 | sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator)); |
351 | 0 | if (sub == NULL) return NULL; |
352 | | |
353 | 0 | sub ->ContextID = ContextID; |
354 | |
|
355 | 0 | sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial); |
356 | 0 | if (sub ->h == NULL) { |
357 | 0 | _cmsFree(ContextID, sub); |
358 | 0 | return NULL; |
359 | 0 | } |
360 | | |
361 | 0 | return sub; |
362 | 0 | } |
363 | | |
364 | | |
365 | | // Get rid of whole linked list |
366 | | void _cmsSubAllocDestroy(_cmsSubAllocator* sub) |
367 | 0 | { |
368 | 0 | _cmsSubAllocator_chunk *chunk, *n; |
369 | |
|
370 | 0 | for (chunk = sub ->h; chunk != NULL; chunk = n) { |
371 | |
|
372 | 0 | n = chunk->next; |
373 | 0 | if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block); |
374 | 0 | _cmsFree(sub ->ContextID, chunk); |
375 | 0 | } |
376 | | |
377 | | // Free the header |
378 | 0 | _cmsFree(sub ->ContextID, sub); |
379 | 0 | } |
380 | | |
381 | | |
382 | | // Get a pointer to small memory block. |
383 | | void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) |
384 | 0 | { |
385 | 0 | cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used; |
386 | 0 | cmsUInt8Number* ptr; |
387 | |
|
388 | 0 | size = _cmsALIGNMEM(size); |
389 | | |
390 | | // Check for memory. If there is no room, allocate a new chunk of double memory size. |
391 | 0 | if (size > Free) { |
392 | |
|
393 | 0 | _cmsSubAllocator_chunk* chunk; |
394 | 0 | cmsUInt32Number newSize; |
395 | |
|
396 | 0 | newSize = sub -> h ->BlockSize * 2; |
397 | 0 | if (newSize < size) newSize = size; |
398 | |
|
399 | 0 | chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize); |
400 | 0 | if (chunk == NULL) return NULL; |
401 | | |
402 | | // Link list |
403 | 0 | chunk ->next = sub ->h; |
404 | 0 | sub ->h = chunk; |
405 | |
|
406 | 0 | } |
407 | | |
408 | 0 | ptr = sub -> h ->Block + sub -> h ->Used; |
409 | 0 | sub -> h -> Used += size; |
410 | |
|
411 | 0 | return (void*) ptr; |
412 | 0 | } |
413 | | |
414 | | // Duplicate in pool |
415 | | void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) |
416 | 0 | { |
417 | 0 | void *NewPtr; |
418 | | |
419 | | // Dup of null pointer is also NULL |
420 | 0 | if (ptr == NULL) |
421 | 0 | return NULL; |
422 | | |
423 | 0 | NewPtr = _cmsSubAlloc(s, size); |
424 | |
|
425 | 0 | if (ptr != NULL && NewPtr != NULL) { |
426 | 0 | memcpy(NewPtr, ptr, size); |
427 | 0 | } |
428 | |
|
429 | 0 | return NewPtr; |
430 | 0 | } |
431 | | |
432 | | |
433 | | |
434 | | // Error logging ****************************************************************** |
435 | | |
436 | | // There is no error handling at all. When a function fails, it returns proper value. |
437 | | // For example, all create functions does return NULL on failure. Other return FALSE |
438 | | // It may be interesting, for the developer, to know why the function is failing. |
439 | | // for that reason, lcms2 does offer a logging function. This function does receive |
440 | | // a ENGLISH string with some clues on what is going wrong. You can show this |
441 | | // info to the end user, or just create some sort of log. |
442 | | // The logging function should NOT terminate the program, as this obviously can leave |
443 | | // resources. It is the programmer's responsibility to check each function return code |
444 | | // to make sure it didn't fail. |
445 | | |
446 | | // Error messages are limited to MAX_ERROR_MESSAGE_LEN |
447 | | |
448 | 0 | #define MAX_ERROR_MESSAGE_LEN 1024 |
449 | | |
450 | | // --------------------------------------------------------------------------------------------------------- |
451 | | |
452 | | // This is our default log error |
453 | | static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); |
454 | | |
455 | | // Context0 storage, which is global |
456 | | _cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; |
457 | | |
458 | | // Allocates and inits error logger container for a given context. If src is NULL, only initializes the value |
459 | | // to the default. Otherwise, it duplicates the value. The interface is standard across all context clients |
460 | | void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx, |
461 | | const struct _cmsContext_struct* src) |
462 | 0 | { |
463 | 0 | static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; |
464 | 0 | void* from; |
465 | | |
466 | 0 | if (src != NULL) { |
467 | 0 | from = src ->chunks[Logger]; |
468 | 0 | } |
469 | 0 | else { |
470 | 0 | from = &LogErrorChunk; |
471 | 0 | } |
472 | | |
473 | 0 | ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); |
474 | 0 | } |
475 | | |
476 | | // The default error logger does nothing. |
477 | | static |
478 | | void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text) |
479 | 0 | { |
480 | | // fprintf(stderr, "[lcms]: %s\n", Text); |
481 | | // fflush(stderr); |
482 | |
|
483 | 0 | cmsUNUSED_PARAMETER(ContextID); |
484 | 0 | cmsUNUSED_PARAMETER(ErrorCode); |
485 | 0 | cmsUNUSED_PARAMETER(Text); |
486 | 0 | } |
487 | | |
488 | | // Change log error, context based |
489 | | void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) |
490 | 0 | { |
491 | 0 | _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); |
492 | |
|
493 | 0 | if (lhg != NULL) { |
494 | |
|
495 | 0 | if (Fn == NULL) |
496 | 0 | lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; |
497 | 0 | else |
498 | 0 | lhg -> LogErrorHandler = Fn; |
499 | 0 | } |
500 | 0 | } |
501 | | |
502 | | // Change log error, legacy |
503 | | void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn) |
504 | 0 | { |
505 | 0 | cmsSetLogErrorHandlerTHR(NULL, Fn); |
506 | 0 | } |
507 | | |
508 | | // Log an error |
509 | | // ErrorText is a text holding an english description of error. |
510 | | void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...) |
511 | 0 | { |
512 | 0 | va_list args; |
513 | 0 | char Buffer[MAX_ERROR_MESSAGE_LEN]; |
514 | 0 | _cmsLogErrorChunkType* lhg; |
515 | | |
516 | |
|
517 | 0 | va_start(args, ErrorText); |
518 | 0 | vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); |
519 | 0 | va_end(args); |
520 | | |
521 | | // Check for the context, if specified go there. If not, go for the global |
522 | 0 | lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); |
523 | 0 | if (lhg ->LogErrorHandler) { |
524 | 0 | lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); |
525 | 0 | } |
526 | 0 | } |
527 | | |
528 | | // Utility function to print signatures |
529 | | void _cmsTagSignature2String(char String[5], cmsTagSignature sig) |
530 | 0 | { |
531 | 0 | cmsUInt32Number be; |
532 | | |
533 | | // Convert to big endian |
534 | 0 | be = _cmsAdjustEndianess32((cmsUInt32Number) sig); |
535 | | |
536 | | // Move chars |
537 | 0 | memmove(String, &be, 4); |
538 | | |
539 | | // Make sure of terminator |
540 | 0 | String[4] = 0; |
541 | 0 | } |
542 | | |
543 | | //-------------------------------------------------------------------------------------------------- |
544 | | |
545 | | |
546 | | static |
547 | | void* defMtxCreate(cmsContext id) |
548 | 0 | { |
549 | 0 | _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); |
550 | 0 | _cmsInitMutexPrimitive(ptr_mutex); |
551 | 0 | return (void*) ptr_mutex; |
552 | 0 | } |
553 | | |
554 | | static |
555 | | void defMtxDestroy(cmsContext id, void* mtx) |
556 | 0 | { |
557 | 0 | _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); |
558 | 0 | _cmsFree(id, mtx); |
559 | 0 | } |
560 | | |
561 | | static |
562 | | cmsBool defMtxLock(cmsContext id, void* mtx) |
563 | 0 | { |
564 | 0 | cmsUNUSED_PARAMETER(id); |
565 | 0 | return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; |
566 | 0 | } |
567 | | |
568 | | static |
569 | | void defMtxUnlock(cmsContext id, void* mtx) |
570 | 0 | { |
571 | 0 | cmsUNUSED_PARAMETER(id); |
572 | 0 | _cmsUnlockPrimitive((_cmsMutex *) mtx); |
573 | 0 | } |
574 | | |
575 | | |
576 | | |
577 | | // Pointers to memory manager functions in Context0 |
578 | | _cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; |
579 | | |
580 | | // Allocate and init mutex container. |
581 | | void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, |
582 | | const struct _cmsContext_struct* src) |
583 | 0 | { |
584 | 0 | static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; |
585 | 0 | void* from; |
586 | | |
587 | 0 | if (src != NULL) { |
588 | 0 | from = src ->chunks[MutexPlugin]; |
589 | 0 | } |
590 | 0 | else { |
591 | 0 | from = &MutexChunk; |
592 | 0 | } |
593 | | |
594 | 0 | ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); |
595 | 0 | } |
596 | | |
597 | | // Register new ways to transform |
598 | | cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) |
599 | 0 | { |
600 | 0 | cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; |
601 | 0 | _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
602 | |
|
603 | 0 | if (Data == NULL) { |
604 | | |
605 | | // No lock routines |
606 | 0 | ctx->CreateMutexPtr = NULL; |
607 | 0 | ctx->DestroyMutexPtr = NULL; |
608 | 0 | ctx->LockMutexPtr = NULL; |
609 | 0 | ctx ->UnlockMutexPtr = NULL; |
610 | 0 | return TRUE; |
611 | 0 | } |
612 | | |
613 | | // Factory callback is required |
614 | 0 | if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || |
615 | 0 | Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; |
616 | | |
617 | 0 | ctx->CreateMutexPtr = Plugin->CreateMutexPtr; |
618 | 0 | ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; |
619 | 0 | ctx ->LockMutexPtr = Plugin ->LockMutexPtr; |
620 | 0 | ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; |
621 | | |
622 | | // All is ok |
623 | 0 | return TRUE; |
624 | 0 | } |
625 | | |
626 | | // Generic Mutex fns |
627 | | void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) |
628 | 0 | { |
629 | 0 | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
630 | |
|
631 | 0 | if (ptr ->CreateMutexPtr == NULL) return NULL; |
632 | | |
633 | 0 | return ptr ->CreateMutexPtr(ContextID); |
634 | 0 | } |
635 | | |
636 | | void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) |
637 | 0 | { |
638 | 0 | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
639 | |
|
640 | 0 | if (ptr ->DestroyMutexPtr != NULL) { |
641 | |
|
642 | 0 | ptr ->DestroyMutexPtr(ContextID, mtx); |
643 | 0 | } |
644 | 0 | } |
645 | | |
646 | | cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) |
647 | 0 | { |
648 | 0 | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
649 | |
|
650 | 0 | if (ptr ->LockMutexPtr == NULL) return TRUE; |
651 | | |
652 | 0 | return ptr ->LockMutexPtr(ContextID, mtx); |
653 | 0 | } |
654 | | |
655 | | void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) |
656 | 0 | { |
657 | 0 | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
658 | |
|
659 | 0 | if (ptr ->UnlockMutexPtr != NULL) { |
660 | |
|
661 | 0 | ptr ->UnlockMutexPtr(ContextID, mtx); |
662 | 0 | } |
663 | 0 | } |
664 | | |
665 | | // The global Context0 storage for parallelization plug-in |
666 | | _cmsParallelizationPluginChunkType _cmsParallelizationPluginChunk = { 0 }; |
667 | | |
668 | | // Allocate parallelization container. |
669 | | void _cmsAllocParallelizationPluginChunk(struct _cmsContext_struct* ctx, |
670 | | const struct _cmsContext_struct* src) |
671 | 0 | { |
672 | 0 | if (src != NULL) { |
673 | 0 | void* from = src->chunks[ParallelizationPlugin]; |
674 | 0 | ctx->chunks[ParallelizationPlugin] = _cmsSubAllocDup(ctx->MemPool, from, sizeof(_cmsParallelizationPluginChunkType)); |
675 | 0 | } |
676 | 0 | else { |
677 | 0 | _cmsParallelizationPluginChunkType ParallelizationPluginChunk = { 0 }; |
678 | 0 | ctx->chunks[ParallelizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &ParallelizationPluginChunk, sizeof(_cmsParallelizationPluginChunkType)); |
679 | 0 | } |
680 | 0 | } |
681 | | |
682 | | // Register parallel processing |
683 | | cmsBool _cmsRegisterParallelizationPlugin(cmsContext ContextID, cmsPluginBase* Data) |
684 | 0 | { |
685 | 0 | cmsPluginParalellization* Plugin = (cmsPluginParalellization*)Data; |
686 | 0 | _cmsParallelizationPluginChunkType* ctx = (_cmsParallelizationPluginChunkType*)_cmsContextGetClientChunk(ContextID, ParallelizationPlugin); |
687 | |
|
688 | 0 | if (Data == NULL) { |
689 | | |
690 | | // No parallelization routines |
691 | 0 | ctx->MaxWorkers = 0; |
692 | 0 | ctx->WorkerFlags = 0; |
693 | 0 | ctx->SchedulerFn = NULL; |
694 | 0 | return TRUE; |
695 | 0 | } |
696 | | |
697 | | // callback is required |
698 | 0 | if (Plugin->SchedulerFn == NULL) return FALSE; |
699 | | |
700 | 0 | ctx->MaxWorkers = Plugin->MaxWorkers; |
701 | 0 | ctx->WorkerFlags = Plugin->WorkerFlags; |
702 | 0 | ctx->SchedulerFn = Plugin->SchedulerFn; |
703 | | |
704 | | // All is ok |
705 | 0 | return TRUE; |
706 | 0 | } |
707 | | |