blob: 2dc1709fdd51ee203790118dc5c86a6272d9d462 [file] [log] [blame]
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% BBBB L OOO BBBB %
% B B L O O B B %
% BBBB L O O BBBB %
% B B L O O B B %
% BBBB LLLLL OOO BBBB %
% %
% %
% MagickCore Binary Large OBjectS Methods %
% %
% Software Design %
% Cristy %
% July 1999 %
% %
% %
% Copyright 1999-2019 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.
*/
#ifdef __VMS
#include <types.h>
#include <mman.h>
#endif
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#include "MagickCore/cache.h"
#include "MagickCore/client.h"
#include "MagickCore/constitute.h"
#include "MagickCore/delegate.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/geometry.h"
#include "MagickCore/image-private.h"
#include "MagickCore/list.h"
#include "MagickCore/locale_.h"
#include "MagickCore/log.h"
#include "MagickCore/magick.h"
#include "MagickCore/memory_.h"
#include "MagickCore/memory-private.h"
#include "MagickCore/nt-base-private.h"
#include "MagickCore/option.h"
#include "MagickCore/policy.h"
#include "MagickCore/resource_.h"
#include "MagickCore/semaphore.h"
#include "MagickCore/string_.h"
#include "MagickCore/string-private.h"
#include "MagickCore/token.h"
#include "MagickCore/utility.h"
#include "MagickCore/utility-private.h"
#if defined(MAGICKCORE_ZLIB_DELEGATE)
#include "zlib.h"
#endif
#if defined(MAGICKCORE_BZLIB_DELEGATE)
#include "bzlib.h"
#endif
/*
Define declarations.
*/
#define MagickMaxBlobExtent (8*8192)
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
# define MAP_ANONYMOUS MAP_ANON
#endif
#if !defined(MAP_FAILED)
#define MAP_FAILED ((void *) -1)
#endif
#if defined(__OS2__)
#include <io.h>
#define _O_BINARY O_BINARY
#endif
/*
Typedef declarations.
*/
typedef union FileInfo
{
FILE
*file;
#if defined(MAGICKCORE_ZLIB_DELEGATE)
gzFile
gzfile;
#endif
#if defined(MAGICKCORE_BZLIB_DELEGATE)
BZFILE
*bzfile;
#endif
} FileInfo;
struct _BlobInfo
{
size_t
length,
extent,
quantum;
BlobMode
mode;
MagickBooleanType
mapped,
eof;
int
error;
MagickOffsetType
offset;
MagickSizeType
size;
MagickBooleanType
exempt,
synchronize,
status,
temporary;
StreamType
type;
FileInfo
file_info;
struct stat
properties;
StreamHandler
stream;
CustomStreamInfo
*custom_stream;
unsigned char
*data;
MagickBooleanType
debug;
SemaphoreInfo
*semaphore;
ssize_t
reference_count;
size_t
signature;
};
struct _CustomStreamInfo
{
CustomStreamHandler
reader,
writer;
CustomStreamSeeker
seeker;
CustomStreamTeller
teller;
void
*data;
size_t
signature;
};
/*
Forward declarations.
*/
static int
SyncBlob(Image *);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ A c q u i r e C u s t o m S t r e a m I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireCustomStreamInfo() allocates the CustomStreamInfo structure.
%
% The format of the AcquireCustomStreamInfo method is:
%
% CustomStreamInfo *AcquireCustomStreamInfo(ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport CustomStreamInfo *AcquireCustomStreamInfo(
ExceptionInfo *magick_unused(exception))
{
CustomStreamInfo
*custom_stream;
magick_unreferenced(exception);
custom_stream=(CustomStreamInfo *) AcquireCriticalMemory(
sizeof(*custom_stream));
(void) memset(custom_stream,0,sizeof(*custom_stream));
custom_stream->signature=MagickCoreSignature;
return(custom_stream);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ A t t a c h B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AttachBlob() attaches a blob to the BlobInfo structure.
%
% The format of the AttachBlob method is:
%
% void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
%
% A description of each parameter follows:
%
% o blob_info: Specifies a pointer to a BlobInfo structure.
%
% o blob: the address of a character stream in one of the image formats
% understood by ImageMagick.
%
% o length: This size_t integer reflects the length in bytes of the blob.
%
*/
MagickExport void AttachBlob(BlobInfo *blob_info,const void *blob,
const size_t length)
{
assert(blob_info != (BlobInfo *) NULL);
if (blob_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
blob_info->length=length;
blob_info->extent=length;
blob_info->quantum=(size_t) MagickMaxBlobExtent;
blob_info->offset=0;
blob_info->type=BlobStream;
blob_info->file_info.file=(FILE *) NULL;
blob_info->data=(unsigned char *) blob;
blob_info->mapped=MagickFalse;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ A t t a c h C u s t o m S t r e a m %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AttachCustomStream() attaches a CustomStreamInfo to the BlobInfo structure.
%
% The format of the AttachCustomStream method is:
%
% void AttachCustomStream(BlobInfo *blob_info,
% CustomStreamInfo *custom_stream)
%
% A description of each parameter follows:
%
% o blob_info: specifies a pointer to a BlobInfo structure.
%
% o custom_stream: the custom stream info.
%
*/
MagickExport void AttachCustomStream(BlobInfo *blob_info,
CustomStreamInfo *custom_stream)
{
assert(blob_info != (BlobInfo *) NULL);
assert(custom_stream != (CustomStreamInfo *) NULL);
assert(custom_stream->signature == MagickCoreSignature);
if (blob_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
blob_info->type=CustomStream;
blob_info->custom_stream=custom_stream;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ B l o b T o F i l e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% BlobToFile() writes a blob to a file. It returns MagickFalse if an error
% occurs otherwise MagickTrue.
%
% The format of the BlobToFile method is:
%
% MagickBooleanType BlobToFile(char *filename,const void *blob,
% const size_t length,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o filename: Write the blob to this file.
%
% o blob: the address of a blob.
%
% o length: This length in bytes of the blob.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType BlobToFile(char *filename,const void *blob,
const size_t length,ExceptionInfo *exception)
{
int
file;
register size_t
i;
ssize_t
count;
assert(filename != (const char *) NULL);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
assert(blob != (const void *) NULL);
if (*filename == '\0')
file=AcquireUniqueFileResource(filename);
else
file=open_utf8(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
return(MagickFalse);
}
for (i=0; i < length; i+=count)
{
count=write(file,(const char *) blob+i,MagickMin(length-i,(size_t)
SSIZE_MAX));
if (count <= 0)
{
count=0;
if (errno != EINTR)
break;
}
}
file=close(file);
if ((file == -1) || (i < length))
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
return(MagickFalse);
}
return(MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% B l o b T o I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% BlobToImage() implements direct to memory image formats. It returns the
% blob as an image.
%
% The format of the BlobToImage method is:
%
% Image *BlobToImage(const ImageInfo *image_info,const void *blob,
% const size_t length,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o blob: the address of a character stream in one of the image formats
% understood by ImageMagick.
%
% o length: This size_t integer reflects the length in bytes of the blob.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport Image *BlobToImage(const ImageInfo *image_info,const void *blob,
const size_t length,ExceptionInfo *exception)
{
const MagickInfo
*magick_info;
Image
*image;
ImageInfo
*blob_info,
*clone_info;
MagickBooleanType
status;
assert(image_info != (ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(exception != (ExceptionInfo *) NULL);
if ((blob == (const void *) NULL) || (length == 0))
{
(void) ThrowMagickException(exception,GetMagickModule(),BlobError,
"ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
return((Image *) NULL);
}
blob_info=CloneImageInfo(image_info);
blob_info->blob=(void *) blob;
blob_info->length=length;
if (*blob_info->magick == '\0')
(void) SetImageInfo(blob_info,0,exception);
magick_info=GetMagickInfo(blob_info->magick,exception);
if (magick_info == (const MagickInfo *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
blob_info->magick);
blob_info=DestroyImageInfo(blob_info);
return((Image *) NULL);
}
if (GetMagickBlobSupport(magick_info) != MagickFalse)
{
char
filename[MagickPathExtent];
/*
Native blob support for this image format.
*/
(void) CopyMagickString(filename,blob_info->filename,MagickPathExtent);
(void) FormatLocaleString(blob_info->filename,MagickPathExtent,"%s:%s",
blob_info->magick,filename);
image=ReadImage(blob_info,exception);
if (image != (Image *) NULL)
(void) DetachBlob(image->blob);
blob_info=DestroyImageInfo(blob_info);
return(image);
}
/*
Write blob to a temporary file on disk.
*/
blob_info->blob=(void *) NULL;
blob_info->length=0;
*blob_info->filename='\0';
status=BlobToFile(blob_info->filename,blob,length,exception);
if (status == MagickFalse)
{
(void) RelinquishUniqueFileResource(blob_info->filename);
blob_info=DestroyImageInfo(blob_info);
return((Image *) NULL);
}
clone_info=CloneImageInfo(blob_info);
(void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:%s",
blob_info->magick,blob_info->filename);
image=ReadImage(clone_info,exception);
if (image != (Image *) NULL)
{
Image
*images;
/*
Restore original filenames and image format.
*/
for (images=GetFirstImageInList(image); images != (Image *) NULL; )
{
(void) CopyMagickString(images->filename,image_info->filename,
MagickPathExtent);
(void) CopyMagickString(images->magick_filename,image_info->filename,
MagickPathExtent);
(void) CopyMagickString(images->magick,magick_info->name,
MagickPathExtent);
images=GetNextImageInList(images);
}
}
clone_info=DestroyImageInfo(clone_info);
(void) RelinquishUniqueFileResource(blob_info->filename);
blob_info=DestroyImageInfo(blob_info);
return(image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ C l o n e B l o b I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CloneBlobInfo() makes a duplicate of the given blob info structure, or if
% blob info is NULL, a new one.
%
% The format of the CloneBlobInfo method is:
%
% BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
%
% A description of each parameter follows:
%
% o blob_info: the blob info.
%
*/
MagickExport BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
{
BlobInfo
*clone_info;
SemaphoreInfo
*semaphore;
clone_info=(BlobInfo *) AcquireCriticalMemory(sizeof(*clone_info));
GetBlobInfo(clone_info);
if (blob_info == (BlobInfo *) NULL)
return(clone_info);
semaphore=clone_info->semaphore;
(void) memcpy(clone_info,blob_info,sizeof(*clone_info));
if (blob_info->mapped != MagickFalse)
(void) AcquireMagickResource(MapResource,blob_info->length);
clone_info->semaphore=semaphore;
LockSemaphoreInfo(clone_info->semaphore);
clone_info->reference_count=1;
UnlockSemaphoreInfo(clone_info->semaphore);
return(clone_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ C l o s e B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CloseBlob() closes a stream associated with the image.
%
% The format of the CloseBlob method is:
%
% MagickBooleanType CloseBlob(Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport MagickBooleanType CloseBlob(Image *image)
{
BlobInfo
*magick_restrict blob_info;
int
status;
/*
Close image file.
*/
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
blob_info=image->blob;
if ((blob_info == (BlobInfo *) NULL) || (blob_info->type == UndefinedStream))
return(MagickTrue);
status=SyncBlob(image);
switch (blob_info->type)
{
case UndefinedStream:
case StandardStream:
break;
case FileStream:
case PipeStream:
{
if (blob_info->synchronize != MagickFalse)
status=fsync(fileno(blob_info->file_info.file));
status=ferror(blob_info->file_info.file);
break;
}
case ZipStream:
{
#if defined(MAGICKCORE_ZLIB_DELEGATE)
(void) gzerror(blob_info->file_info.gzfile,&status);
#endif
break;
}
case BZipStream:
{
#if defined(MAGICKCORE_BZLIB_DELEGATE)
(void) BZ2_bzerror(blob_info->file_info.bzfile,&status);
#endif
break;
}
case FifoStream:
break;
case BlobStream:
{
if (blob_info->file_info.file != (FILE *) NULL)
{
if (blob_info->synchronize != MagickFalse)
status=fsync(fileno(blob_info->file_info.file));
status=ferror(blob_info->file_info.file);
}
break;
}
case CustomStream:
break;
}
blob_info->status=status < 0 ? MagickTrue : MagickFalse;
blob_info->size=GetBlobSize(image);
image->extent=blob_info->size;
blob_info->eof=MagickFalse;
blob_info->error=0;
blob_info->mode=UndefinedBlobMode;
if (blob_info->exempt != MagickFalse)
{
blob_info->type=UndefinedStream;
return(blob_info->status);
}
switch (blob_info->type)
{
case UndefinedStream:
case StandardStream:
break;
case FileStream:
{
status=fclose(blob_info->file_info.file);
break;
}
case PipeStream:
{
#if defined(MAGICKCORE_HAVE_PCLOSE)
status=pclose(blob_info->file_info.file);
#endif
break;
}
case ZipStream:
{
#if defined(MAGICKCORE_ZLIB_DELEGATE)
status=gzclose(blob_info->file_info.gzfile);
#endif
break;
}
case BZipStream:
{
#if defined(MAGICKCORE_BZLIB_DELEGATE)
BZ2_bzclose(blob_info->file_info.bzfile);
#endif
break;
}
case FifoStream:
break;
case BlobStream:
{
if (blob_info->file_info.file != (FILE *) NULL)
status=fclose(blob_info->file_info.file);
break;
}
case CustomStream:
break;
}
(void) DetachBlob(blob_info);
blob_info->status=status < 0 ? MagickTrue : MagickFalse;
return(blob_info->status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% C u s t o m S t r e a m T o I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% CustomStreamToImage() is the equivalent of ReadImage(), but reads the
% formatted "file" from the suplied method rather than to an actual file.
%
% The format of the CustomStreamToImage method is:
%
% Image *CustomStreamToImage(const ImageInfo *image_info,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport Image *CustomStreamToImage(const ImageInfo *image_info,
ExceptionInfo *exception)
{
const MagickInfo
*magick_info;
Image
*image;
ImageInfo
*blob_info;
assert(image_info != (ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
assert(image_info->custom_stream->signature == MagickCoreSignature);
assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
assert(exception != (ExceptionInfo *) NULL);
blob_info=CloneImageInfo(image_info);
if (*blob_info->magick == '\0')
(void) SetImageInfo(blob_info,0,exception);
magick_info=GetMagickInfo(blob_info->magick,exception);
if (magick_info == (const MagickInfo *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
blob_info->magick);
blob_info=DestroyImageInfo(blob_info);
return((Image *) NULL);
}
image=(Image *) NULL;
if ((GetMagickBlobSupport(magick_info) != MagickFalse) ||
(*blob_info->filename != '\0'))
{
char
filename[MagickPathExtent];
/*
Native blob support for this image format or SetImageInfo changed the
blob to a file.
*/
(void) CopyMagickString(filename,blob_info->filename,MagickPathExtent);
(void) FormatLocaleString(blob_info->filename,MagickPathExtent,"%s:%s",
blob_info->magick,filename);
image=ReadImage(blob_info,exception);
if (image != (Image *) NULL)
(void) CloseBlob(image);
}
else
{
char
unique[MagickPathExtent];
int
file;
ImageInfo
*clone_info;
unsigned char
*blob;
/*
Write data to file on disk.
*/
blob_info->custom_stream=(CustomStreamInfo *) NULL;
blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
sizeof(*blob));
if (blob == (unsigned char *) NULL)
{
ThrowFileException(exception,BlobError,"UnableToReadBlob",
image_info->filename);
blob_info=DestroyImageInfo(blob_info);
return((Image *) NULL);
}
file=AcquireUniqueFileResource(unique);
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToReadBlob",
image_info->filename);
blob=(unsigned char *) RelinquishMagickMemory(blob);
blob_info=DestroyImageInfo(blob_info);
return((Image *) NULL);
}
clone_info=CloneImageInfo(blob_info);
blob_info->file=fdopen(file,"wb+");
if (blob_info->file != (FILE *) NULL)
{
ssize_t
count;
count=(ssize_t) MagickMaxBufferExtent;
while (count == (ssize_t) MagickMaxBufferExtent)
{
count=image_info->custom_stream->reader(blob,MagickMaxBufferExtent,
image_info->custom_stream->data);
count=(ssize_t) write(file,(const char *) blob,(size_t) count);
}
(void) fclose(blob_info->file);
(void) FormatLocaleString(clone_info->filename,MagickPathExtent,
"%s:%s",blob_info->magick,unique);
image=ReadImage(clone_info,exception);
if (image != (Image *) NULL)
{
Image
*images;
/*
Restore original filenames and image format.
*/
for (images=GetFirstImageInList(image); images != (Image *) NULL; )
{
(void) CopyMagickString(images->filename,image_info->filename,
MagickPathExtent);
(void) CopyMagickString(images->magick_filename,
image_info->filename,MagickPathExtent);
(void) CopyMagickString(images->magick,magick_info->name,
MagickPathExtent);
(void) CloseBlob(images);
images=GetNextImageInList(images);
}
}
}
clone_info=DestroyImageInfo(clone_info);
blob=(unsigned char *) RelinquishMagickMemory(blob);
(void) RelinquishUniqueFileResource(unique);
}
blob_info=DestroyImageInfo(blob_info);
return(image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ D e s t r o y B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DestroyBlob() deallocates memory associated with a blob.
%
% The format of the DestroyBlob method is:
%
% void DestroyBlob(Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport void DestroyBlob(Image *image)
{
BlobInfo
*magick_restrict blob_info;
MagickBooleanType
destroy;
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(image->blob != (BlobInfo *) NULL);
assert(image->blob->signature == MagickCoreSignature);
blob_info=image->blob;
destroy=MagickFalse;
LockSemaphoreInfo(blob_info->semaphore);
blob_info->reference_count--;
assert(blob_info->reference_count >= 0);
if (blob_info->reference_count == 0)
destroy=MagickTrue;
UnlockSemaphoreInfo(blob_info->semaphore);
if (destroy == MagickFalse)
{
image->blob=(BlobInfo *) NULL;
return;
}
(void) CloseBlob(image);
if (blob_info->mapped != MagickFalse)
{
(void) UnmapBlob(blob_info->data,blob_info->length);
RelinquishMagickResource(MapResource,blob_info->length);
}
if (blob_info->semaphore != (SemaphoreInfo *) NULL)
RelinquishSemaphoreInfo(&blob_info->semaphore);
blob_info->signature=(~MagickCoreSignature);
image->blob=(BlobInfo *) RelinquishMagickMemory(blob_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ D e s t r o y C u s t o m S t r e a m I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DestroyCustomStreamInfo() destroys memory associated with the
% CustomStreamInfo structure.
%
% The format of the DestroyCustomStreamInfo method is:
%
% CustomStreamInfo *DestroyCustomStreamInfo(CustomStreamInfo *stream_info)
%
% A description of each parameter follows:
%
% o custom_stream: the custom stream info.
%
*/
MagickExport CustomStreamInfo *DestroyCustomStreamInfo(
CustomStreamInfo *custom_stream)
{
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(custom_stream != (CustomStreamInfo *) NULL);
assert(custom_stream->signature == MagickCoreSignature);
custom_stream->signature=(~MagickCoreSignature);
custom_stream=(CustomStreamInfo *) RelinquishMagickMemory(custom_stream);
return(custom_stream);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ D e t a c h B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DetachBlob() detaches a blob from the BlobInfo structure.
%
% The format of the DetachBlob method is:
%
% void *DetachBlob(BlobInfo *blob_info)
%
% A description of each parameter follows:
%
% o blob_info: Specifies a pointer to a BlobInfo structure.
%
*/
MagickExport void *DetachBlob(BlobInfo *blob_info)
{
void
*data;
assert(blob_info != (BlobInfo *) NULL);
if (blob_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
if (blob_info->mapped != MagickFalse)
{
(void) UnmapBlob(blob_info->data,blob_info->length);
RelinquishMagickResource(MapResource,blob_info->length);
}
blob_info->mapped=MagickFalse;
blob_info->length=0;
blob_info->offset=0;
blob_info->eof=MagickFalse;
blob_info->error=0;
blob_info->exempt=MagickFalse;
blob_info->type=UndefinedStream;
blob_info->file_info.file=(FILE *) NULL;
data=blob_info->data;
blob_info->data=(unsigned char *) NULL;
blob_info->stream=(StreamHandler) NULL;
blob_info->custom_stream=(CustomStreamInfo *) NULL;
return(data);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ D i s a s s o c i a t e B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DisassociateBlob() disassociates the image stream. It checks if the
% blob of the specified image is referenced by other images. If the reference
% count is higher then 1 a new blob is assigned to the specified image.
%
% The format of the DisassociateBlob method is:
%
% void DisassociateBlob(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport void DisassociateBlob(Image *image)
{
BlobInfo
*magick_restrict blob_info,
*clone_info;
MagickBooleanType
clone;
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(image->blob != (BlobInfo *) NULL);
assert(image->blob->signature == MagickCoreSignature);
blob_info=image->blob;
clone=MagickFalse;
LockSemaphoreInfo(blob_info->semaphore);
assert(blob_info->reference_count >= 0);
if (blob_info->reference_count > 1)
clone=MagickTrue;
UnlockSemaphoreInfo(blob_info->semaphore);
if (clone == MagickFalse)
return;
clone_info=CloneBlobInfo(blob_info);
DestroyBlob(image);
image->blob=clone_info;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ D i s c a r d B l o b B y t e s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DiscardBlobBytes() discards bytes in a blob.
%
% The format of the DiscardBlobBytes method is:
%
% MagickBooleanType DiscardBlobBytes(Image *image,
% const MagickSizeType length)
%
% A description of each parameter follows.
%
% o image: the image.
%
% o length: the number of bytes to skip.
%
*/
MagickExport MagickBooleanType DiscardBlobBytes(Image *image,
const MagickSizeType length)
{
register MagickOffsetType
i;
size_t
quantum;
ssize_t
count;
unsigned char
buffer[16384];
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (length != (MagickSizeType) ((MagickOffsetType) length))
return(MagickFalse);
count=0;
for (i=0; i < (MagickOffsetType) length; i+=count)
{
quantum=(size_t) MagickMin(length-i,sizeof(buffer));
(void) ReadBlobStream(image,quantum,buffer,&count);
if (count <= 0)
{
count=0;
if (errno != EINTR)
break;
}
}
return(i < (MagickOffsetType) length ? MagickFalse : MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ D u p l i c a t e s B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DuplicateBlob() duplicates a blob descriptor.
%
% The format of the DuplicateBlob method is:
%
% void DuplicateBlob(Image *image,const Image *duplicate)
%
% A description of each parameter follows:
%
% o image: the image.
%
% o duplicate: the duplicate image.
%
*/
MagickExport void DuplicateBlob(Image *image,const Image *duplicate)
{
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(duplicate != (Image *) NULL);
assert(duplicate->signature == MagickCoreSignature);
DestroyBlob(image);
image->blob=ReferenceBlob(duplicate->blob);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ E O F B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% EOFBlob() returns a non-zero value when EOF has been detected reading from
% a blob or file.
%
% The format of the EOFBlob method is:
%
% int EOFBlob(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport int EOFBlob(const Image *image)
{
BlobInfo
*magick_restrict blob_info;
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(image->blob != (BlobInfo *) NULL);
assert(image->blob->type != UndefinedStream);
blob_info=image->blob;
switch (blob_info->type)
{
case UndefinedStream:
case StandardStream:
break;
case FileStream:
case PipeStream:
{
blob_info->eof=feof(blob_info->file_info.file) != 0 ? MagickTrue :
MagickFalse;
break;
}
case ZipStream:
{
#if defined(MAGICKCORE_ZLIB_DELEGATE)
blob_info->eof=gzeof(blob_info->file_info.gzfile) != 0 ? MagickTrue :
MagickFalse;
#endif
break;
}
case BZipStream:
{
#if defined(MAGICKCORE_BZLIB_DELEGATE)
int
status;
status=0;
(void) BZ2_bzerror(blob_info->file_info.bzfile,&status);
blob_info->eof=status == BZ_UNEXPECTED_EOF ? MagickTrue : MagickFalse;
#endif
break;
}
case FifoStream:
{
blob_info->eof=MagickFalse;
break;
}
case BlobStream:
break;
case CustomStream:
break;
}
return((int) blob_info->eof);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ E r r o r B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ErrorBlob() returns a non-zero value when an error has been detected reading
% from a blob or file.
%
% The format of the ErrorBlob method is:
%
% int ErrorBlob(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport int ErrorBlob(const Image *image)
{
BlobInfo
*magick_restrict blob_info;
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
assert(image->blob != (BlobInfo *) NULL);
assert(image->blob->type != UndefinedStream);
blob_info=image->blob;
switch (blob_info->type)
{
case UndefinedStream:
case StandardStream:
break;
case FileStream:
case PipeStream:
{
blob_info->error=ferror(blob_info->file_info.file);
break;
}
case ZipStream:
{
#if defined(MAGICKCORE_ZLIB_DELEGATE)
(void) gzerror(blob_info->file_info.gzfile,&blob_info->error);
#endif
break;
}
case BZipStream:
{
#if defined(MAGICKCORE_BZLIB_DELEGATE)
(void) BZ2_bzerror(blob_info->file_info.bzfile,&blob_info->error);
#endif
break;
}
case FifoStream:
{
blob_info->error=0;
break;
}
case BlobStream:
break;
case CustomStream:
break;
}
return(blob_info->error);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% F i l e T o B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FileToBlob() returns the contents of a file as a buffer terminated with
% the '\0' character. The length of the buffer (not including the extra
% terminating '\0' character) is returned via the 'length' parameter. Free
% the buffer with RelinquishMagickMemory().
%
% The format of the FileToBlob method is:
%
% void *FileToBlob(const char *filename,const size_t extent,
% size_t *length,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o blob: FileToBlob() returns the contents of a file as a blob. If
% an error occurs NULL is returned.
%
% o filename: the filename.
%
% o extent: The maximum length of the blob.
%
% o length: On return, this reflects the actual length of the blob.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport void *FileToBlob(const char *filename,const size_t extent,
size_t *length,ExceptionInfo *exception)
{
int
file;
MagickBooleanType
status;
MagickOffsetType
offset;
register size_t
i;
ssize_t
count;
struct stat
attributes;
unsigned char
*blob;
void
*map;
assert(filename != (const char *) NULL);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
assert(exception != (ExceptionInfo *) NULL);
*length=0;
status=IsRightsAuthorized(PathPolicyDomain,ReadPolicyRights,filename);
if (status == MagickFalse)
{
errno=EPERM;
(void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
"NotAuthorized","`%s'",filename);
return(NULL);
}
file=fileno(stdin);
if (LocaleCompare(filename,"-") != 0)
{
status=GetPathAttributes(filename,&attributes);
if ((status == MagickFalse) || (S_ISDIR(attributes.st_mode) != 0))
{
ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
return(NULL);
}
file=open_utf8(filename,O_RDONLY | O_BINARY,0);
}
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
return(NULL);
}
offset=(MagickOffsetType) lseek(file,0,SEEK_END);
count=0;
if ((file == fileno(stdin)) || (offset < 0) ||
(offset != (MagickOffsetType) ((ssize_t) offset)))
{
size_t
quantum;
struct stat
file_stats;
/*
Stream is not seekable.
*/
offset=(MagickOffsetType) lseek(file,0,SEEK_SET);
quantum=(size_t) MagickMaxBufferExtent;
if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
for (i=0; blob != (unsigned char *) NULL; i+=count)
{
count=read(file,blob+i,quantum);
if (count <= 0)
{
count=0;
if (errno != EINTR)
break;
}
if (~((size_t) i) < (quantum+1))
{
blob=(unsigned char *) RelinquishMagickMemory(blob);
break;
}
blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
sizeof(*blob));
if ((size_t) (i+count) >= extent)
break;
}
if (LocaleCompare(filename,"-") != 0)
file=close(file);
if (blob == (unsigned char *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
return(NULL);
}
if (file == -1)
{
blob=(unsigned char *) RelinquishMagickMemory(blob);
ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
return(NULL);
}
*length=(size_t) MagickMin(i+count,extent);
blob[*length]='\0';
return(blob);
}
*length=(size_t) MagickMin(offset,(MagickOffsetType)
MagickMin(extent,(size_t) SSIZE_MAX));
blob=(unsigned char *) NULL;
if (~(*length) >= (MagickPathExtent-1))
blob=(unsigned char *) AcquireQuantumMemory(*length+MagickPathExtent,
sizeof(*blob));
if (blob == (unsigned char *) NULL)
{
file=close(file);
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
return(NULL);
}
map=MapBlob(file,ReadMode,0,*length);
if (map != (unsigned char *) NULL)
{
(void) memcpy(blob,map,*length);
(void) UnmapBlob(map,*length);
}
else
{
(void) lseek(file,0,SEEK_SET);
for (i=0; i < *length; i+=count)
{
count=read(file,blob+i,(size_t) MagickMin(*length-i,(size_t)
SSIZE_MAX));
if (count <= 0)
{
count=0;
if (errno != EINTR)
break;
}
}
if (i < *length)
{
file=close(file)-1;
blob=(unsigned char *) RelinquishMagickMemory(blob);
ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
return(NULL);
}
}
blob[*length]='\0';
if (LocaleCompare(filename,"-") != 0)
file=close(file);
if (file == -1)
{
blob=(unsigned char *) RelinquishMagickMemory(blob);
ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
}
return(blob);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% F i l e T o I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FileToImage() write the contents of a file to an image.
%
% The format of the FileToImage method is:
%
% MagickBooleanType FileToImage(Image *,const char *filename)
%
% A description of each parameter follows:
%
% o image: the image.
%
% o filename: the filename.
%
*/
static inline ssize_t WriteBlobStream(Image *image,const size_t length,
const void *data)
{
BlobInfo
*magick_restrict blob_info;
MagickSizeType
extent;
register unsigned char
*q;
assert(image->blob != (BlobInfo *) NULL);
assert(image->blob->type != UndefinedStream);
assert(data != NULL);
blob_info=image->blob;
if (blob_info->type != BlobStream)
return(WriteBlob(image,length,(const unsigned char *) data));
extent=(MagickSizeType) (blob_info->offset+(MagickOffsetType) length);
if (extent >= blob_info->extent)
{
extent=blob_info->extent+blob_info->quantum+length;
blob_info->quantum<<=1;
if (SetBlobExtent(image,extent) == MagickFalse)
return(0);
}
q=blob_info->data+blob_info->offset;
(void) memcpy(q,data,length);
blob_info->offset+=length;
if (blob_info->offset >= (MagickOffsetType) blob_info->length)
blob_info->length=(size_t) blob_info->offset;
return((ssize_t) length);
}
MagickExport MagickBooleanType FileToImage(Image *image,const char *filename,
ExceptionInfo *exception)
{
int
file;
MagickBooleanType
status;
size_t
length,
quantum;
ssize_t
count;
struct stat
file_stats;
unsigned char
*blob;
assert(image != (const Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(filename != (const char *) NULL);
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
status=IsRightsAuthorized(PathPolicyDomain,WritePolicyRights,filename);
if (status == MagickFalse)
{
errno=EPERM;
(void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
"NotAuthorized","`%s'",filename);
return(MagickFalse);
}
file=fileno(stdin);
if (LocaleCompare(filename,"-") != 0)
file=open_utf8(filename,O_RDONLY | O_BINARY,0);
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
return(MagickFalse);
}
quantum=(size_t) MagickMaxBufferExtent;
if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
if (blob == (unsigned char *) NULL)
{
file=close(file);
ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
filename);
return(MagickFalse);
}
for ( ; ; )
{
count=read(file,blob,quantum);
if (count <= 0)
{
count=0;
if (errno != EINTR)
break;
}
length=(size_t) count;
count=WriteBlobStream(image,length,blob);
if (count != (ssize_t) length)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
break;
}
}
file=close(file);
if (file == -1)
ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
blob=(unsigned char *) RelinquishMagickMemory(blob);
return(MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t B l o b E r r o r %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetBlobError() returns MagickTrue if the blob associated with the specified
% image encountered an error.
%
% The format of the GetBlobError method is:
%
% MagickBooleanType GetBlobError(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport MagickBooleanType GetBlobError(const Image *image)
{
assert(image != (const Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
return(image->blob->status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t B l o b F i l e H a n d l e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetBlobFileHandle() returns the file handle associated with the image blob.
%
% The format of the GetBlobFile method is:
%
% FILE *GetBlobFileHandle(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport FILE *GetBlobFileHandle(const Image *image)
{
assert(image != (const Image *) NULL);
assert(image->signature == MagickCoreSignature);
return(image->blob->file_info.file);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t B l o b I n f o %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetBlobInfo() initializes the BlobInfo structure.
%
% The format of the GetBlobInfo method is:
%
% void GetBlobInfo(BlobInfo *blob_info)
%
% A description of each parameter follows:
%
% o blob_info: Specifies a pointer to a BlobInfo structure.
%
*/
MagickExport void GetBlobInfo(BlobInfo *blob_info)
{
assert(blob_info != (BlobInfo *) NULL);
(void) memset(blob_info,0,sizeof(*blob_info));
blob_info->type=UndefinedStream;
blob_info->quantum=(size_t) MagickMaxBlobExtent;
blob_info->properties.st_mtime=time((time_t *) NULL);
blob_info->properties.st_ctime=blob_info->properties.st_mtime;
blob_info->debug=IsEventLogging();
blob_info->reference_count=1;
blob_info->semaphore=AcquireSemaphoreInfo();
blob_info->signature=MagickCoreSignature;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% G e t B l o b P r o p e r t i e s %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetBlobProperties() returns information about an image blob.
%
% The format of the GetBlobProperties method is:
%
% const struct stat *GetBlobProperties(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport const struct stat *GetBlobProperties(const Image *image)
{
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
return(&image->blob->properties);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t B l o b S i z e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetBlobSize() returns the current length of the image file or blob; zero is
% returned if the size cannot be determined.
%
% The format of the GetBlobSize method is:
%
% MagickSizeType GetBlobSize(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport MagickSizeType GetBlobSize(const Image *image)
{
BlobInfo
*magick_restrict blob_info;
MagickSizeType
extent;
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(image->blob != (BlobInfo *) NULL);
blob_info=image->blob;
extent=0;
switch (blob_info->type)
{
case UndefinedStream:
case StandardStream:
{
extent=blob_info->size;
break;
}
case FileStream:
{
if (fstat(fileno(blob_info->file_info.file),&blob_info->properties) == 0)
extent=(MagickSizeType) blob_info->properties.st_size;
break;
}
case PipeStream:
{
extent=blob_info->size;
break;
}
case ZipStream:
case BZipStream:
{
MagickBooleanType
status;
status=GetPathAttributes(image->filename,&blob_info->properties);
if (status != MagickFalse)
extent=(MagickSizeType) blob_info->properties.st_size;
break;
}
case FifoStream:
break;
case BlobStream:
{
extent=(MagickSizeType) blob_info->length;
break;
}
case CustomStream:
{
if ((blob_info->custom_stream->teller != (CustomStreamTeller) NULL) &&
(blob_info->custom_stream->seeker != (CustomStreamSeeker) NULL))
{
MagickOffsetType
offset;
offset=blob_info->custom_stream->teller(
blob_info->custom_stream->data);
extent=(MagickSizeType) blob_info->custom_stream->seeker(0,SEEK_END,
blob_info->custom_stream->data);
(void) blob_info->custom_stream->seeker(offset,SEEK_SET,
blob_info->custom_stream->data);
}
break;
}
}
return(extent);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t B l o b S t r e a m D a t a %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetBlobStreamData() returns the stream data for the image.
%
% The format of the GetBlobStreamData method is:
%
% void *GetBlobStreamData(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport void *GetBlobStreamData(const Image *image)
{
assert(image != (const Image *) NULL);
assert(image->signature == MagickCoreSignature);
return(image->blob->data);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t B l o b S t r e a m H a n d l e r %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetBlobStreamHandler() returns the stream handler for the image.
%
% The format of the GetBlobStreamHandler method is:
%
% StreamHandler GetBlobStreamHandler(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport StreamHandler GetBlobStreamHandler(const Image *image)
{
assert(image != (const Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
return(image->blob->stream);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I m a g e T o B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ImageToBlob() implements direct to memory image formats. It returns the
% image as a formatted blob and its length. The magick member of the Image
% structure determines the format of the returned blob (GIF, JPEG, PNG,
% etc.). This method is the equivalent of WriteImage(), but writes the
% formatted "file" to a memory buffer rather than to an actual file.
%
% The format of the ImageToBlob method is:
%
% void *ImageToBlob(const ImageInfo *image_info,Image *image,
% size_t *length,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o image: the image.
%
% o length: return the actual length of the blob.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport void *ImageToBlob(const ImageInfo *image_info,
Image *image,size_t *length,ExceptionInfo *exception)
{
const MagickInfo
*magick_info;
ImageInfo
*blob_info;
MagickBooleanType
status;
void
*blob;
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(exception != (ExceptionInfo *) NULL);
*length=0;
blob=(unsigned char *) NULL;
blob_info=CloneImageInfo(image_info);
blob_info->adjoin=MagickFalse;
(void) SetImageInfo(blob_info,1,exception);
if (*blob_info->magick != '\0')
(void) CopyMagickString(image->magick,blob_info->magick,MagickPathExtent);
magick_info=GetMagickInfo(image->magick,exception);
if (magick_info == (const MagickInfo *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
image->magick);
blob_info=DestroyImageInfo(blob_info);
return(blob);
}
(void) CopyMagickString(blob_info->magick,image->magick,MagickPathExtent);
if (GetMagickBlobSupport(magick_info) != MagickFalse)
{
/*
Native blob support for this image format.
*/
blob_info->length=0;
blob_info->blob=AcquireQuantumMemory(MagickMaxBlobExtent,
sizeof(unsigned char));
if (blob_info->blob == NULL)
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
else
{
(void) CloseBlob(image);
image->blob->exempt=MagickTrue;
*image->filename='\0';
status=WriteImage(blob_info,image,exception);
*length=image->blob->length;
blob=DetachBlob(image->blob);
if (blob == (void *) NULL)
blob_info->blob=RelinquishMagickMemory(blob_info->blob);
else if (status == MagickFalse)
blob=RelinquishMagickMemory(blob);
else
blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
}
}
else
{
char
unique[MagickPathExtent];
int
file;
/*
Write file to disk in blob image format.
*/
file=AcquireUniqueFileResource(unique);
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",
image_info->filename);
}
else
{
blob_info->file=fdopen(file,"wb");
if (blob_info->file != (FILE *) NULL)
{
(void) FormatLocaleString(image->filename,MagickPathExtent,
"%s:%s",image->magick,unique);
status=WriteImage(blob_info,image,exception);
(void) CloseBlob(image);
(void) fclose(blob_info->file);
if (status != MagickFalse)
blob=FileToBlob(unique,~0UL,length,exception);
}
(void) RelinquishUniqueFileResource(unique);
}
}
blob_info=DestroyImageInfo(blob_info);
return(blob);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ I m a g e T o C u s t o m S t r e a m %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ImageToCustomStream() is the equivalent of WriteImage(), but writes the
% formatted "file" to the custom stream rather than to an actual file.
%
% The format of the ImageToCustomStream method is:
%
% void ImageToCustomStream(const ImageInfo *image_info,Image *image,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o image: the image.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport void ImageToCustomStream(const ImageInfo *image_info,Image *image,
ExceptionInfo *exception)
{
const MagickInfo
*magick_info;
ImageInfo
*clone_info;
MagickBooleanType
blob_support,
status;
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
assert(image_info->custom_stream->signature == MagickCoreSignature);
assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
assert(exception != (ExceptionInfo *) NULL);
clone_info=CloneImageInfo(image_info);
clone_info->adjoin=MagickFalse;
(void) SetImageInfo(clone_info,1,exception);
if (*clone_info->magick != '\0')
(void) CopyMagickString(image->magick,clone_info->magick,MagickPathExtent);
magick_info=GetMagickInfo(image->magick,exception);
if (magick_info == (const MagickInfo *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
image->magick);
clone_info=DestroyImageInfo(clone_info);
return;
}
(void) CopyMagickString(clone_info->magick,image->magick,MagickPathExtent);
blob_support=GetMagickBlobSupport(magick_info);
if ((blob_support != MagickFalse) &&
(GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
{
if ((clone_info->custom_stream->seeker == (CustomStreamSeeker) NULL) ||
(clone_info->custom_stream->teller == (CustomStreamTeller) NULL))
blob_support=MagickFalse;
}
if (blob_support != MagickFalse)
{
/*
Native blob support for this image format.
*/
(void) CloseBlob(image);
*image->filename='\0';
(void) WriteImage(clone_info,image,exception);
(void) CloseBlob(image);
}
else
{
char
unique[MagickPathExtent];
int
file;
unsigned char
*blob;
/*
Write file to disk in blob image format.
*/
clone_info->custom_stream=(CustomStreamInfo *) NULL;
blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
sizeof(*blob));
if (blob == (unsigned char *) NULL)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",
image_info->filename);
clone_info=DestroyImageInfo(clone_info);
return;
}
file=AcquireUniqueFileResource(unique);
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",
image_info->filename);
blob=(unsigned char *) RelinquishMagickMemory(blob);
clone_info=DestroyImageInfo(clone_info);
return;
}
clone_info->file=fdopen(file,"wb+");
if (clone_info->file != (FILE *) NULL)
{
ssize_t
count;
(void) FormatLocaleString(image->filename,MagickPathExtent,
"%s:%s",image->magick,unique);
status=WriteImage(clone_info,image,exception);
(void) CloseBlob(image);
if (status != MagickFalse)
{
(void) fseek(clone_info->file,0,SEEK_SET);
count=(ssize_t) MagickMaxBufferExtent;
while (count == (ssize_t) MagickMaxBufferExtent)
{
count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
clone_info->file);
(void) image_info->custom_stream->writer(blob,(size_t) count,
image_info->custom_stream->data);
}
}
(void) fclose(clone_info->file);
}
blob=(unsigned char *) RelinquishMagickMemory(blob);
(void) RelinquishUniqueFileResource(unique);
}
clone_info=DestroyImageInfo(clone_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I m a g e T o F i l e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ImageToFile() writes an image to a file. It returns MagickFalse if an error
% occurs otherwise MagickTrue.
%
% The format of the ImageToFile method is:
%
% MagickBooleanType ImageToFile(Image *image,char *filename,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: the image.
%
% o filename: Write the image to this file.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType ImageToFile(Image *image,char *filename,
ExceptionInfo *exception)
{
int
file;
register const unsigned char
*p;
register size_t
i;
size_t
length,
quantum;
ssize_t
count;
struct stat
file_stats;
unsigned char
*buffer;
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(image->blob != (BlobInfo *) NULL);
assert(image->blob->type != UndefinedStream);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
assert(filename != (const char *) NULL);
if (*filename == '\0')
file=AcquireUniqueFileResource(filename);
else
if (LocaleCompare(filename,"-") == 0)
file=fileno(stdout);
else
file=open_utf8(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
return(MagickFalse);
}
quantum=(size_t) MagickMaxBufferExtent;
if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
if (buffer == (unsigned char *) NULL)
{
file=close(file)-1;
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationError","`%s'",filename);
return(MagickFalse);
}
length=0;
p=(const unsigned char *) ReadBlobStream(image,quantum,buffer,&count);
for (i=0; count > 0; )
{
length=(size_t) count;
for (i=0; i < length; i+=count)
{
count=write(file,p+i,(size_t) (length-i));
if (count <= 0)
{
count=0;
if (errno != EINTR)
break;
}
}
if (i < length)
break;
p=(const unsigned char *) ReadBlobStream(image,quantum,buffer,&count);
}
if (LocaleCompare(filename,"-") != 0)
file=close(file);
buffer=(unsigned char *) RelinquishMagickMemory(buffer);
if ((file == -1) || (i < length))
{
if (file != -1)
file=close(file);
ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
return(MagickFalse);
}
return(MagickTrue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I m a g e s T o B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ImagesToBlob() implements direct to memory image formats. It returns the
% image sequence as a blob and its length. The magick member of the ImageInfo
% structure determines the format of the returned blob (GIF, JPEG, PNG, etc.)
%
% Note, some image formats do not permit multiple images to the same image
% stream (e.g. JPEG). in this instance, just the first image of the
% sequence is returned as a blob.
%
% The format of the ImagesToBlob method is:
%
% void *ImagesToBlob(const ImageInfo *image_info,Image *images,
% size_t *length,ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o images: the image list.
%
% o length: return the actual length of the blob.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images,
size_t *length,ExceptionInfo *exception)
{
const MagickInfo
*magick_info;
ImageInfo
*clone_info;
MagickBooleanType
status;
void
*blob;
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(images != (Image *) NULL);
assert(images->signature == MagickCoreSignature);
assert(exception != (ExceptionInfo *) NULL);
*length=0;
blob=(unsigned char *) NULL;
clone_info=CloneImageInfo(image_info);
(void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(images),
exception);
if (*clone_info->magick != '\0')
(void) CopyMagickString(images->magick,clone_info->magick,MagickPathExtent);
magick_info=GetMagickInfo(images->magick,exception);
if (magick_info == (const MagickInfo *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
images->magick);
clone_info=DestroyImageInfo(clone_info);
return(blob);
}
if (GetMagickAdjoin(magick_info) == MagickFalse)
{
clone_info=DestroyImageInfo(clone_info);
return(ImageToBlob(image_info,images,length,exception));
}
(void) CopyMagickString(clone_info->magick,images->magick,MagickPathExtent);
if (GetMagickBlobSupport(magick_info) != MagickFalse)
{
/*
Native blob support for this images format.
*/
clone_info->length=0;
clone_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
sizeof(unsigned char));
if (clone_info->blob == (void *) NULL)
(void) ThrowMagickException(exception,GetMagickModule(),
ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
else
{
(void) CloseBlob(images);
images->blob->exempt=MagickTrue;
*images->filename='\0';
status=WriteImages(clone_info,images,images->filename,exception);
*length=images->blob->length;
blob=DetachBlob(images->blob);
if (blob == (void *) NULL)
clone_info->blob=RelinquishMagickMemory(clone_info->blob);
else if (status == MagickFalse)
blob=RelinquishMagickMemory(blob);
else
blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
}
}
else
{
char
filename[MagickPathExtent],
unique[MagickPathExtent];
int
file;
/*
Write file to disk in blob images format.
*/
file=AcquireUniqueFileResource(unique);
if (file == -1)
{
ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",
image_info->filename);
}
else
{
clone_info->file=fdopen(file,"wb");
if (clone_info->file != (FILE *) NULL)
{
(void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
images->magick,unique);
status=WriteImages(clone_info,images,filename,exception);
(void) CloseBlob(images);
(void) fclose(clone_info->file);
if (status != MagickFalse)
blob=FileToBlob(unique,~0UL,length,exception);
}
(void) RelinquishUniqueFileResource(unique);
}
}
clone_info=DestroyImageInfo(clone_info);
return(blob);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ I m a g e s T o C u s t o m B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ImagesToCustomStream() is the equivalent of WriteImages(), but writes the
% formatted "file" to the custom stream rather than to an actual file.
%
% The format of the ImageToCustomStream method is:
%
% void ImagesToCustomStream(const ImageInfo *image_info,Image *images,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o images: the image list.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport void ImagesToCustomStream(const ImageInfo *image_info,
Image *images,ExceptionInfo *exception)
{
const MagickInfo
*magick_info;
ImageInfo
*clone_info;
MagickBooleanType
blob_support,
status;
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(images != (Image *) NULL);
assert(images->signature == MagickCoreSignature);
assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
assert(image_info->custom_stream->signature == MagickCoreSignature);
assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
assert(exception != (ExceptionInfo *) NULL);
clone_info=CloneImageInfo(image_info);
(void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(images),
exception);
if (*clone_info->magick != '\0')
(void) CopyMagickString(images->magick,clone_info->magick,MagickPathExtent);
magick_info=GetMagickInfo(images->magick,exception);
if (magick_info == (const MagickInfo *) NULL)
{
(void) ThrowMagickException(exception,GetMagickModule(),
MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
images->magick);
clone_info=DestroyImageInfo(clone_info);
return;
}
(void) CopyMagickString(clone_info->magick,images->magick,MagickPathExtent);
blob_support=GetMagickBlobSupport(magick_info);
if ((blob_support != MagickFalse) &&
(GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
{
if ((clone_info->custom_stream->seeker == (CustomStreamSeeker) NULL) ||
(clone_info->custom_stream->teller == (CustomStreamTeller) NULL))
blob_support=MagickFalse;
}
if (blob_support != MagickFalse)
{
/*
Native blob support for this image format.
*/
(void) CloseBlob(images);
*images->filename='\0';
(void) WriteImages(clone_info,images,images->filename,exception);
(void) CloseBlob(images);
}
else
{
char
filename[MagickPathExtent],
unique[MagickPathExtent];
int
file;
unsigned char
*blob;
/*
Write file to disk in blob image format.
*/
clone_info->custom_stream=(CustomStreamInfo *) NULL;
blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
sizeof(*blob));
if (blob == (unsigned char *) NULL)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",
image_info->filename);
clone_info=DestroyImageInfo(clone_info);
return;
}
file=AcquireUniqueFileResource(unique);
if (file == -1)
{
ThrowFileException(exception,BlobError,"UnableToWriteBlob",
image_info->filename);
blob=(unsigned char *) RelinquishMagickMemory(blob);
clone_info=DestroyImageInfo(clone_info);
return;
}
clone_info->file=fdopen(file,"wb+");
if (clone_info->file != (FILE *) NULL)
{
ssize_t
count;
(void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
images->magick,unique);
status=WriteImages(clone_info,images,filename,exception);
(void) CloseBlob(images);
if (status != MagickFalse)
{
(void) fseek(clone_info->file,0,SEEK_SET);
count=(ssize_t) MagickMaxBufferExtent;
while (count == (ssize_t) MagickMaxBufferExtent)
{
count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
clone_info->file);
(void) image_info->custom_stream->writer(blob,(size_t) count,
image_info->custom_stream->data);
}
}
(void) fclose(clone_info->file);
}
blob=(unsigned char *) RelinquishMagickMemory(blob);
(void) RelinquishUniqueFileResource(unique);
}
clone_info=DestroyImageInfo(clone_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I n j e c t I m a g e B l o b %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% InjectImageBlob() injects the image with a copy of itself in the specified
% format (e.g. inject JPEG into a PDF image).
%
% The format of the InjectImageBlob method is:
%
% MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
% Image *image,Image *inject_image,const char *format,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image_info: the image info..
%
% o image: the image.
%
% o inject_image: inject into the image stream.
%
% o format: the image format.
%
% o exception: return any errors or warnings in this structure.
%
*/
MagickExport MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
Image *image,Image *inject_image,const char *format,ExceptionInfo *exception)
{
char
filename[MagickPathExtent];
FILE
*unique_file;
Image
*byte_image;
ImageInfo
*write_info;
int
file;
MagickBooleanType
status;
register ssize_t
i;
size_t
quantum;
ssize_t
count;
struct stat
file_stats;
unsigned char
*buffer;
/*
Write inject image to a temporary file.
*/
assert(image_info != (ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);
assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
assert(inject_image != (Image *) NULL);
assert(inject_image->signature == MagickCoreSignature);
assert(exception != (ExceptionInfo *) NULL);
unique_file=(FILE *) NULL;
file=AcquireUniqueFileResource(filename);
if (file != -1)
unique_file=fdopen(file,"wb");
if ((file == -1) || (unique_file == (FILE *) NULL))
{
(void) CopyMagickString(image->filename,filename,MagickPathExtent);
ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
image->filename);
return(MagickFalse);
}
byte_image=CloneImage(inject_image,0,0,MagickFalse,exception);
if (byte_image == (Image *) NULL)
{
(void) fclose(unique_file);
(void) RelinquishUniqueFileResource(filename);
return(MagickFalse);
}
(void) FormatLocaleString(byte_image->filename,MagickPathExtent,"%s:%s",
format,filename);
DestroyBlob(byte_image);
byte_image->blob=CloneBlobInfo((BlobInfo *) NULL);
write_info=CloneImageInfo(image_info);
SetImageInfoFile(write_info,unique_file);
status=WriteImage(write_info,byte_image,exception);
write_info=DestroyImageInfo(write_info);
byte_image=DestroyImage(byte_image);
(void) fclose(unique_file);
if (status == MagickFalse)
{
(void) RelinquishUniqueFileResource(filename);
return(MagickFalse);
}
/*
Inject into image stream.
*/
file=open_utf8(filename,O_RDONLY | O_BINARY,0);
if (file == -1)
{
(void) RelinquishUniqueFileResource(filename);
ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
image_info->filename);
return(MagickFalse);
}
quantum=(size_t) MagickMaxBufferExtent;
if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
if (buffer == (unsigned char *) NULL)
{
(void) RelinquishUniqueFileResource(filename);
file=close(file);
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
image->filename);
}
for (i=0; ; i+=count)
{
count=read(file,buffer,quantum);
if (count <= 0)
{
count=0;
if (errno != EINTR)
break;
}
status=WriteBlobStream(image,(size_t) count,buffer) == count ? MagickTrue :
MagickFalse;
}
file=close(file);
if (file == -1)
ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",filename);
(void) RelinquishUniqueFileResource(filename);
buffer=(unsigned char *) RelinquishMagickMemory(buffer);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I s B l o b E x e m p t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IsBlobExempt() returns true if the blob is exempt.
%
% The format of the IsBlobExempt method is:
%
% MagickBooleanType IsBlobExempt(const Image *image)
%
% A description of each parameter follows:
%
% o image: the image.
%
*/
MagickExport MagickBooleanType IsBlobExempt(const Image *image)
{
assert(image != (const Image *) NULL);
assert(image->signature == MagickCoreSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
return(image->blob->exempt);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I s B l o b S e e k a b l e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IsBlobSeekable() returns true if the blob is seekable.