You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

561 lines
20 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% CCCC OOO DDDD EEEEE RRRR %
% C O O D D E R R %
% C O O D D EEE RRRR %
% C O O D D E R R %
% CCCC OOO DDDD EEEEE R R %
% %
% %
% MagickCore Image Coder Methods %
% %
% Software Design %
% Cristy %
% May 2001 %
% %
% %
% Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/client.h"
#include "MagickCore/coder.h"
#include "MagickCore/coder-private.h"
#include "MagickCore/configure.h"
#include "MagickCore/draw.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/log.h"
#include "MagickCore/memory_.h"
#include "MagickCore/memory-private.h"
#include "MagickCore/option.h"
#include "MagickCore/semaphore.h"
#include "MagickCore/string_.h"
#include "MagickCore/splay-tree.h"
#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "MagickCore/utility-private.h"
#include "coders/coders.h"
/*
Define declarations.
*/
#define AddMagickCoder(coder) Magick ## coder ## Aliases
/*
Typedef declarations.
*/
typedef struct _CoderMapInfo
{
const char
*magick,
*name;
} CoderMapInfo;
/*
Static declarations.
*/
static const CoderMapInfo
CoderMap[] =
{
#include "coders/coders-list.h"
};
static SemaphoreInfo
*coder_semaphore = (SemaphoreInfo *) NULL;
static SplayTreeInfo
*coder_cache = (SplayTreeInfo *) NULL;
/*
Forward declarations.
*/
static MagickBooleanType
IsCoderTreeInstantiated(ExceptionInfo *);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ A c q u i r e C o d e r C a c h e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireCoderCache() caches one or more coder configurations which provides a
% mapping between coder attributes and a coder name.
%
% The format of the AcquireCoderCache coder is:
%
% SplayTreeInfo *AcquireCoderCache(ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o exception: return any errors or warnings in this structure.
%
*/
static void *DestroyCoderNode(void *coder_info)
{
CoderInfo
*p;
p=(CoderInfo *) coder_info;
if (p->exempt == MagickFalse)
{
if (p->path != (char *) NULL)
p->path=DestroyString(p->path);
if (p->name != (char *) NULL)
p->name=DestroyString(p->name);
if (p->magick != (char *) NULL)
p->magick=DestroyString(p->magick);
}
return(RelinquishMagickMemory(p));
}
static SplayTreeInfo *AcquireCoderCache(ExceptionInfo *exception)
{
MagickStatusType
status;
ssize_t
i;
SplayTreeInfo
*cache;
/*
Load built-in coder map.
*/
cache=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
DestroyCoderNode);
status=MagickTrue;
for (i=0; i < (ssize_t) (sizeof(CoderMap)/sizeof(*CoderMap)); i++)
{
CoderInfo
*coder_info;
const CoderMapInfo
*p;
p=CoderMap+i;
coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
if (coder_info == (CoderInfo *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
continue;
}
(void) memset(coder_info,0,sizeof(*coder_info));
coder_info->path=(char *) "[built-in]";
coder_info->magick=(char *) p->magick;
coder_info->name=(char *) p->name;
coder_info->exempt=MagickTrue;
coder_info->signature=MagickCoreSignature;
status&=AddValueToSplayTree(cache,ConstantString(coder_info->magick),
coder_info);
if (status == MagickFalse)
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
}
return(cache);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ C o d e r C o m p o n e n t G e n e s i s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CoderComponentGenesis() instantiates the coder component.
%
% The format of the CoderComponentGenesis method is:
%
% MagickBooleanType CoderComponentGenesis(void)
%
*/
MagickPrivate MagickBooleanType CoderComponentGenesis(void)
{
if (coder_semaphore == (SemaphoreInfo *) NULL)
coder_semaphore=AcquireSemaphoreInfo();
return(MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ C o d e r C o m p o n e n t T e r m i n u s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CoderComponentTerminus() destroys the coder component.
%
% The format of the CoderComponentTerminus method is:
%
% CoderComponentTerminus(void)
%
*/
MagickPrivate void CoderComponentTerminus(void)
{
if (coder_semaphore == (SemaphoreInfo *) NULL)
ActivateSemaphoreInfo(&coder_semaphore);
LockSemaphoreInfo(coder_semaphore);
if (coder_cache != (SplayTreeInfo *) NULL)
coder_cache=DestroySplayTree(coder_cache);
UnlockSemaphoreInfo(coder_semaphore);
RelinquishSemaphoreInfo(&coder_semaphore);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t C o d e r I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetCoderInfo searches the coder list for the specified name and if found
% returns attributes for that coder.
%
% The format of the GetCoderInfo method is:
%
% const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o name: the coder name.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport const CoderInfo *GetCoderInfo(const char *name,
ExceptionInfo *exception)
{
assert(exception != (ExceptionInfo *) NULL);
if (IsCoderTreeInstantiated(exception) == MagickFalse)
return((const CoderInfo *) NULL);
if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
return((const CoderInfo *) GetRootValueFromSplayTree(coder_cache));
return((const CoderInfo *) GetValueFromSplayTree(coder_cache,name));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t C o d e r I n f o L i s t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetCoderInfoList() returns any coder_map that match the specified pattern.
% The format of the GetCoderInfoList function is:
%
% const CoderInfo **GetCoderInfoList(const char *pattern,
% size_t *number_coders,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o pattern: Specifies a pointer to a text string containing a pattern.
%
% o number_coders: This integer returns the number of coders in the list.
%
% o exception: return any errors or warnings in this structure.
%
*/
static int CoderInfoCompare(const void *x,const void *y)
{
const CoderInfo
**p,
**q;
p=(const CoderInfo **) x,
q=(const CoderInfo **) y;
if (LocaleCompare((*p)->path,(*q)->path) == 0)
return(LocaleCompare((*p)->name,(*q)->name));
return(LocaleCompare((*p)->path,(*q)->path));
}
MagickExport const CoderInfo **GetCoderInfoList(const char *pattern,
size_t *number_coders,ExceptionInfo *exception)
{
const CoderInfo
**coder_map;
const CoderInfo
*p;
ssize_t
i;
/*
Allocate coder list.
*/
assert(pattern != (char *) NULL);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
assert(number_coders != (size_t *) NULL);
*number_coders=0;
p=GetCoderInfo("*",exception);
if (p == (const CoderInfo *) NULL)
return((const CoderInfo **) NULL);
coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t)
GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
if (coder_map == (const CoderInfo **) NULL)
return((const CoderInfo **) NULL);
/*
Generate coder list.
*/
LockSemaphoreInfo(coder_semaphore);
ResetSplayTreeIterator(coder_cache);
p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
for (i=0; p != (const CoderInfo *) NULL; )
{
if ((p->stealth == MagickFalse) &&
(GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
coder_map[i++]=p;
p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
}
UnlockSemaphoreInfo(coder_semaphore);
qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
coder_map[i]=(CoderInfo *) NULL;
*number_coders=(size_t) i;
return(coder_map);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t C o d e r L i s t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetCoderList() returns any coder_map that match the specified pattern.
%
% The format of the GetCoderList function is:
%
% char **GetCoderList(const char *pattern,size_t *number_coders,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o pattern: Specifies a pointer to a text string containing a pattern.
%
% o number_coders: This integer returns the number of coders in the list.
%
% o exception: return any errors or warnings in this structure.
%
*/
static int CoderCompare(const void *x,const void *y)
{
const char
**p,
**q;
p=(const char **) x;
q=(const char **) y;
return(LocaleCompare(*p,*q));
}
MagickExport char **GetCoderList(const char *pattern,
size_t *number_coders,ExceptionInfo *exception)
{
char
**coder_map;
const CoderInfo
*p;
ssize_t
i;
/*
Allocate coder list.
*/
assert(pattern != (char *) NULL);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
assert(number_coders != (size_t *) NULL);
*number_coders=0;
p=GetCoderInfo("*",exception);
if (p == (const CoderInfo *) NULL)
return((char **) NULL);
coder_map=(char **) AcquireQuantumMemory((size_t)
GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
if (coder_map == (char **) NULL)
return((char **) NULL);
/*
Generate coder list.
*/
LockSemaphoreInfo(coder_semaphore);
ResetSplayTreeIterator(coder_cache);
p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
for (i=0; p != (const CoderInfo *) NULL; )
{
if ((p->stealth == MagickFalse) &&
(GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
coder_map[i++]=ConstantString(p->name);
p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
}
UnlockSemaphoreInfo(coder_semaphore);
qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
coder_map[i]=(char *) NULL;
*number_coders=(size_t) i;
return(coder_map);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ I s C o d e r T r e e I n s t a n t i a t e d %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IsCoderTreeInstantiated() determines if the coder tree is instantiated. If
% not, it instantiates the tree and returns it.
%
% The format of the IsCoderInstantiated method is:
%
% MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
%
% A description of each parameter follows.
%
% o exception: return any errors or warnings in this structure.
%
*/
static MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
{
if (coder_cache == (SplayTreeInfo *) NULL)
{
if (coder_semaphore == (SemaphoreInfo *) NULL)
ActivateSemaphoreInfo(&coder_semaphore);
LockSemaphoreInfo(coder_semaphore);
if (coder_cache == (SplayTreeInfo *) NULL)
coder_cache=AcquireCoderCache(exception);
UnlockSemaphoreInfo(coder_semaphore);
}
return(coder_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% L i s t C o d e r I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ListCoderInfo() lists the coder info to a file.
%
% The format of the ListCoderInfo coder is:
%
% MagickBooleanType ListCoderInfo(FILE *file,ExceptionInfo *exception)
%
% A description of each parameter follows.
%
% o file: An pointer to a FILE.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType ListCoderInfo(FILE *file,
ExceptionInfo *exception)
{
const char
*path;
const CoderInfo
**coder_info;
ssize_t
i;
size_t
number_coders;
ssize_t
j;
if (file == (const FILE *) NULL)
file=stdout;
coder_info=GetCoderInfoList("*",&number_coders,exception);
if (coder_info == (const CoderInfo **) NULL)
return(MagickFalse);
path=(const char *) NULL;
for (i=0; i < (ssize_t) number_coders; i++)
{
if (coder_info[i]->stealth != MagickFalse)
continue;
if ((path == (const char *) NULL) ||
(LocaleCompare(path,coder_info[i]->path) != 0))
{
if (coder_info[i]->path != (char *) NULL)
(void) FormatLocaleFile(file,"\nPath: %s\n\n",coder_info[i]->path);
(void) FormatLocaleFile(file,"Magick Coder\n");
(void) FormatLocaleFile(file,
"-------------------------------------------------"
"------------------------------\n");
}
path=coder_info[i]->path;
(void) FormatLocaleFile(file,"%s",coder_info[i]->magick);
for (j=(ssize_t) strlen(coder_info[i]->magick); j <= 15; j++)
(void) FormatLocaleFile(file," ");
if (coder_info[i]->name != (char *) NULL)
(void) FormatLocaleFile(file,"%s",coder_info[i]->name);
(void) FormatLocaleFile(file,"\n");
}
coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info);
(void) fflush(file);
return(MagickTrue);
}