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