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