1 //---------------------------------------------------------------------------------
3 // Little Color Management System
4 // Copyright (c) 1998-2012 Marti Maria Saguer
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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
24 //---------------------------------------------------------------------------------
26 #include "lcms2_internal.h"
28 // I am so tired about incompatibilities on those functions that here are some replacements
29 // that hopefully would be fully portable.
31 // compare two strings ignoring case
32 int CMSEXPORT
cmsstrcasecmp(const char* s1
, const char* s2
)
34 register const unsigned char *us1
= (const unsigned char *)s1
,
35 *us2
= (const unsigned char *)s2
;
37 while (toupper(*us1
) == toupper(*us2
++))
40 return (toupper(*us1
) - toupper(*--us2
));
43 // long int because C99 specifies ftell in such way (7.19.9.2)
44 long int CMSEXPORT
cmsfilelength(FILE* f
)
48 p
= ftell(f
); // register current file position
50 if (fseek(f
, 0, SEEK_END
) != 0) {
55 fseek(f
, p
, SEEK_SET
); // file position restored
61 // Memory handling ------------------------------------------------------------------
63 // This is the interface to low-level memory management routines. By default a simple
64 // wrapping to malloc/free/realloc is provided, although there is a limit on the max
65 // amount of memoy that can be reclaimed. This is mostly as a safety feature to
66 // prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms
69 #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
71 // User may override this behaviour by using a memory plug-in, which basically replaces
72 // the default memory management functions. In this case, no check is performed and it
73 // is up to the plug-in writter to keep in the safe side. There are only three functions
74 // required to be implemented: malloc, realloc and free, although the user may want to
75 // replace the optional mallocZero, calloc and dup as well.
77 cmsBool
_cmsRegisterMemHandlerPlugin(cmsPluginBase
* Plugin
);
79 // *********************************************************************************
81 // This is the default memory allocation function. It does a very coarse
82 // check of amout of memory, just to prevent exploits
84 void* _cmsMallocDefaultFn(cmsContext ContextID
, cmsUInt32Number size
)
86 if (size
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never allow over maximum
88 return (void*) malloc(size
);
90 cmsUNUSED_PARAMETER(ContextID
);
93 // Generic allocate & zero
95 void* _cmsMallocZeroDefaultFn(cmsContext ContextID
, cmsUInt32Number size
)
97 void *pt
= _cmsMalloc(ContextID
, size
);
98 if (pt
== NULL
) return NULL
;
105 // The default free function. The only check proformed is against NULL pointers
107 void _cmsFreeDefaultFn(cmsContext ContextID
, void *Ptr
)
109 // free(NULL) is defined a no-op by C99, therefore it is safe to
110 // avoid the check, but it is here just in case...
114 cmsUNUSED_PARAMETER(ContextID
);
117 // The default realloc function. Again it check for exploits. If Ptr is NULL,
118 // realloc behaves the same way as malloc and allocates a new block of size bytes.
120 void* _cmsReallocDefaultFn(cmsContext ContextID
, void* Ptr
, cmsUInt32Number size
)
123 if (size
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never realloc over 512Mb
125 return realloc(Ptr
, size
);
127 cmsUNUSED_PARAMETER(ContextID
);
131 // The default calloc function. Allocates an array of num elements, each one of size bytes
132 // all memory is initialized to zero.
134 void* _cmsCallocDefaultFn(cmsContext ContextID
, cmsUInt32Number num
, cmsUInt32Number size
)
136 cmsUInt32Number Total
= num
* size
;
138 // Preserve calloc behaviour
139 if (Total
== 0) return NULL
;
141 // Safe check for overflow.
142 if (num
>= UINT_MAX
/ size
) return NULL
;
144 // Check for overflow
145 if (Total
< num
|| Total
< size
) {
149 if (Total
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never alloc over 512Mb
151 return _cmsMallocZero(ContextID
, Total
);
154 // Generic block duplication
156 void* _cmsDupDefaultFn(cmsContext ContextID
, const void* Org
, cmsUInt32Number size
)
160 if (size
> MAX_MEMORY_FOR_ALLOC
) return NULL
; // Never dup over 512Mb
162 mem
= _cmsMalloc(ContextID
, size
);
164 if (mem
!= NULL
&& Org
!= NULL
)
165 memmove(mem
, Org
, size
);
170 // Pointers to malloc and _cmsFree functions in current environment
171 static void * (* MallocPtr
)(cmsContext ContextID
, cmsUInt32Number size
) = _cmsMallocDefaultFn
;
172 static void * (* MallocZeroPtr
)(cmsContext ContextID
, cmsUInt32Number size
) = _cmsMallocZeroDefaultFn
;
173 static void (* FreePtr
)(cmsContext ContextID
, void *Ptr
) = _cmsFreeDefaultFn
;
174 static void * (* ReallocPtr
)(cmsContext ContextID
, void *Ptr
, cmsUInt32Number NewSize
) = _cmsReallocDefaultFn
;
175 static void * (* CallocPtr
)(cmsContext ContextID
, cmsUInt32Number num
, cmsUInt32Number size
)= _cmsCallocDefaultFn
;
176 static void * (* DupPtr
)(cmsContext ContextID
, const void* Org
, cmsUInt32Number size
) = _cmsDupDefaultFn
;
178 // Plug-in replacement entry
179 cmsBool
_cmsRegisterMemHandlerPlugin(cmsPluginBase
*Data
)
181 cmsPluginMemHandler
* Plugin
= (cmsPluginMemHandler
*) Data
;
183 // NULL forces to reset to defaults
186 MallocPtr
= _cmsMallocDefaultFn
;
187 MallocZeroPtr
= _cmsMallocZeroDefaultFn
;
188 FreePtr
= _cmsFreeDefaultFn
;
189 ReallocPtr
= _cmsReallocDefaultFn
;
190 CallocPtr
= _cmsCallocDefaultFn
;
191 DupPtr
= _cmsDupDefaultFn
;
195 // Check for required callbacks
196 if (Plugin
-> MallocPtr
== NULL
||
197 Plugin
-> FreePtr
== NULL
||
198 Plugin
-> ReallocPtr
== NULL
) return FALSE
;
200 // Set replacement functions
201 MallocPtr
= Plugin
-> MallocPtr
;
202 FreePtr
= Plugin
-> FreePtr
;
203 ReallocPtr
= Plugin
-> ReallocPtr
;
205 if (Plugin
->MallocZeroPtr
!= NULL
) MallocZeroPtr
= Plugin
->MallocZeroPtr
;
206 if (Plugin
->CallocPtr
!= NULL
) CallocPtr
= Plugin
-> CallocPtr
;
207 if (Plugin
->DupPtr
!= NULL
) DupPtr
= Plugin
-> DupPtr
;
213 void* CMSEXPORT
_cmsMalloc(cmsContext ContextID
, cmsUInt32Number size
)
215 return MallocPtr(ContextID
, size
);
218 // Generic allocate & zero
219 void* CMSEXPORT
_cmsMallocZero(cmsContext ContextID
, cmsUInt32Number size
)
221 return MallocZeroPtr(ContextID
, size
);
225 void* CMSEXPORT
_cmsCalloc(cmsContext ContextID
, cmsUInt32Number num
, cmsUInt32Number size
)
227 return CallocPtr(ContextID
, num
, size
);
230 // Generic reallocate
231 void* CMSEXPORT
_cmsRealloc(cmsContext ContextID
, void* Ptr
, cmsUInt32Number size
)
233 return ReallocPtr(ContextID
, Ptr
, size
);
236 // Generic free memory
237 void CMSEXPORT
_cmsFree(cmsContext ContextID
, void* Ptr
)
239 if (Ptr
!= NULL
) FreePtr(ContextID
, Ptr
);
242 // Generic block duplication
243 void* CMSEXPORT
_cmsDupMem(cmsContext ContextID
, const void* Org
, cmsUInt32Number size
)
245 return DupPtr(ContextID
, Org
, size
);
248 // ********************************************************************************************
250 // Sub allocation takes care of many pointers of small size. The memory allocated in
251 // this way have be freed at once. Next function allocates a single chunk for linked list
252 // I prefer this method over realloc due to the big inpact on xput realloc may have if
253 // memory is being swapped to disk. This approach is safer (although that may not be true on all platforms)
255 _cmsSubAllocator_chunk
* _cmsCreateSubAllocChunk(cmsContext ContextID
, cmsUInt32Number Initial
)
257 _cmsSubAllocator_chunk
* chunk
;
263 // Create the container
264 chunk
= (_cmsSubAllocator_chunk
*) _cmsMallocZero(ContextID
, sizeof(_cmsSubAllocator_chunk
));
265 if (chunk
== NULL
) return NULL
;
268 chunk
->Block
= (cmsUInt8Number
*) _cmsMalloc(ContextID
, Initial
);
269 if (chunk
->Block
== NULL
) {
271 // Something went wrong
272 _cmsFree(ContextID
, chunk
);
276 chunk
->BlockSize
= Initial
;
283 // The suballocated is nothing but a pointer to the first element in the list. We also keep
284 // the thread ID in this structure.
285 _cmsSubAllocator
* _cmsCreateSubAlloc(cmsContext ContextID
, cmsUInt32Number Initial
)
287 _cmsSubAllocator
* sub
;
289 // Create the container
290 sub
= (_cmsSubAllocator
*) _cmsMallocZero(ContextID
, sizeof(_cmsSubAllocator
));
291 if (sub
== NULL
) return NULL
;
293 sub
->ContextID
= ContextID
;
295 sub
->h
= _cmsCreateSubAllocChunk(ContextID
, Initial
);
296 if (sub
->h
== NULL
) {
297 _cmsFree(ContextID
, sub
);
305 // Get rid of whole linked list
306 void _cmsSubAllocDestroy(_cmsSubAllocator
* sub
)
308 _cmsSubAllocator_chunk
*chunk
, *n
;
310 for (chunk
= sub
->h
; chunk
!= NULL
; chunk
= n
) {
313 if (chunk
->Block
!= NULL
) _cmsFree(sub
->ContextID
, chunk
->Block
);
314 _cmsFree(sub
->ContextID
, chunk
);
318 _cmsFree(sub
->ContextID
, sub
);
322 // Get a pointer to small memory block.
323 void* _cmsSubAlloc(_cmsSubAllocator
* sub
, cmsUInt32Number size
)
325 cmsUInt32Number Free
= sub
-> h
->BlockSize
- sub
-> h
-> Used
;
328 size
= _cmsALIGNMEM(size
);
330 // Check for memory. If there is no room, allocate a new chunk of double memory size.
333 _cmsSubAllocator_chunk
* chunk
;
334 cmsUInt32Number newSize
;
336 newSize
= sub
-> h
->BlockSize
* 2;
337 if (newSize
< size
) newSize
= size
;
339 chunk
= _cmsCreateSubAllocChunk(sub
-> ContextID
, newSize
);
340 if (chunk
== NULL
) return NULL
;
343 chunk
->next
= sub
->h
;
348 ptr
= sub
-> h
->Block
+ sub
-> h
->Used
;
349 sub
-> h
-> Used
+= size
;
354 // Error logging ******************************************************************
356 // There is no error handling at all. When a funtion fails, it returns proper value.
357 // For example, all create functions does return NULL on failure. Other return FALSE
358 // It may be interesting, for the developer, to know why the function is failing.
359 // for that reason, lcms2 does offer a logging function. This function does recive
360 // a ENGLISH string with some clues on what is going wrong. You can show this
361 // info to the end user, or just create some sort of log.
362 // The logging function should NOT terminate the program, as this obviously can leave
363 // resources. It is the programmer's responsability to check each function return code
364 // to make sure it didn't fail.
366 // Error messages are limited to MAX_ERROR_MESSAGE_LEN
368 #define MAX_ERROR_MESSAGE_LEN 1024
370 // ---------------------------------------------------------------------------------------------------------
372 // This is our default log error
373 static void DefaultLogErrorHandlerFunction(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *Text
);
375 // The current handler in actual environment
376 static cmsLogErrorHandlerFunction LogErrorHandler
= DefaultLogErrorHandlerFunction
;
378 // The default error logger does nothing.
380 void DefaultLogErrorHandlerFunction(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *Text
)
382 // fprintf(stderr, "[lcms]: %s\n", Text);
385 cmsUNUSED_PARAMETER(ContextID
);
386 cmsUNUSED_PARAMETER(ErrorCode
);
387 cmsUNUSED_PARAMETER(Text
);
391 void CMSEXPORT
cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn
)
394 LogErrorHandler
= DefaultLogErrorHandlerFunction
;
396 LogErrorHandler
= Fn
;
400 // ErrorText is a text holding an english description of error.
401 void CMSEXPORT
cmsSignalError(cmsContext ContextID
, cmsUInt32Number ErrorCode
, const char *ErrorText
, ...)
404 char Buffer
[MAX_ERROR_MESSAGE_LEN
];
406 va_start(args
, ErrorText
);
407 vsnprintf(Buffer
, MAX_ERROR_MESSAGE_LEN
-1, ErrorText
, args
);
411 LogErrorHandler(ContextID
, ErrorCode
, Buffer
);
414 // Utility function to print signatures
415 void _cmsTagSignature2String(char String
[5], cmsTagSignature sig
)
419 // Convert to big endian
420 be
= _cmsAdjustEndianess32((cmsUInt32Number
) sig
);
423 memmove(String
, &be
, 4);
425 // Make sure of terminator