Path: blob/master/src/java.desktop/share/native/liblcms/cmserr.c
41149 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324// This file is available under and governed by the GNU General Public25// License version 2 only, as published by the Free Software Foundation.26// However, the following notice accompanied the original version of this27// file:28//29//---------------------------------------------------------------------------------30//31// Little Color Management System32// Copyright (c) 1998-2020 Marti Maria Saguer33//34// Permission is hereby granted, free of charge, to any person obtaining35// a copy of this software and associated documentation files (the "Software"),36// to deal in the Software without restriction, including without limitation37// the rights to use, copy, modify, merge, publish, distribute, sublicense,38// and/or sell copies of the Software, and to permit persons to whom the Software39// is furnished to do so, subject to the following conditions:40//41// The above copyright notice and this permission notice shall be included in42// all copies or substantial portions of the Software.43//44// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,45// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO46// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND47// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE48// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION49// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION50// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.51//52//---------------------------------------------------------------------------------5354#include "lcms2_internal.h"555657// This function is here to help applications to prevent mixing lcms versions on header and shared objects.58int CMSEXPORT cmsGetEncodedCMMversion(void)59{60return LCMS_VERSION;61}6263// I am so tired about incompatibilities on those functions that here are some replacements64// that hopefully would be fully portable.6566// compare two strings ignoring case67int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2)68{69CMSREGISTER const unsigned char *us1 = (const unsigned char *)s1,70*us2 = (const unsigned char *)s2;7172while (toupper(*us1) == toupper(*us2++))73if (*us1++ == '\0')74return 0;7576return (toupper(*us1) - toupper(*--us2));77}7879// long int because C99 specifies ftell in such way (7.19.9.2)80long int CMSEXPORT cmsfilelength(FILE* f)81{82long int p , n;8384p = ftell(f); // register current file position85if (p == -1L)86return -1L;8788if (fseek(f, 0, SEEK_END) != 0) {89return -1L;90}9192n = ftell(f);93fseek(f, p, SEEK_SET); // file position restored9495return n;96}979899// Memory handling ------------------------------------------------------------------100//101// This is the interface to low-level memory management routines. By default a simple102// wrapping to malloc/free/realloc is provided, although there is a limit on the max103// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent104// bogus or evil code to allocate huge blocks that otherwise lcms would never need.105106#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))107108// User may override this behaviour by using a memory plug-in, which basically replaces109// the default memory management functions. In this case, no check is performed and it110// is up to the plug-in writter to keep in the safe side. There are only three functions111// required to be implemented: malloc, realloc and free, although the user may want to112// replace the optional mallocZero, calloc and dup as well.113114cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin);115116// *********************************************************************************117118// This is the default memory allocation function. It does a very coarse119// check of amount of memory, just to prevent exploits120static121void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)122{123if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum124125return (void*) malloc(size);126127cmsUNUSED_PARAMETER(ContextID);128}129130// Generic allocate & zero131static132void* _cmsMallocZeroDefaultFn(cmsContext ContextID, cmsUInt32Number size)133{134void *pt = _cmsMalloc(ContextID, size);135if (pt == NULL) return NULL;136137memset(pt, 0, size);138return pt;139}140141142// The default free function. The only check proformed is against NULL pointers143static144void _cmsFreeDefaultFn(cmsContext ContextID, void *Ptr)145{146// free(NULL) is defined a no-op by C99, therefore it is safe to147// avoid the check, but it is here just in case...148149if (Ptr) free(Ptr);150151cmsUNUSED_PARAMETER(ContextID);152}153154// The default realloc function. Again it checks for exploits. If Ptr is NULL,155// realloc behaves the same way as malloc and allocates a new block of size bytes.156static157void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size)158{159160if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never realloc over 512Mb161162return realloc(Ptr, size);163164cmsUNUSED_PARAMETER(ContextID);165}166167168// The default calloc function. Allocates an array of num elements, each one of size bytes169// all memory is initialized to zero.170static171void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)172{173cmsUInt32Number Total = num * size;174175// Preserve calloc behaviour176if (Total == 0) return NULL;177178// Safe check for overflow.179if (num >= UINT_MAX / size) return NULL;180181// Check for overflow182if (Total < num || Total < size) {183return NULL;184}185186if (Total > MAX_MEMORY_FOR_ALLOC) return NULL; // Never alloc over 512Mb187188return _cmsMallocZero(ContextID, Total);189}190191// Generic block duplication192static193void* _cmsDupDefaultFn(cmsContext ContextID, const void* Org, cmsUInt32Number size)194{195void* mem;196197if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never dup over 512Mb198199mem = _cmsMalloc(ContextID, size);200201if (mem != NULL && Org != NULL)202memmove(mem, Org, size);203204return mem;205}206207208// Pointers to memory manager functions in Context0209_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn,210_cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn211};212213214// Reset and duplicate memory manager215void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)216{217_cmsAssert(ctx != NULL);218219if (src != NULL) {220221// Duplicate222ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType));223}224else {225226// To reset it, we use the default allocators, which cannot be overridden227ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager;228}229}230231// Auxiliary to fill memory management functions from plugin (or context 0 defaults)232void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr)233{234if (Plugin == NULL) {235236memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk));237}238else {239240ptr ->MallocPtr = Plugin -> MallocPtr;241ptr ->FreePtr = Plugin -> FreePtr;242ptr ->ReallocPtr = Plugin -> ReallocPtr;243244// Make sure we revert to defaults245ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn;246ptr ->CallocPtr = _cmsCallocDefaultFn;247ptr ->DupPtr = _cmsDupDefaultFn;248249if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr;250if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr;251if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr;252253}254}255256257// Plug-in replacement entry258cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data)259{260cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data;261_cmsMemPluginChunkType* ptr;262263// NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure.264// Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the265// context internal data should be malloce'd by using those functions.266if (Data == NULL) {267268struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID;269270// Return to the default allocators271if (ContextID != NULL) {272ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager;273}274return TRUE;275}276277// Check for required callbacks278if (Plugin -> MallocPtr == NULL ||279Plugin -> FreePtr == NULL ||280Plugin -> ReallocPtr == NULL) return FALSE;281282// Set replacement functions283ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);284if (ptr == NULL)285return FALSE;286287_cmsInstallAllocFunctions(Plugin, ptr);288return TRUE;289}290291// Generic allocate292void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size)293{294_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);295return ptr ->MallocPtr(ContextID, size);296}297298// Generic allocate & zero299void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size)300{301_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);302return ptr->MallocZeroPtr(ContextID, size);303}304305// Generic calloc306void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)307{308_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);309return ptr->CallocPtr(ContextID, num, size);310}311312// Generic reallocate313void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size)314{315_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);316return ptr->ReallocPtr(ContextID, Ptr, size);317}318319// Generic free memory320void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr)321{322if (Ptr != NULL) {323_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);324ptr ->FreePtr(ContextID, Ptr);325}326}327328// Generic block duplication329void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size)330{331_cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);332return ptr ->DupPtr(ContextID, Org, size);333}334335// ********************************************************************************************336337// Sub allocation takes care of many pointers of small size. The memory allocated in338// this way have be freed at once. Next function allocates a single chunk for linked list339// I prefer this method over realloc due to the big inpact on xput realloc may have if340// memory is being swapped to disk. This approach is safer (although that may not be true on all platforms)341static342_cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial)343{344_cmsSubAllocator_chunk* chunk;345346// 20K by default347if (Initial == 0)348Initial = 20*1024;349350// Create the container351chunk = (_cmsSubAllocator_chunk*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator_chunk));352if (chunk == NULL) return NULL;353354// Initialize values355chunk ->Block = (cmsUInt8Number*) _cmsMalloc(ContextID, Initial);356if (chunk ->Block == NULL) {357358// Something went wrong359_cmsFree(ContextID, chunk);360return NULL;361}362363chunk ->BlockSize = Initial;364chunk ->Used = 0;365chunk ->next = NULL;366367return chunk;368}369370// The suballocated is nothing but a pointer to the first element in the list. We also keep371// the thread ID in this structure.372_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial)373{374_cmsSubAllocator* sub;375376// Create the container377sub = (_cmsSubAllocator*) _cmsMallocZero(ContextID, sizeof(_cmsSubAllocator));378if (sub == NULL) return NULL;379380sub ->ContextID = ContextID;381382sub ->h = _cmsCreateSubAllocChunk(ContextID, Initial);383if (sub ->h == NULL) {384_cmsFree(ContextID, sub);385return NULL;386}387388return sub;389}390391392// Get rid of whole linked list393void _cmsSubAllocDestroy(_cmsSubAllocator* sub)394{395_cmsSubAllocator_chunk *chunk, *n;396397for (chunk = sub ->h; chunk != NULL; chunk = n) {398399n = chunk->next;400if (chunk->Block != NULL) _cmsFree(sub ->ContextID, chunk->Block);401_cmsFree(sub ->ContextID, chunk);402}403404// Free the header405_cmsFree(sub ->ContextID, sub);406}407408409// Get a pointer to small memory block.410void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size)411{412cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used;413cmsUInt8Number* ptr;414415size = _cmsALIGNMEM(size);416417// Check for memory. If there is no room, allocate a new chunk of double memory size.418if (size > Free) {419420_cmsSubAllocator_chunk* chunk;421cmsUInt32Number newSize;422423newSize = sub -> h ->BlockSize * 2;424if (newSize < size) newSize = size;425426chunk = _cmsCreateSubAllocChunk(sub -> ContextID, newSize);427if (chunk == NULL) return NULL;428429// Link list430chunk ->next = sub ->h;431sub ->h = chunk;432433}434435ptr = sub -> h ->Block + sub -> h ->Used;436sub -> h -> Used += size;437438return (void*) ptr;439}440441// Duplicate in pool442void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size)443{444void *NewPtr;445446// Dup of null pointer is also NULL447if (ptr == NULL)448return NULL;449450NewPtr = _cmsSubAlloc(s, size);451452if (ptr != NULL && NewPtr != NULL) {453memcpy(NewPtr, ptr, size);454}455456return NewPtr;457}458459460461// Error logging ******************************************************************462463// There is no error handling at all. When a function fails, it returns proper value.464// For example, all create functions does return NULL on failure. Other return FALSE465// It may be interesting, for the developer, to know why the function is failing.466// for that reason, lcms2 does offer a logging function. This function does receive467// a ENGLISH string with some clues on what is going wrong. You can show this468// info to the end user, or just create some sort of log.469// The logging function should NOT terminate the program, as this obviously can leave470// resources. It is the programmer's responsibility to check each function return code471// to make sure it didn't fail.472473// Error messages are limited to MAX_ERROR_MESSAGE_LEN474475#define MAX_ERROR_MESSAGE_LEN 1024476477// ---------------------------------------------------------------------------------------------------------478479// This is our default log error480static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);481482// Context0 storage, which is global483_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction };484485// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value486// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients487void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx,488const struct _cmsContext_struct* src)489{490static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction };491void* from;492493if (src != NULL) {494from = src ->chunks[Logger];495}496else {497from = &LogErrorChunk;498}499500ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType));501}502503// The default error logger does nothing.504static505void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)506{507// fprintf(stderr, "[lcms]: %s\n", Text);508// fflush(stderr);509510cmsUNUSED_PARAMETER(ContextID);511cmsUNUSED_PARAMETER(ErrorCode);512cmsUNUSED_PARAMETER(Text);513}514515// Change log error, context based516void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn)517{518_cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger);519520if (lhg != NULL) {521522if (Fn == NULL)523lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction;524else525lhg -> LogErrorHandler = Fn;526}527}528529// Change log error, legacy530void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn)531{532cmsSetLogErrorHandlerTHR(NULL, Fn);533}534535// Log an error536// ErrorText is a text holding an english description of error.537void CMSEXPORT cmsSignalError(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *ErrorText, ...)538{539va_list args;540char Buffer[MAX_ERROR_MESSAGE_LEN];541_cmsLogErrorChunkType* lhg;542543544va_start(args, ErrorText);545vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args);546va_end(args);547548// Check for the context, if specified go there. If not, go for the global549lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger);550if (lhg ->LogErrorHandler) {551lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer);552}553}554555// Utility function to print signatures556void _cmsTagSignature2String(char String[5], cmsTagSignature sig)557{558cmsUInt32Number be;559560// Convert to big endian561be = _cmsAdjustEndianess32((cmsUInt32Number) sig);562563// Move chars564memmove(String, &be, 4);565566// Make sure of terminator567String[4] = 0;568}569570//--------------------------------------------------------------------------------------------------571572573static574void* defMtxCreate(cmsContext id)575{576_cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex));577_cmsInitMutexPrimitive(ptr_mutex);578return (void*) ptr_mutex;579}580581static582void defMtxDestroy(cmsContext id, void* mtx)583{584_cmsDestroyMutexPrimitive((_cmsMutex *) mtx);585_cmsFree(id, mtx);586}587588static589cmsBool defMtxLock(cmsContext id, void* mtx)590{591cmsUNUSED_PARAMETER(id);592return _cmsLockPrimitive((_cmsMutex *) mtx) == 0;593}594595static596void defMtxUnlock(cmsContext id, void* mtx)597{598cmsUNUSED_PARAMETER(id);599_cmsUnlockPrimitive((_cmsMutex *) mtx);600}601602603604// Pointers to memory manager functions in Context0605_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };606607// Allocate and init mutex container.608void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,609const struct _cmsContext_struct* src)610{611static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };612void* from;613614if (src != NULL) {615from = src ->chunks[MutexPlugin];616}617else {618from = &MutexChunk;619}620621ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType));622}623624// Register new ways to transform625cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data)626{627cmsPluginMutex* Plugin = (cmsPluginMutex*) Data;628_cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);629630if (Data == NULL) {631632// No lock routines633ctx->CreateMutexPtr = NULL;634ctx->DestroyMutexPtr = NULL;635ctx->LockMutexPtr = NULL;636ctx ->UnlockMutexPtr = NULL;637return TRUE;638}639640// Factory callback is required641if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL ||642Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE;643644645ctx->CreateMutexPtr = Plugin->CreateMutexPtr;646ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr;647ctx ->LockMutexPtr = Plugin ->LockMutexPtr;648ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr;649650// All is ok651return TRUE;652}653654// Generic Mutex fns655void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID)656{657_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);658659if (ptr ->CreateMutexPtr == NULL) return NULL;660661return ptr ->CreateMutexPtr(ContextID);662}663664void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx)665{666_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);667668if (ptr ->DestroyMutexPtr != NULL) {669670ptr ->DestroyMutexPtr(ContextID, mtx);671}672}673674cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx)675{676_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);677678if (ptr ->LockMutexPtr == NULL) return TRUE;679680return ptr ->LockMutexPtr(ContextID, mtx);681}682683void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx)684{685_cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);686687if (ptr ->UnlockMutexPtr != NULL) {688689ptr ->UnlockMutexPtr(ContextID, mtx);690}691}692693694