/src/ghostpdl/lcms2mt/src/cmserr.c
Line | Count | Source |
1 | | //--------------------------------------------------------------------------------- |
2 | | // |
3 | | // Little Color Management System |
4 | | // Copyright (c) 1998-2020 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 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. |
77 | | |
78 | 69.6M | #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 writter 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 | 192k | { |
95 | 192k | if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum |
96 | | |
97 | 192k | return (void*) malloc(size); |
98 | | |
99 | 0 | cmsUNUSED_PARAMETER(ContextID); |
100 | 0 | } |
101 | | |
102 | | // Generic allocate & zero |
103 | | static |
104 | | void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size) |
105 | 162M | { |
106 | 162M | void *pt = _cmsMalloc(ContextID, size); |
107 | 162M | if (pt == NULL) return NULL; |
108 | | |
109 | 162M | memset(pt, 0, size); |
110 | 162M | return pt; |
111 | 162M | } |
112 | | |
113 | | |
114 | | // The default free function. The only check proformed is against NULL pointers |
115 | | static |
116 | | void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr) |
117 | 192k | { |
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... |
120 | | |
121 | 192k | if (Ptr) free(Ptr); |
122 | | |
123 | 192k | cmsUNUSED_PARAMETER(ContextID); |
124 | 192k | } |
125 | | |
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. |
128 | | static |
129 | | void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size) |
130 | 0 | { |
131 | |
|
132 | 0 | if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb |
133 | | |
134 | 0 | return realloc(Ptr, size); |
135 | | |
136 | 0 | cmsUNUSED_PARAMETER(ContextID); |
137 | 0 | } |
138 | | |
139 | | |
140 | | // The default calloc function. Allocates an array of num elements, each one of size bytes |
141 | | // all memory is initialized to zero. |
142 | | static |
143 | | void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) |
144 | 60.2M | { |
145 | 60.2M | cmsUInt32Number Total = num * size; |
146 | | |
147 | | // Preserve calloc behaviour |
148 | 60.2M | if (Total == 0) return NULL; |
149 | | |
150 | | // Safe check for overflow. |
151 | 60.2M | if (num >= UINT_MAX / size) return NULL; |
152 | | |
153 | | // Check for overflow |
154 | 60.2M | if (Total < num || Total < size) { |
155 | 0 | return NULL; |
156 | 0 | } |
157 | | |
158 | 60.2M | if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb |
159 | | |
160 | 60.2M | return _cmsMallocZero(ContextID, Total); |
161 | 60.2M | } |
162 | | |
163 | | // Generic block duplication |
164 | | static |
165 | | void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size) |
166 | 9.26M | { |
167 | 9.26M | void* mem; |
168 | | |
169 | 9.26M | if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb |
170 | | |
171 | 9.26M | mem = _cmsMalloc(ContextID, size); |
172 | | |
173 | 9.26M | if (mem != NULL && Org != NULL) |
174 | 9.26M | memmove(mem, Org, size); |
175 | | |
176 | 9.26M | return mem; |
177 | 9.26M | } |
178 | | |
179 | | |
180 | | // Pointers to memory manager functions in Context0 |
181 | | _cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn, |
182 | | _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn |
183 | | }; |
184 | | |
185 | | |
186 | | // Reset and duplicate memory manager |
187 | | void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src) |
188 | 192k | { |
189 | 192k | _cmsAssert(ctx != NULL); |
190 | | |
191 | 192k | if (src != NULL) { |
192 | | |
193 | | // Duplicate |
194 | 0 | ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType)); |
195 | 0 | } |
196 | 192k | else { |
197 | | |
198 | | // To reset it, we use the default allocators, which cannot be overridden |
199 | 192k | ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager; |
200 | 192k | } |
201 | 192k | } |
202 | | |
203 | | // Auxiliary to fill memory management functions from plugin (or context 0 defaults) |
204 | | void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr) |
205 | 385k | { |
206 | 385k | if (Plugin == NULL) { |
207 | |
|
208 | 0 | memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk)); |
209 | 0 | } |
210 | 385k | else { |
211 | | |
212 | 385k | ptr ->MallocPtr = Plugin -> MallocPtr; |
213 | 385k | ptr ->FreePtr = Plugin -> FreePtr; |
214 | 385k | ptr ->ReallocPtr = Plugin -> ReallocPtr; |
215 | | |
216 | | // Make sure we revert to defaults |
217 | 385k | ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn; |
218 | 385k | ptr ->CallocPtr = _cmsCallocDefaultFn; |
219 | 385k | ptr ->DupPtr = _cmsDupDefaultFn; |
220 | | |
221 | 385k | if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr; |
222 | 385k | if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr; |
223 | 385k | if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr; |
224 | | |
225 | 385k | } |
226 | 385k | } |
227 | | |
228 | | |
229 | | // Plug-in replacement entry |
230 | | cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) |
231 | 385k | { |
232 | 385k | cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data; |
233 | 385k | _cmsMemPluginChunkType* ptr; |
234 | | |
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. |
238 | 385k | if (Data == NULL) { |
239 | | |
240 | 192k | struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; |
241 | | |
242 | | // Return to the default allocators |
243 | 192k | if (ContextID != NULL) { |
244 | 192k | ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager; |
245 | 192k | } |
246 | 192k | return TRUE; |
247 | 192k | } |
248 | | |
249 | | // Check for required callbacks |
250 | 192k | if (Plugin -> MallocPtr == NULL || |
251 | 192k | Plugin -> FreePtr == NULL || |
252 | 192k | Plugin -> ReallocPtr == NULL) return FALSE; |
253 | | |
254 | | // Set replacement functions |
255 | 192k | ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
256 | 192k | if (ptr == NULL) |
257 | 0 | return FALSE; |
258 | | |
259 | 192k | _cmsInstallAllocFunctions(Plugin, ptr); |
260 | 192k | return TRUE; |
261 | 192k | } |
262 | | |
263 | | // Generic allocate |
264 | | void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size) |
265 | 179M | { |
266 | 179M | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
267 | 179M | return ptr ->MallocPtr(ContextID, size); |
268 | 179M | } |
269 | | |
270 | | // Generic allocate & zero |
271 | | void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size) |
272 | 162M | { |
273 | 162M | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
274 | 162M | return ptr->MallocZeroPtr(ContextID, size); |
275 | 162M | } |
276 | | |
277 | | // Generic calloc |
278 | | void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size) |
279 | 60.2M | { |
280 | 60.2M | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
281 | 60.2M | return ptr->CallocPtr(ContextID, num, size); |
282 | 60.2M | } |
283 | | |
284 | | // Generic reallocate |
285 | | void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size) |
286 | 6.60M | { |
287 | 6.60M | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
288 | 6.60M | return ptr->ReallocPtr(ContextID, Ptr, size); |
289 | 6.60M | } |
290 | | |
291 | | // Generic free memory |
292 | | void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr) |
293 | 186M | { |
294 | 186M | if (Ptr != NULL) { |
295 | 186M | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
296 | 186M | ptr ->FreePtr(ContextID, Ptr); |
297 | 186M | } |
298 | 186M | } |
299 | | |
300 | | // Generic block duplication |
301 | | void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size) |
302 | 9.26M | { |
303 | 9.26M | _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin); |
304 | 9.26M | return ptr ->DupPtr(ContextID, Org, size); |
305 | 9.26M | } |
306 | | |
307 | | // ******************************************************************************************** |
308 | | |
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 inpact 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) |
313 | | static |
314 | | _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) |
315 | 192k | { |
316 | 192k | _cmsSubAllocator_chunk* chunk; |
317 | | |
318 | | // 20K by default |
319 | 192k | if (Initial == 0) |
320 | 0 | Initial = 20*1024; |
321 | | |
322 | | // Create the container |
323 | 192k | chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk)); |
324 | 192k | if (chunk == NULL) return NULL; |
325 | | |
326 | | // Initialize values |
327 | 192k | chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial); |
328 | 192k | if (chunk ->Block == NULL) { |
329 | | |
330 | | // Something went wrong |
331 | 0 | _cmsFree(ContextID, chunk); |
332 | 0 | return NULL; |
333 | 0 | } |
334 | | |
335 | 192k | chunk ->BlockSize = Initial; |
336 | 192k | chunk ->Used = 0; |
337 | 192k | chunk ->next = NULL; |
338 | | |
339 | 192k | return chunk; |
340 | 192k | } |
341 | | |
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) |
345 | 192k | { |
346 | 192k | _cmsSubAllocator* sub; |
347 | | |
348 | | // Create the container |
349 | 192k | sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator)); |
350 | 192k | if (sub == NULL) return NULL; |
351 | | |
352 | 192k | sub ->ContextID = ContextID; |
353 | | |
354 | 192k | sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial); |
355 | 192k | if (sub ->h == NULL) { |
356 | 0 | _cmsFree(ContextID, sub); |
357 | 0 | return NULL; |
358 | 0 | } |
359 | | |
360 | 192k | return sub; |
361 | 192k | } |
362 | | |
363 | | |
364 | | // Get rid of whole linked list |
365 | | void _cmsSubAllocDestroy(_cmsSubAllocator* sub) |
366 | 192k | { |
367 | 192k | _cmsSubAllocator_chunk *chunk, *n; |
368 | | |
369 | 385k | for (chunk = sub ->h; chunk != NULL; chunk = n) { |
370 | | |
371 | 192k | n = chunk->next; |
372 | 192k | if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block); |
373 | 192k | _cmsFree(sub ->ContextID, chunk); |
374 | 192k | } |
375 | | |
376 | | // Free the header |
377 | 192k | _cmsFree(sub ->ContextID, sub); |
378 | 192k | } |
379 | | |
380 | | |
381 | | // Get a pointer to small memory block. |
382 | | void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) |
383 | 2.50M | { |
384 | 2.50M | cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used; |
385 | 2.50M | cmsUInt8Number* ptr; |
386 | | |
387 | 2.50M | size = _cmsALIGNMEM(size); |
388 | | |
389 | | // Check for memory. If there is no room, allocate a new chunk of double memory size. |
390 | 2.50M | if (size > Free) { |
391 | |
|
392 | 0 | _cmsSubAllocator_chunk* chunk; |
393 | 0 | cmsUInt32Number newSize; |
394 | |
|
395 | 0 | newSize = sub -> h ->BlockSize * 2; |
396 | 0 | if (newSize < size) newSize = size; |
397 | |
|
398 | 0 | chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize); |
399 | 0 | if (chunk == NULL) return NULL; |
400 | | |
401 | | // Link list |
402 | 0 | chunk ->next = sub ->h; |
403 | 0 | sub ->h = chunk; |
404 | |
|
405 | 0 | } |
406 | | |
407 | 2.50M | ptr = sub -> h ->Block + sub -> h ->Used; |
408 | 2.50M | sub -> h -> Used += size; |
409 | | |
410 | 2.50M | return (void*) ptr; |
411 | 2.50M | } |
412 | | |
413 | | // Duplicate in pool |
414 | | void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size) |
415 | 2.50M | { |
416 | 2.50M | void *NewPtr; |
417 | | |
418 | | // Dup of null pointer is also NULL |
419 | 2.50M | if (ptr == NULL) |
420 | 0 | return NULL; |
421 | | |
422 | 2.50M | NewPtr = _cmsSubAlloc(s, size); |
423 | | |
424 | 2.50M | if (ptr != NULL && NewPtr != NULL) { |
425 | 2.50M | memcpy(NewPtr, ptr, size); |
426 | 2.50M | } |
427 | | |
428 | 2.50M | return NewPtr; |
429 | 2.50M | } |
430 | | |
431 | | |
432 | | |
433 | | // Error logging ****************************************************************** |
434 | | |
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. |
444 | | |
445 | | // Error messages are limited to MAX_ERROR_MESSAGE_LEN |
446 | | |
447 | 1.97M | #define MAX_ERROR_MESSAGE_LEN 1024 |
448 | | |
449 | | // --------------------------------------------------------------------------------------------------------- |
450 | | |
451 | | // This is our default log error |
452 | | static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text); |
453 | | |
454 | | // Context0 storage, which is global |
455 | | _cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction }; |
456 | | |
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) |
461 | 192k | { |
462 | 192k | static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction }; |
463 | 192k | void* from; |
464 | | |
465 | 192k | if (src != NULL) { |
466 | 0 | from = src ->chunks[Logger]; |
467 | 0 | } |
468 | 192k | else { |
469 | 192k | from = &LogErrorChunk; |
470 | 192k | } |
471 | | |
472 | 192k | ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType)); |
473 | 192k | } |
474 | | |
475 | | // The default error logger does nothing. |
476 | | static |
477 | | void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text) |
478 | 0 | { |
479 | | // fprintf(stderr, "[lcms]: %s\n", Text); |
480 | | // fflush(stderr); |
481 | |
|
482 | 0 | cmsUNUSED_PARAMETER(ContextID); |
483 | 0 | cmsUNUSED_PARAMETER(ErrorCode); |
484 | 0 | cmsUNUSED_PARAMETER(Text); |
485 | 0 | } |
486 | | |
487 | | // Change log error, context based |
488 | | void CMSEXPORT cmsSetLogErrorHandler(cmsContext ContextID, cmsLogErrorHandlerFunction Fn) |
489 | 1.11M | { |
490 | 1.11M | _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); |
491 | | |
492 | 1.11M | if (lhg != NULL) { |
493 | | |
494 | 1.11M | if (Fn == NULL) |
495 | 0 | lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction; |
496 | 1.11M | else |
497 | 1.11M | lhg -> LogErrorHandler = Fn; |
498 | 1.11M | } |
499 | 1.11M | } |
500 | | |
501 | | // Log an error |
502 | | // ErrorText is a text holding an english description of error. |
503 | | void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...) |
504 | 1.97M | { |
505 | 1.97M | va_list args; |
506 | 1.97M | char Buffer[MAX_ERROR_MESSAGE_LEN]; |
507 | 1.97M | _cmsLogErrorChunkType* lhg; |
508 | | |
509 | | |
510 | 1.97M | va_start(args, ErrorText); |
511 | 1.97M | vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args); |
512 | 1.97M | va_end(args); |
513 | | |
514 | | // Check for the context, if specified go there. If not, go for the global |
515 | 1.97M | lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger); |
516 | 1.97M | if (lhg ->LogErrorHandler) { |
517 | 1.97M | lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer); |
518 | 1.97M | } |
519 | 1.97M | } |
520 | | |
521 | | // Utility function to print signatures |
522 | | void _cmsTagSignature2String(char String[5], cmsTagSignature sig) |
523 | 210k | { |
524 | 210k | cmsUInt32Number be; |
525 | | |
526 | | // Convert to big endian |
527 | 210k | be = _cmsAdjustEndianess32((cmsUInt32Number) sig); |
528 | | |
529 | | // Move chars |
530 | 210k | memmove(String, &be, 4); |
531 | | |
532 | | // Make sure of terminator |
533 | 210k | String[4] = 0; |
534 | 210k | } |
535 | | |
536 | | //-------------------------------------------------------------------------------------------------- |
537 | | |
538 | | |
539 | | static |
540 | | void* defMtxCreate(cmsContext id) |
541 | 0 | { |
542 | 0 | _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex)); |
543 | 0 | if (ptr_mutex != NULL) |
544 | 0 | _cmsInitMutexPrimitive(ptr_mutex); |
545 | 0 | return (void*) ptr_mutex; |
546 | 0 | } |
547 | | |
548 | | static |
549 | | void defMtxDestroy(cmsContext id, void* mtx) |
550 | 0 | { |
551 | 0 | _cmsDestroyMutexPrimitive((_cmsMutex *) mtx); |
552 | 0 | _cmsFree(id, mtx); |
553 | 0 | } |
554 | | |
555 | | static |
556 | | cmsBool defMtxLock(cmsContext id, void* mtx) |
557 | 0 | { |
558 | 0 | cmsUNUSED_PARAMETER(id); |
559 | 0 | return _cmsLockPrimitive((_cmsMutex *) mtx) == 0; |
560 | 0 | } |
561 | | |
562 | | static |
563 | | void defMtxUnlock(cmsContext id, void* mtx) |
564 | 0 | { |
565 | 0 | cmsUNUSED_PARAMETER(id); |
566 | 0 | _cmsUnlockPrimitive((_cmsMutex *) mtx); |
567 | 0 | } |
568 | | |
569 | | |
570 | | |
571 | | // Pointers to memory manager functions in Context0 |
572 | | _cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; |
573 | | |
574 | | // Allocate and init mutex container. |
575 | | void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx, |
576 | | const struct _cmsContext_struct* src) |
577 | 192k | { |
578 | 192k | static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock }; |
579 | 192k | void* from; |
580 | | |
581 | 192k | if (src != NULL) { |
582 | 0 | from = src ->chunks[MutexPlugin]; |
583 | 0 | } |
584 | 192k | else { |
585 | 192k | from = &MutexChunk; |
586 | 192k | } |
587 | | |
588 | 192k | ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType)); |
589 | 192k | } |
590 | | |
591 | | // Register new ways to transform |
592 | | cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) |
593 | 385k | { |
594 | 385k | cmsPluginMutex* Plugin = (cmsPluginMutex*) Data; |
595 | 385k | _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
596 | | |
597 | 385k | if (Data == NULL) { |
598 | | |
599 | | // No lock routines |
600 | 192k | ctx->CreateMutexPtr = NULL; |
601 | 192k | ctx->DestroyMutexPtr = NULL; |
602 | 192k | ctx->LockMutexPtr = NULL; |
603 | 192k | ctx ->UnlockMutexPtr = NULL; |
604 | 192k | return TRUE; |
605 | 192k | } |
606 | | |
607 | | // Factory callback is required |
608 | 192k | if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL || |
609 | 192k | Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE; |
610 | | |
611 | | |
612 | 192k | ctx->CreateMutexPtr = Plugin->CreateMutexPtr; |
613 | 192k | ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr; |
614 | 192k | ctx ->LockMutexPtr = Plugin ->LockMutexPtr; |
615 | 192k | ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr; |
616 | | |
617 | | // All is ok |
618 | 192k | return TRUE; |
619 | 192k | } |
620 | | |
621 | | // Generic Mutex fns |
622 | | void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID) |
623 | 2.57M | { |
624 | 2.57M | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
625 | | |
626 | 2.57M | if (ptr ->CreateMutexPtr == NULL) return NULL; |
627 | | |
628 | 2.57M | return ptr ->CreateMutexPtr(ContextID); |
629 | 2.57M | } |
630 | | |
631 | | void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx) |
632 | 2.57M | { |
633 | 2.57M | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
634 | | |
635 | 2.57M | if (ptr ->DestroyMutexPtr != NULL && mtx != NULL) { |
636 | | |
637 | 2.57M | ptr ->DestroyMutexPtr(ContextID, mtx); |
638 | 2.57M | } |
639 | 2.57M | } |
640 | | |
641 | | cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx) |
642 | 25.6M | { |
643 | 25.6M | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
644 | | |
645 | 25.6M | if (ptr ->LockMutexPtr == NULL) return TRUE; |
646 | | |
647 | 25.6M | return ptr ->LockMutexPtr(ContextID, mtx); |
648 | 25.6M | } |
649 | | |
650 | | void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) |
651 | 25.6M | { |
652 | 25.6M | _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin); |
653 | | |
654 | 25.6M | if (ptr ->UnlockMutexPtr != NULL) { |
655 | | |
656 | 25.6M | ptr ->UnlockMutexPtr(ContextID, mtx); |
657 | 25.6M | } |
658 | 25.6M | } |