| 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 | |