root / ImageMagick / branches / ImageMagick-6.3.5 / magick / blob.c

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