root / ImageMagick / trunk / magick / blob.c

Revision 11670, 135.0 kB (checked in by cristy, 6 weeks ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                         BBBB   L       OOO   BBBB                           %
7%                         B   B  L      O   O  B   B                          %
8%                         BBBB   L      O   O  BBBB                           %
9%                         B   B  L      O   O  B   B                          %
10%                         BBBB   LLLLL   OOO   BBBB                           %
11%                                                                             %
12%                                                                             %
13%                    ImageMagick Binary Large OBjectS Methods                 %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1999                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/client.h"
48#include "magick/constitute.h"
49#include "magick/delegate.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
52#include "magick/image-private.h"
53#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
57#include "magick/resource_.h"
58#include "magick/semaphore.h"
59#include "magick/string_.h"
60#include "magick/utility.h"
61#if defined(MAGICKCORE_HAVE_MMAP_FILEIO) && !defined(__WINDOWS__)
62# include <sys/mman.h>
63#endif
64#if defined(MAGICKCORE_ZLIB_DELEGATE)
65#include "zlib.h"
66#endif
67#if defined(MAGICKCORE_BZLIB_DELEGATE)
68#include "bzlib.h"
69#endif
70
71/*
72  Define declarations.
73*/
74#if defined(MAGICKCORE_HAVE_FSEEKO)
75# define fseek  fseeko
76# define ftell  ftello
77#endif
78#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
79# define MAP_ANONYMOUS  MAP_ANON
80#endif
81#if !defined(MAP_FAILED)
82#define MAP_FAILED  ((void *) -1)
83#endif
84#if !defined(MS_SYNC)
85#define MS_SYNC  0x04
86#endif
87
88/*
89  Typedef declarations.
90*/
91struct _BlobInfo
92{
93  size_t
94    length,
95    extent,
96    quantum;
97
98  MagickBooleanType
99    mapped,
100    eof;
101
102  MagickOffsetType
103    offset;
104
105  MagickSizeType
106    size;
107
108  MagickBooleanType
109    exempt,
110    status,
111    temporary;
112
113  StreamType
114    type;
115
116  FILE
117    *file;
118
119  struct stat
120    properties;
121
122  StreamHandler
123    stream;
124
125  unsigned char
126    *data;
127
128  MagickBooleanType
129    debug;
130
131  SemaphoreInfo
132    *semaphore;
133
134  long
135    reference_count;
136
137  unsigned long
138    signature;
139};
140
141/*
142  Forward declarations.
143*/
144static int
145  SyncBlob(Image *);
146
147/*
148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149%                                                                             %
150%                                                                             %
151%                                                                             %
152+   A t t a c h B l o b                                                       %
153%                                                                             %
154%                                                                             %
155%                                                                             %
156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157%
158%  AttachBlob() attaches a blob to the BlobInfo structure.
159%
160%  The format of the AttachBlob method is:
161%
162%      void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
163%
164%  A description of each parameter follows:
165%
166%    o blob_info: Specifies a pointer to a BlobInfo structure.
167%
168%    o blob: the address of a character stream in one of the image formats
169%      understood by ImageMagick.
170%
171%    o length: This size_t integer reflects the length in bytes of the blob.
172%
173*/
174MagickExport void AttachBlob(BlobInfo *blob_info,const void *blob,
175  const size_t length)
176{
177  assert(blob_info != (BlobInfo *) NULL);
178  if (blob_info->debug != MagickFalse)
179    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
180  blob_info->length=length;
181  blob_info->extent=length;
182  blob_info->quantum=(size_t) MagickMaxBufferSize;
183  blob_info->offset=0;
184  blob_info->type=BlobStream;
185  blob_info->file=(FILE *) NULL;
186  blob_info->data=(unsigned char *) blob;
187  blob_info->mapped=MagickFalse;
188}
189
190/*
191%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
192%                                                                             %
193%                                                                             %
194%                                                                             %
195+   B l o b T o F i l e                                                       %
196%                                                                             %
197%                                                                             %
198%                                                                             %
199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200%
201%  BlobToFile() writes a blob to a file.  It returns MagickFalse if an error
202%  occurs otherwise MagickTrue.
203%
204%  The format of the BlobToFile method is:
205%
206%       MagickBooleanType BlobToFile(char *filename,const void *blob,
207%        const size_t length,ExceptionInfo *exception)
208%
209%  A description of each parameter follows:
210%
211%    o filename: Write the blob to this file.
212%
213%    o blob: the address of a blob.
214%
215%    o length: This length in bytes of the blob.
216%
217%    o exception: Return any errors or warnings in this structure.
218%
219*/
220
221static inline size_t MagickMin(const size_t x,const size_t y)
222{
223  if (x < y)
224    return(x);
225  return(y);
226}
227
228MagickExport MagickBooleanType BlobToFile(char *filename,const void *blob,
229  const size_t length,ExceptionInfo *exception)
230{
231  int
232    file;
233
234  register size_t
235    i;
236
237  ssize_t
238    count;
239
240  assert(filename != (const char *) NULL);
241  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
242  assert(blob != (const void *) NULL);
243  if (*filename == '\0')
244    file=AcquireUniqueFileResource(filename);
245  else
246    file=open(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
247  if (file == -1)
248    {
249      ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
250      return(MagickFalse);
251    }
252  for (i=0; i < length; i+=count)
253  {
254    count=(ssize_t) write(file,(const char *) blob+i,MagickMin(length-i,(size_t)
255      SSIZE_MAX));
256    if (count <= 0)
257      {
258        count=0;
259        if (errno != EINTR)
260          break;
261      }
262  }
263  file=close(file)-1;
264  if (i < length)
265    {
266      ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
267      return(MagickFalse);
268    }
269  return(MagickTrue);
270}
271
272/*
273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274%                                                                             %
275%                                                                             %
276%                                                                             %
277%   B l o b T o I m a g e                                                     %
278%                                                                             %
279%                                                                             %
280%                                                                             %
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282%
283%  BlobToImage() implements direct to memory image formats.  It returns the
284%  blob as an image.
285%
286%  The format of the BlobToImage method is:
287%
288%      Image *BlobToImage(const ImageInfo *image_info,const void *blob,
289%        const size_t length,ExceptionInfo *exception)
290%
291%  A description of each parameter follows:
292%
293%    o image_info: the image info.
294%
295%    o blob: the address of a character stream in one of the image formats
296%      understood by ImageMagick.
297%
298%    o length: This size_t integer reflects the length in bytes of the blob.
299%
300%    o exception: Return any errors or warnings in this structure.
301%
302*/
303MagickExport Image *BlobToImage(const ImageInfo *image_info,const void *blob,
304  const size_t length,ExceptionInfo *exception)
305{
306  const MagickInfo
307    *magick_info;
308
309  Image
310    *image;
311
312  ImageInfo
313    *blob_info;
314
315  MagickBooleanType
316    status;
317
318  assert(image_info != (ImageInfo *) NULL);
319  assert(image_info->signature == MagickSignature);
320  if (image_info->debug != MagickFalse)
321    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
322      image_info->filename);
323  assert(exception != (ExceptionInfo *) NULL);
324  if ((blob == (const void *) NULL) || (length == 0))
325    {
326      (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
327        "ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
328      return((Image *) NULL);
329    }
330  blob_info=CloneImageInfo(image_info);
331  blob_info->blob=(void *) blob;
332  blob_info->length=length;
333  if (*blob_info->magick == '\0')
334    (void) SetImageInfo(blob_info,MagickFalse,exception);
335  magick_info=GetMagickInfo(blob_info->magick,exception);
336  if (magick_info == (const MagickInfo *) NULL)
337    {
338      blob_info=DestroyImageInfo(blob_info);
339      (void) ThrowMagickException(exception,GetMagickModule(),
340        MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
341        image_info->filename);
342      return((Image *) NULL);
343    }
344  if (GetMagickBlobSupport(magick_info) != MagickFalse)
345    {
346      /*
347        Native blob support for this image format.
348      */
349      (void) CopyMagickString(blob_info->filename,image_info->filename,
350        MaxTextExtent);
351      (void) CopyMagickString(blob_info->magick,image_info->magick,
352        MaxTextExtent);
353      image=ReadImage(blob_info,exception);
354      if (image != (Image *) NULL)
355        (void) DetachBlob(image->blob);
356      blob_info=DestroyImageInfo(blob_info);
357      return(image);
358    }
359  /*
360    Write blob to a temporary file on disk.
361  */
362  blob_info->blob=(void *) NULL;
363  blob_info->length=0;
364  *blob_info->filename='\0';
365  status=BlobToFile(blob_info->filename,blob,length,exception);
366  if (status == MagickFalse)
367    {
368      (void) RelinquishUniqueFileResource(blob_info->filename);
369      blob_info=DestroyImageInfo(blob_info);
370      return((Image *) NULL);
371    }
372  image=ReadImage(blob_info,exception);
373  (void) RelinquishUniqueFileResource(blob_info->filename);
374  blob_info=DestroyImageInfo(blob_info);
375  return(image);
376}
377
378/*
379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380%                                                                             %
381%                                                                             %
382%                                                                             %
383+   C l o n e B l o b I n f o                                                 %
384%                                                                             %
385%                                                                             %
386%                                                                             %
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388%
389%  CloneBlobInfo() makes a duplicate of the given blob info structure, or if
390%  blob info is NULL, a new one.
391%
392%  The format of the CloneBlobInfo method is:
393%
394%      BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
395%
396%  A description of each parameter follows:
397%
398%    o blob_info: the blob info.
399%
400*/
401MagickExport BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
402{
403  BlobInfo
404    *clone_info;
405
406  clone_info=(BlobInfo *) AcquireMagickMemory(sizeof(*clone_info));
407  if (clone_info == (BlobInfo *) NULL)
408    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
409  GetBlobInfo(clone_info);
410  if (blob_info == (BlobInfo *) NULL)
411    return(clone_info);
412  clone_info->length=blob_info->length;
413  clone_info->extent=blob_info->extent;
414  clone_info->quantum=blob_info->quantum;
415  clone_info->mapped=blob_info->mapped;
416  clone_info->eof=blob_info->eof;
417  clone_info->offset=blob_info->offset;
418  clone_info->size=blob_info->size;
419  clone_info->exempt=blob_info->exempt;
420  clone_info->status=blob_info->status;
421  clone_info->temporary=blob_info->temporary;
422  clone_info->type=blob_info->type;
423  clone_info->file=blob_info->file;
424  clone_info->properties=blob_info->properties;
425  clone_info->stream=blob_info->stream;
426  clone_info->data=blob_info->data;
427  clone_info->debug=IsEventLogging();
428  clone_info->reference_count=1;
429  clone_info->semaphore=(SemaphoreInfo *) NULL;
430  return(clone_info);
431}
432
433/*
434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435%                                                                             %
436%                                                                             %
437%                                                                             %
438+   C l o s e B l o b                                                         %
439%                                                                             %
440%                                                                             %
441%                                                                             %
442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443%
444%  CloseBlob() closes a stream associated with the image.
445%
446%  The format of the CloseBlob method is:
447%
448%      MagickBooleanType CloseBlob(Image *image)
449%
450%  A description of each parameter follows:
451%
452%    o image: the image.
453%
454*/
455MagickExport MagickBooleanType CloseBlob(Image *image)
456{
457  int
458    status;
459
460  /*
461    Close image file.
462  */
463  assert(image != (Image *) NULL);
464  assert(image->signature == MagickSignature);
465  if (image->debug != MagickFalse)
466    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
467  assert(image->blob != (BlobInfo *) NULL);
468  if (image->blob->type == UndefinedStream)
469    return(MagickTrue);
470  (void) SyncBlob(image);
471  image->blob->size=GetBlobSize(image);
472  image->blob->eof=MagickFalse;
473  if (image->blob->exempt != MagickFalse)
474    {
475      image->blob->type=UndefinedStream;
476      return(MagickTrue);
477    }
478  status=0;
479  switch (image->blob->type)
480  {
481    case UndefinedStream:
482      break;
483    case FileStream:
484    case StandardStream:
485    case PipeStream:
486    {
487      status=ferror(image->blob->file);
488      break;
489    }
490    case ZipStream:
491    {
492#if defined(MAGICKCORE_ZLIB_DELEGATE)
493      (void) gzerror(image->blob->file,&status);
494#endif
495      break;
496    }
497    case BZipStream:
498    {
499#if defined(MAGICKCORE_BZLIB_DELEGATE)
500      (void) BZ2_bzerror((BZFILE *) image->blob->file,&status);
501#endif
502      break;
503    }
504    case FifoStream:
505    case BlobStream:
506      break;
507  }
508  image->blob->status=status < 0 ? MagickTrue : MagickFalse;
509  switch (image->blob->type)
510  {
511    case UndefinedStream:
512      break;
513    case FileStream:
514    case StandardStream:
515    {
516      status=fclose(image->blob->file);
517      break;
518    }
519    case PipeStream:
520    {
521#if defined(MAGICKCORE_HAVE_POPEN)
522      status=pclose(image->blob->file);
523#endif
524      break;
525    }
526    case ZipStream:
527    {
528#if defined(MAGICKCORE_ZLIB_DELEGATE)
529      status=gzclose(image->blob->file);
530#endif
531      break;
532    }
533    case BZipStream:
534    {
535#if defined(MAGICKCORE_BZLIB_DELEGATE)
536      BZ2_bzclose((BZFILE *) image->blob->file);
537#endif
538      break;
539    }
540    case FifoStream:
541    case BlobStream:
542      break;
543  }
544  (void) DetachBlob(image->blob);
545  image->blob->status=status < 0 ? MagickTrue : MagickFalse;
546  return(image->blob->status);
547}
548
549/*
550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551%                                                                             %
552%                                                                             %
553%                                                                             %
554+   D e s t r o y B l o b                                                     %
555%                                                                             %
556%                                                                             %
557%                                                                             %
558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
559%
560%  DestroyBlob() deallocates memory associated with a blob.
561%
562%  The format of the DestroyBlob method is:
563%
564%      void DestroyBlob(Image *image)
565%
566%  A description of each parameter follows:
567%
568%    o image: the image.
569%
570*/
571MagickExport void DestroyBlob(Image *image)
572{
573  MagickBooleanType
574    destroy;
575
576  assert(image != (Image *) NULL);
577  assert(image->signature == MagickSignature);
578  if (image->debug != MagickFalse)
579    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
580  assert(image->blob != (BlobInfo *) NULL);
581  assert(image->blob->signature == MagickSignature);
582  destroy=MagickFalse;
583  AcquireSemaphoreInfo(&image->blob->semaphore);
584  image->blob->reference_count--;
585  assert(image->blob->reference_count >= 0);
586  if (image->blob->reference_count == 0)
587    destroy=MagickTrue;
588  RelinquishSemaphoreInfo(image->blob->semaphore);
589  if (destroy == MagickFalse)
590    return;
591  (void) CloseBlob(image);
592  if (image->blob->mapped != MagickFalse)
593    (void) UnmapBlob(image->blob->data,image->blob->length);
594  if (image->blob->semaphore != (SemaphoreInfo *) NULL)
595    DestroySemaphoreInfo(&image->blob->semaphore);
596  image->blob->signature=(~MagickSignature);
597  image->blob=(BlobInfo *) RelinquishMagickMemory(image->blob);
598}
599
600/*
601%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602%                                                                             %
603%                                                                             %
604%                                                                             %
605+   D e t a c h B l o b                                                       %
606%                                                                             %
607%                                                                             %
608%                                                                             %
609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610%
611%  DetachBlob() detaches a blob from the BlobInfo structure.
612%
613%  The format of the DetachBlob method is:
614%
615%      unsigned char *DetachBlob(BlobInfo *blob_info)
616%
617%  A description of each parameter follows:
618%
619%    o blob_info: Specifies a pointer to a BlobInfo structure.
620%
621*/
622MagickExport unsigned char *DetachBlob(BlobInfo *blob_info)
623{
624  unsigned char
625    *data;
626
627  assert(blob_info != (BlobInfo *) NULL);
628  if (blob_info->debug != MagickFalse)
629    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
630  if (blob_info->mapped != MagickFalse)
631    (void) UnmapBlob(blob_info->data,blob_info->length);
632  blob_info->mapped=MagickFalse;
633  blob_info->length=0;
634  blob_info->offset=0;
635  blob_info->eof=MagickFalse;
636  blob_info->exempt=MagickFalse;
637  blob_info->type=UndefinedStream;
638  blob_info->file=(FILE *) NULL;
639  data=blob_info->data;
640  blob_info->data=(unsigned char *) NULL;
641  blob_info->stream=(StreamHandler) NULL;
642  return(data);
643}
644
645/*
646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647%                                                                             %
648%                                                                             %
649%                                                                             %
650+  E O F B l o b                                                              %
651%                                                                             %
652%                                                                             %
653%                                                                             %
654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
655%
656%  EOFBlob() returns a non-zero value when EOF has been detected reading from
657%  a blob or file.
658%
659%  The format of the EOFBlob method is:
660%
661%      int EOFBlob(const Image *image)
662%
663%  A description of each parameter follows:
664%
665%    o image: the image.
666%
667*/
668MagickExport int EOFBlob(const Image *image)
669{
670  assert(image != (Image *) NULL);
671  assert(image->signature == MagickSignature);
672  if (image->debug != MagickFalse)
673    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
674  assert(image->blob != (BlobInfo *) NULL);
675  assert(image->blob->type != UndefinedStream);
676  switch (image->blob->type)
677  {
678    case UndefinedStream:
679      break;
680    case FileStream:
681    case StandardStream:
682    case PipeStream:
683    {
684      image->blob->eof=feof(image->blob->file) != 0 ? MagickTrue : MagickFalse;
685      break;
686    }
687    case ZipStream:
688    {
689      image->blob->eof=MagickFalse;
690      break;
691    }
692    case BZipStream:
693    {
694#if defined(MAGICKCORE_BZLIB_DELEGATE)
695      int
696        status;
697
698      status=0;
699      (void) BZ2_bzerror((BZFILE *) image->blob->file,&status);
700      image->blob->eof=status == BZ_UNEXPECTED_EOF ? MagickTrue : MagickFalse;
701#endif
702      break;
703    }
704    case FifoStream:
705    {
706      image->blob->eof=MagickFalse;
707      break;
708    }
709    case BlobStream:
710      break;
711  }
712  return((int) image->blob->eof);
713}
714
715/*
716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717%                                                                             %
718%                                                                             %
719%                                                                             %
720+   F i l e T o B l o b                                                       %
721%                                                                             %
722%                                                                             %
723%                                                                             %
724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
725%
726%  FileToBlob() returns the contents of a file as a blob.  It returns the
727%  file as a blob and its length.  If an error occurs, NULL is returned.
728%
729%  The format of the FileToBlob method is:
730%
731%      unsigned char *FileToBlob(const char *filename,const size_t extent,
732%        size_t *length,ExceptionInfo *exception)
733%
734%  A description of each parameter follows:
735%
736%    o blob:  FileToBlob() returns the contents of a file as a blob.  If
737%      an error occurs NULL is returned.
738%
739%    o filename: the filename.
740%
741%    o extent:  The maximum length of the blob.
742%
743%    o length: On return, this reflects the actual length of the blob.
744%
745%    o exception: Return any errors or warnings in this structure.
746%
747*/
748MagickExport unsigned char *FileToBlob(const char *filename,const size_t extent,
749  size_t *length,ExceptionInfo *exception)
750{
751  int
752    file;
753
754  MagickOffsetType
755    offset;
756
757  register size_t
758    i;
759
760  ssize_t
761    count;
762
763  unsigned char
764    *blob;
765
766  void
767    *map;
768
769  assert(filename != (const char *) NULL);
770  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
771  assert(exception != (ExceptionInfo *) NULL);
772  *length=0;
773  file=fileno(stdin);
774  if (LocaleCompare(filename,"-") != 0)
775    file=open(filename,O_RDONLY | O_BINARY);
776  if (file == -1)
777    {
778      ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
779      return((unsigned char *) NULL);
780    }
781  offset=(MagickOffsetType) MagickSeek(file,0,SEEK_END);
782  count=0;
783  if ((offset < 0) || (offset != (MagickOffsetType) ((ssize_t) offset)))
784    {
785      size_t
786        quantum;
787
788      struct stat
789        file_info;
790
791      /*
792        Stream is not seekable.
793      */
794      quantum=(size_t) MagickMaxBufferSize;
795      if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
796        quantum=MagickMin((size_t) file_info.st_size,MagickMaxBufferSize);
797      blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
798      for (i=0; blob != (unsigned char *) NULL; i+=count)
799      {
800        count=(ssize_t) read(file,blob+i,quantum);
801        if (count <= 0)
802          {
803            count=0;
804            if (errno != EINTR)
805              break;
806          }
807        if (~(1UL*i) < (quantum+1))
808          {
809            blob=(unsigned char *) RelinquishMagickMemory(blob);
810            break;
811          }
812        blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
813          sizeof(*blob));
814        if ((size_t) (i+count) >= extent)
815          break;
816      }
817      file=close(file)-1;
818      if (blob == (unsigned char *) NULL)
819        {
820          (void) ThrowMagickException(exception,GetMagickModule(),
821            ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
822          return((unsigned char *) NULL);
823        }
824      *length=MagickMin(i+count,extent);
825      blob[*length]='\0';
826      return(blob);
827    }
828  *length=MagickMin((size_t) offset,extent);
829  blob=(unsigned char *) NULL;
830  if (~(*length) >= MaxTextExtent)
831    blob=(unsigned char *) AcquireQuantumMemory(*length+MaxTextExtent,
832      sizeof(*blob));
833  if (blob == (unsigned char *) NULL)
834    {
835      file=close(file)-1;
836      (void) ThrowMagickException(exception,GetMagickModule(),
837        ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
838      return((unsigned char *) NULL);
839    }
840  map=MapBlob(file,ReadMode,0,*length);
841  if (map != (unsigned char *) NULL)
842    {
843      (void) CopyMagickMemory(blob,map,*length);
844      (void) UnmapBlob(map,*length);
845    }
846  else
847    {
848      (void) MagickSeek(file,0,SEEK_SET);
849      for (i=0; i < *length; i+=count)
850      {
851        count=(ssize_t) read(file,blob+i,MagickMin(*length-i,(size_t)
852          SSIZE_MAX));
853        if (count <= 0)
854          {
855            count=0;
856            if (errno != EINTR)
857              break;
858          }
859      }
860      if (i < *length)
861        {
862          file=close(file)-1;
863          blob=(unsigned char *) RelinquishMagickMemory(blob);
864          ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
865          return((unsigned char *) NULL);
866        }
867    }
868  file=close(file)-1;
869  blob[*length]='\0';
870  return(blob);
871}
872
873/*
874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
875%                                                                             %
876%                                                                             %
877%                                                                             %
878%   F i l e T o I m a g e                                                     %
879%                                                                             %
880%                                                                             %
881%                                                                             %
882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883%
884%  FileToImage() write the contents of a file to an image.
885%
886%  The format of the FileToImage method is:
887%
888%      MagickBooleanType FileToImage(Image *,const char *filename)
889%
890%  A description of each parameter follows:
891%
892%    o image: the image.
893%
894%    o filename: the filename.
895%
896*/
897
898static inline ssize_t WriteBlobStream(Image *image,const size_t length,
899  const unsigned char *data)
900{
901  MagickSizeType
902    extent;
903
904  register unsigned char
905    *q;
906
907  assert(image->blob != (BlobInfo *) NULL);
908  if (image->blob->type != BlobStream)
909    return(WriteBlob(image,length,data));
910  assert(image->blob->type != UndefinedStream);
911  assert(data != (void *) NULL);
912  extent=(MagickSizeType) (image->blob->offset+(MagickOffsetType) length);
913  if (extent >= image->blob->extent)
914    {
915      image->blob->quantum<<=1;
916      extent=image->blob->extent+image->blob->quantum+length;
917      if (SetBlobExtent(image,extent) == MagickFalse)
918        return(0);
919    }
920  q=image->blob->data+image->blob->offset;
921  switch (length)
922  {
923    default:
924    {
925      (void) CopyMagickMemory(q,data,length);
926      break;
927    }
928    case 7: *q++=(*data++);
929    case 6: *q++=(*data++);
930    case 5: *q++=(*data++);
931    case 4: *q++=(*data++);
932    case 3: *q++=(*data++);
933    case 2: *q++=(*data++);
934    case 1: *q++=(*data++);
935    case 0: break;
936  }
937  image->blob->offset+=length;
938  if (image->blob->offset >= (MagickOffsetType) image->blob->length)
939    image->blob->length=(size_t) image->blob->offset;
940  return((ssize_t) length);
941}
942
943MagickExport MagickBooleanType FileToImage(Image *image,const char *filename)
944{
945  int
946    file;
947
948  size_t
949    length,
950    quantum;
951
952  ssize_t
953    count;
954
955  struct stat
956    file_info;
957
958  unsigned char
959    *blob;
960
961  assert(image != (const Image *) NULL);
962  assert(image->signature == MagickSignature);
963  assert(filename != (const char *) NULL);
964  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
965  file=open(filename,O_RDONLY | O_BINARY);
966  if (file == -1)
967    {
968      ThrowFileException(&image->exception,BlobError,"UnableToOpenBlob",
969        filename);
970      return(MagickFalse);
971    }
972  quantum=(size_t) MagickMaxBufferSize;
973  if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
974    quantum=MagickMin((size_t) file_info.st_size,MagickMaxBufferSize);
975  blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
976  if (blob == (unsigned char *) NULL)
977    {
978      ThrowFileException(&image->exception,ResourceLimitError,
979