]> granicus.if.org Git - imagemagick/blob - MagickCore/blob.c
...
[imagemagick] / MagickCore / blob.c
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 %                     MagickCore Binary Large OBjectS Methods                 %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1999                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2017 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 %    https://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 \f
40 /*
41   Include declarations.
42 */
43 #ifdef __VMS
44 #include  <types.h>
45 #include  <mman.h>
46 #endif
47 #include "MagickCore/studio.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/client.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/delegate.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/locale_.h"
59 #include "MagickCore/log.h"
60 #include "MagickCore/magick.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/nt-base-private.h"
63 #include "MagickCore/option.h"
64 #include "MagickCore/policy.h"
65 #include "MagickCore/resource_.h"
66 #include "MagickCore/semaphore.h"
67 #include "MagickCore/string_.h"
68 #include "MagickCore/string-private.h"
69 #include "MagickCore/token.h"
70 #include "MagickCore/utility.h"
71 #include "MagickCore/utility-private.h"
72 #if defined(MAGICKCORE_ZLIB_DELEGATE)
73 #include "zlib.h"
74 #endif
75 #if defined(MAGICKCORE_BZLIB_DELEGATE)
76 #include "bzlib.h"
77 #endif
78 \f
79 /*
80   Define declarations.
81 */
82 #define MagickMaxBlobExtent  (8*8192)
83 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
84 # define MAP_ANONYMOUS  MAP_ANON
85 #endif
86 #if !defined(MAP_FAILED)
87 #define MAP_FAILED  ((void *) -1)
88 #endif
89 #if defined(__OS2__)
90 #include <io.h>
91 #define _O_BINARY O_BINARY
92 #endif
93 \f
94 /*
95   Typedef declarations.
96 */
97 typedef union FileInfo
98 {
99   FILE
100     *file;
101
102 #if defined(MAGICKCORE_ZLIB_DELEGATE)
103   gzFile
104     gzfile;
105 #endif
106
107 #if defined(MAGICKCORE_BZLIB_DELEGATE)
108   BZFILE
109     *bzfile;
110 #endif
111 } FileInfo;
112
113 struct _BlobInfo
114 {
115   size_t
116     length,
117     extent,
118     quantum;
119
120   MagickBooleanType
121     mapped,
122     eof;
123
124   MagickOffsetType
125     offset;
126
127   MagickSizeType
128     size;
129
130   MagickBooleanType
131     exempt,
132     synchronize,
133     status,
134     temporary;
135
136   StreamType
137     type;
138
139   FileInfo
140     file_info;
141
142   struct stat
143     properties;
144
145   StreamHandler
146     stream;
147
148   CustomStreamInfo
149     *custom_stream;
150
151   unsigned char
152     *data;
153
154   MagickBooleanType
155     debug;
156
157   SemaphoreInfo
158     *semaphore;
159
160   ssize_t
161     reference_count;
162
163   size_t
164     signature;
165 };
166
167 struct _CustomStreamInfo
168 {
169   CustomStreamHandler
170     reader,
171     writer;
172
173   CustomStreamSeeker
174     seeker;
175
176   CustomStreamTeller
177     teller;
178
179   void
180     *data;
181
182   size_t
183     signature;
184 };
185 \f
186 /*
187   Forward declarations.
188 */
189 static int
190   SyncBlob(Image *);
191 \f
192 /*
193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194 %                                                                             %
195 %                                                                             %
196 %                                                                             %
197 +   A c q u i r e C u s t o m S t r e a m I n f o                             %
198 %                                                                             %
199 %                                                                             %
200 %                                                                             %
201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 %
203 %  AcquireCustomStreamInfo() allocates the CustomStreamInfo structure.
204 %
205 %  The format of the AcquireCustomStreamInfo method is:
206 %
207 %      CustomStreamInfo *AcquireCustomStreamInfo(ExceptionInfo *exception)
208 %
209 %  A description of each parameter follows:
210 %
211 %    o exception: return any errors or warnings in this structure.
212 %
213 */
214 MagickExport CustomStreamInfo *AcquireCustomStreamInfo(
215   ExceptionInfo *exception)
216 {
217   CustomStreamInfo
218     *custom_stream;
219
220   custom_stream=(CustomStreamInfo *) AcquireMagickMemory(
221     sizeof(*custom_stream));
222   if (custom_stream == (CustomStreamInfo *) NULL)
223     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
224   (void) ResetMagickMemory(custom_stream,0,sizeof(*custom_stream));
225   custom_stream->signature=MagickCoreSignature;
226   return(custom_stream);
227 }
228 \f
229 /*
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231 %                                                                             %
232 %                                                                             %
233 %                                                                             %
234 +   A t t a c h B l o b                                                       %
235 %                                                                             %
236 %                                                                             %
237 %                                                                             %
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 %
240 %  AttachBlob() attaches a blob to the BlobInfo structure.
241 %
242 %  The format of the AttachBlob method is:
243 %
244 %      void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
245 %
246 %  A description of each parameter follows:
247 %
248 %    o blob_info: Specifies a pointer to a BlobInfo structure.
249 %
250 %    o blob: the address of a character stream in one of the image formats
251 %      understood by ImageMagick.
252 %
253 %    o length: This size_t integer reflects the length in bytes of the blob.
254 %
255 */
256 MagickExport void AttachBlob(BlobInfo *blob_info,const void *blob,
257   const size_t length)
258 {
259   assert(blob_info != (BlobInfo *) NULL);
260   if (blob_info->debug != MagickFalse)
261     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
262   blob_info->length=length;
263   blob_info->extent=length;
264   blob_info->quantum=(size_t) MagickMaxBlobExtent;
265   blob_info->offset=0;
266   blob_info->type=BlobStream;
267   blob_info->file_info.file=(FILE *) NULL;
268   blob_info->data=(unsigned char *) blob;
269   blob_info->mapped=MagickFalse;
270 }
271 \f
272 /*
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 %                                                                             %
275 %                                                                             %
276 %                                                                             %
277 +   B l o b T o F i l e                                                       %
278 %                                                                             %
279 %                                                                             %
280 %                                                                             %
281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282 %
283 %  BlobToFile() writes a blob to a file.  It returns MagickFalse if an error
284 %  occurs otherwise MagickTrue.
285 %
286 %  The format of the BlobToFile method is:
287 %
288 %       MagickBooleanType BlobToFile(char *filename,const void *blob,
289 %         const size_t length,ExceptionInfo *exception)
290 %
291 %  A description of each parameter follows:
292 %
293 %    o filename: Write the blob to this file.
294 %
295 %    o blob: the address of a blob.
296 %
297 %    o length: This length in bytes of the blob.
298 %
299 %    o exception: return any errors or warnings in this structure.
300 %
301 */
302 MagickExport MagickBooleanType BlobToFile(char *filename,const void *blob,
303   const size_t length,ExceptionInfo *exception)
304 {
305   int
306     file;
307
308   register size_t
309     i;
310
311   ssize_t
312     count;
313
314   assert(filename != (const char *) NULL);
315   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
316   assert(blob != (const void *) NULL);
317   if (*filename == '\0')
318     file=AcquireUniqueFileResource(filename);
319   else
320     file=open_utf8(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
321   if (file == -1)
322     {
323       ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
324       return(MagickFalse);
325     }
326   for (i=0; i < length; i+=count)
327   {
328     count=write(file,(const char *) blob+i,MagickMin(length-i,SSIZE_MAX));
329     if (count <= 0)
330       {
331         count=0;
332         if (errno != EINTR)
333           break;
334       }
335   }
336   file=close(file);
337   if ((file == -1) || (i < length))
338     {
339       ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
340       return(MagickFalse);
341     }
342   return(MagickTrue);
343 }
344 \f
345 /*
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 %                                                                             %
348 %                                                                             %
349 %                                                                             %
350 %   B l o b T o I m a g e                                                     %
351 %                                                                             %
352 %                                                                             %
353 %                                                                             %
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355 %
356 %  BlobToImage() implements direct to memory image formats.  It returns the
357 %  blob as an image.
358 %
359 %  The format of the BlobToImage method is:
360 %
361 %      Image *BlobToImage(const ImageInfo *image_info,const void *blob,
362 %        const size_t length,ExceptionInfo *exception)
363 %
364 %  A description of each parameter follows:
365 %
366 %    o image_info: the image info.
367 %
368 %    o blob: the address of a character stream in one of the image formats
369 %      understood by ImageMagick.
370 %
371 %    o length: This size_t integer reflects the length in bytes of the blob.
372 %
373 %    o exception: return any errors or warnings in this structure.
374 %
375 */
376 MagickExport Image *BlobToImage(const ImageInfo *image_info,const void *blob,
377   const size_t length,ExceptionInfo *exception)
378 {
379   const MagickInfo
380     *magick_info;
381
382   Image
383     *image;
384
385   ImageInfo
386     *blob_info,
387     *clone_info;
388
389   MagickBooleanType
390     status;
391
392   assert(image_info != (ImageInfo *) NULL);
393   assert(image_info->signature == MagickCoreSignature);
394   if (image_info->debug != MagickFalse)
395     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
396       image_info->filename);
397   assert(exception != (ExceptionInfo *) NULL);
398   if ((blob == (const void *) NULL) || (length == 0))
399     {
400       (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
401         "ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
402       return((Image *) NULL);
403     }
404   blob_info=CloneImageInfo(image_info);
405   blob_info->blob=(void *) blob;
406   blob_info->length=length;
407   if (*blob_info->magick == '\0')
408     (void) SetImageInfo(blob_info,0,exception);
409   magick_info=GetMagickInfo(blob_info->magick,exception);
410   if (magick_info == (const MagickInfo *) NULL)
411     {
412       (void) ThrowMagickException(exception,GetMagickModule(),
413         MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
414         blob_info->magick);
415       blob_info=DestroyImageInfo(blob_info);
416       return((Image *) NULL);
417     }
418   if (GetMagickBlobSupport(magick_info) != MagickFalse)
419     {
420       /*
421         Native blob support for this image format.
422       */
423       (void) CopyMagickString(blob_info->filename,image_info->filename,
424         MagickPathExtent);
425       (void) CopyMagickString(blob_info->magick,image_info->magick,
426         MagickPathExtent);
427       image=ReadImage(blob_info,exception);
428       if (image != (Image *) NULL)
429         (void) DetachBlob(image->blob);
430       blob_info=DestroyImageInfo(blob_info);
431       return(image);
432     }
433   /*
434     Write blob to a temporary file on disk.
435   */
436   blob_info->blob=(void *) NULL;
437   blob_info->length=0;
438   *blob_info->filename='\0';
439   status=BlobToFile(blob_info->filename,blob,length,exception);
440   if (status == MagickFalse)
441     {
442       (void) RelinquishUniqueFileResource(blob_info->filename);
443       blob_info=DestroyImageInfo(blob_info);
444       return((Image *) NULL);
445     }
446   clone_info=CloneImageInfo(blob_info);
447   (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:%s",
448     blob_info->magick,blob_info->filename);
449   image=ReadImage(clone_info,exception);
450   if (image != (Image *) NULL)
451     {
452       Image
453         *images;
454
455       /*
456         Restore original filenames and image format.
457       */
458       for (images=GetFirstImageInList(image); images != (Image *) NULL; )
459       {
460         (void) CopyMagickString(images->filename,image_info->filename,
461           MagickPathExtent);
462         (void) CopyMagickString(images->magick_filename,image_info->filename,
463           MagickPathExtent);
464         (void) CopyMagickString(images->magick,magick_info->name,
465           MagickPathExtent);
466         images=GetNextImageInList(images);
467       }
468     }
469   clone_info=DestroyImageInfo(clone_info);
470   (void) RelinquishUniqueFileResource(blob_info->filename);
471   blob_info=DestroyImageInfo(blob_info);
472   return(image);
473 }
474 \f
475 /*
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 %                                                                             %
478 %                                                                             %
479 %                                                                             %
480 +   C l o n e B l o b I n f o                                                 %
481 %                                                                             %
482 %                                                                             %
483 %                                                                             %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 %
486 %  CloneBlobInfo() makes a duplicate of the given blob info structure, or if
487 %  blob info is NULL, a new one.
488 %
489 %  The format of the CloneBlobInfo method is:
490 %
491 %      BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
492 %
493 %  A description of each parameter follows:
494 %
495 %    o blob_info: the blob info.
496 %
497 */
498 MagickExport BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
499 {
500   BlobInfo
501     *clone_info;
502
503   clone_info=(BlobInfo *) AcquireMagickMemory(sizeof(*clone_info));
504   if (clone_info == (BlobInfo *) NULL)
505     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
506   GetBlobInfo(clone_info);
507   if (blob_info == (BlobInfo *) NULL)
508     return(clone_info);
509   clone_info->length=blob_info->length;
510   clone_info->extent=blob_info->extent;
511   clone_info->synchronize=blob_info->synchronize;
512   clone_info->quantum=blob_info->quantum;
513   clone_info->mapped=blob_info->mapped;
514   clone_info->eof=blob_info->eof;
515   clone_info->offset=blob_info->offset;
516   clone_info->size=blob_info->size;
517   clone_info->exempt=blob_info->exempt;
518   clone_info->status=blob_info->status;
519   clone_info->temporary=blob_info->temporary;
520   clone_info->type=blob_info->type;
521   clone_info->file_info.file=blob_info->file_info.file;
522   clone_info->properties=blob_info->properties;
523   clone_info->stream=blob_info->stream;
524   clone_info->custom_stream=blob_info->custom_stream;
525   clone_info->data=blob_info->data;
526   clone_info->debug=IsEventLogging();
527   clone_info->reference_count=1;
528   return(clone_info);
529 }
530 \f
531 /*
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 %                                                                             %
534 %                                                                             %
535 %                                                                             %
536 +   C l o s e B l o b                                                         %
537 %                                                                             %
538 %                                                                             %
539 %                                                                             %
540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 %
542 %  CloseBlob() closes a stream associated with the image.
543 %
544 %  The format of the CloseBlob method is:
545 %
546 %      MagickBooleanType CloseBlob(Image *image)
547 %
548 %  A description of each parameter follows:
549 %
550 %    o image: the image.
551 %
552 */
553 MagickExport MagickBooleanType CloseBlob(Image *image)
554 {
555   int
556     status;
557
558   /*
559     Close image file.
560   */
561   assert(image != (Image *) NULL);
562   assert(image->signature == MagickCoreSignature);
563   if (image->debug != MagickFalse)
564     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
565   assert(image->blob != (BlobInfo *) NULL);
566   if (image->blob->type == UndefinedStream)
567     return(MagickTrue);
568   status=SyncBlob(image);
569   switch (image->blob->type)
570   {
571     case UndefinedStream:
572     case StandardStream:
573       break;
574     case FileStream:
575     case PipeStream:
576     {
577       if (image->blob->synchronize != MagickFalse)
578         status=fsync(fileno(image->blob->file_info.file));
579       status=ferror(image->blob->file_info.file);
580       break;
581     }
582     case ZipStream:
583     {
584 #if defined(MAGICKCORE_ZLIB_DELEGATE)
585       (void) gzerror(image->blob->file_info.gzfile,&status);
586 #endif
587       break;
588     }
589     case BZipStream:
590     {
591 #if defined(MAGICKCORE_BZLIB_DELEGATE)
592       (void) BZ2_bzerror(image->blob->file_info.bzfile,&status);
593 #endif
594       break;
595     }
596     case FifoStream:
597       break;
598     case BlobStream:
599     {
600       if ((image->blob->file_info.file != (FILE *) NULL) &&
601           (image->blob->synchronize != MagickFalse))
602         {
603           (void) fsync(fileno(image->blob->file_info.file));
604           status=ferror(image->blob->file_info.file);
605         }
606       break;
607     }
608     case CustomStream:
609       break;
610   }
611   image->blob->status=status < 0 ? MagickTrue : MagickFalse;
612   image->blob->size=GetBlobSize(image);
613   image->extent=image->blob->size;
614   image->blob->eof=MagickFalse;
615   if (image->blob->exempt != MagickFalse)
616     {
617       image->blob->type=UndefinedStream;
618       return(image->blob->status);
619     }
620   switch (image->blob->type)
621   {
622     case UndefinedStream:
623     case StandardStream:
624       break;
625     case FileStream:
626     {
627       status=fclose(image->blob->file_info.file);
628       break;
629     }
630     case PipeStream:
631     {
632 #if defined(MAGICKCORE_HAVE_PCLOSE)
633       status=pclose(image->blob->file_info.file);
634 #endif
635       break;
636     }
637     case ZipStream:
638     {
639 #if defined(MAGICKCORE_ZLIB_DELEGATE)
640       status=gzclose(image->blob->file_info.gzfile);
641 #endif
642       break;
643     }
644     case BZipStream:
645     {
646 #if defined(MAGICKCORE_BZLIB_DELEGATE)
647       BZ2_bzclose(image->blob->file_info.bzfile);
648 #endif
649       break;
650     }
651     case FifoStream:
652       break;
653     case BlobStream:
654     {
655       if (image->blob->file_info.file != (FILE *) NULL)
656         status=fclose(image->blob->file_info.file);
657       break;
658     }
659     case CustomStream:
660       break;
661   }
662   (void) DetachBlob(image->blob);
663   image->blob->status=status < 0 ? MagickTrue : MagickFalse;
664   return(image->blob->status);
665 }
666 \f
667 /*
668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669 %                                                                             %
670 %                                                                             %
671 %                                                                             %
672 +   D e s t r o y B l o b                                                     %
673 %                                                                             %
674 %                                                                             %
675 %                                                                             %
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677 %
678 %  DestroyBlob() deallocates memory associated with a blob.
679 %
680 %  The format of the DestroyBlob method is:
681 %
682 %      void DestroyBlob(Image *image)
683 %
684 %  A description of each parameter follows:
685 %
686 %    o image: the image.
687 %
688 */
689 MagickExport void DestroyBlob(Image *image)
690 {
691   MagickBooleanType
692     destroy;
693
694   assert(image != (Image *) NULL);
695   assert(image->signature == MagickCoreSignature);
696   if (image->debug != MagickFalse)
697     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
698   assert(image->blob != (BlobInfo *) NULL);
699   assert(image->blob->signature == MagickCoreSignature);
700   destroy=MagickFalse;
701   LockSemaphoreInfo(image->blob->semaphore);
702   image->blob->reference_count--;
703   assert(image->blob->reference_count >= 0);
704   if (image->blob->reference_count == 0)
705     destroy=MagickTrue;
706   UnlockSemaphoreInfo(image->blob->semaphore);
707   if (destroy == MagickFalse)
708     return;
709   (void) CloseBlob(image);
710   if (image->blob->mapped != MagickFalse)
711     {
712       (void) UnmapBlob(image->blob->data,image->blob->length);
713       RelinquishMagickResource(MapResource,image->blob->length);
714     }
715   if (image->blob->semaphore != (SemaphoreInfo *) NULL)
716     RelinquishSemaphoreInfo(&image->blob->semaphore);
717   image->blob->signature=(~MagickCoreSignature);
718   image->blob=(BlobInfo *) RelinquishMagickMemory(image->blob);
719 }
720 \f
721 /*
722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 %                                                                             %
724 %                                                                             %
725 %                                                                             %
726 +   D e s t r o y C u s t o m S t r e a m I n f o                             %
727 %                                                                             %
728 %                                                                             %
729 %                                                                             %
730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
731 %
732 %  DestroyCustomStreamInfo() destroys memory associated with the
733 %  CustomStreamInfo structure.
734 %
735 %  The format of the DestroyCustomStreamInfo method is:
736 %
737 %      CustomStreamInfo *DestroyCustomStreamInfo(CustomStreamInfo *stream_info)
738 %
739 %  A description of each parameter follows:
740 %
741 %    o custom_stream: the custom stream info.
742 %
743 */
744 MagickExport CustomStreamInfo *DestroyCustomStreamInfo(
745   CustomStreamInfo *custom_stream)
746 {
747   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
748   assert(custom_stream != (CustomStreamInfo *) NULL);
749   assert(custom_stream->signature == MagickCoreSignature);
750   custom_stream->signature=(~MagickCoreSignature);
751   custom_stream=(CustomStreamInfo *) RelinquishMagickMemory(custom_stream);
752   return(custom_stream);
753 }
754 \f
755 /*
756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757 %                                                                             %
758 %                                                                             %
759 %                                                                             %
760 +   D e t a c h B l o b                                                       %
761 %                                                                             %
762 %                                                                             %
763 %                                                                             %
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765 %
766 %  DetachBlob() detaches a blob from the BlobInfo structure.
767 %
768 %  The format of the DetachBlob method is:
769 %
770 %      void *DetachBlob(BlobInfo *blob_info)
771 %
772 %  A description of each parameter follows:
773 %
774 %    o blob_info: Specifies a pointer to a BlobInfo structure.
775 %
776 */
777 MagickExport void *DetachBlob(BlobInfo *blob_info)
778 {
779   void
780     *data;
781
782   assert(blob_info != (BlobInfo *) NULL);
783   if (blob_info->debug != MagickFalse)
784     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
785   if (blob_info->mapped != MagickFalse)
786     {
787       (void) UnmapBlob(blob_info->data,blob_info->length);
788       blob_info->data=(unsigned char *) NULL;
789       RelinquishMagickResource(MapResource,blob_info->length);
790     }
791   blob_info->mapped=MagickFalse;
792   blob_info->length=0;
793   blob_info->offset=0;
794   blob_info->eof=MagickFalse;
795   blob_info->exempt=MagickFalse;
796   blob_info->type=UndefinedStream;
797   blob_info->file_info.file=(FILE *) NULL;
798   data=blob_info->data;
799   blob_info->data=(unsigned char *) NULL;
800   blob_info->stream=(StreamHandler) NULL;
801   blob_info->custom_stream=(CustomStreamInfo *) NULL;
802   return(data);
803 }
804 \f
805 /*
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807 %                                                                             %
808 %                                                                             %
809 %                                                                             %
810 +   D i s a s s o c i a t e B l o b                                           %
811 %                                                                             %
812 %                                                                             %
813 %                                                                             %
814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
815 %
816 %  DisassociateBlob() disassociates the image stream.  It checks if the
817 %  blob of the specified image is referenced by other images. If the reference
818 %  count is higher then 1 a new blob is assigned to the specified image.
819 %
820 %  The format of the DisassociateBlob method is:
821 %
822 %      void DisassociateBlob(const Image *image)
823 %
824 %  A description of each parameter follows:
825 %
826 %    o image: the image.
827 %
828 */
829 MagickExport void DisassociateBlob(Image *image)
830 {
831   BlobInfo
832     *blob;
833
834   MagickBooleanType
835     clone;
836
837   assert(image != (Image *) NULL);
838   assert(image->signature == MagickCoreSignature);
839   if (image->debug != MagickFalse)
840     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
841   assert(image->blob != (BlobInfo *) NULL);
842   assert(image->blob->signature == MagickCoreSignature);
843   clone=MagickFalse;
844   LockSemaphoreInfo(image->blob->semaphore);
845   assert(image->blob->reference_count >= 0);
846   if (image->blob->reference_count > 1)
847     clone=MagickTrue;
848   UnlockSemaphoreInfo(image->blob->semaphore);
849   if (clone == MagickFalse)
850     return;
851   blob=CloneBlobInfo(image->blob);
852   DestroyBlob(image);
853   image->blob=blob;
854 }
855 \f
856 /*
857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858 %                                                                             %
859 %                                                                             %
860 %                                                                             %
861 +  D i s c a r d B l o b B y t e s                                            %
862 %                                                                             %
863 %                                                                             %
864 %                                                                             %
865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
866 %
867 %  DiscardBlobBytes() discards bytes in a blob.
868 %
869 %  The format of the DiscardBlobBytes method is:
870 %
871 %      MagickBooleanType DiscardBlobBytes(Image *image,
872 %        const MagickSizeType length)
873 %
874 %  A description of each parameter follows.
875 %
876 %    o image: the image.
877 %
878 %    o length:  the number of bytes to skip.
879 %
880 */
881 MagickExport MagickBooleanType DiscardBlobBytes(Image *image,
882   const MagickSizeType length)
883 {
884   register MagickOffsetType
885     i;
886
887   size_t
888     quantum;
889
890   ssize_t
891     count;
892
893   unsigned char
894     buffer[16384];
895
896   assert(image != (Image *) NULL);
897   assert(image->signature == MagickCoreSignature);
898   if (length != (MagickSizeType) ((MagickOffsetType) length))
899     return(MagickFalse);
900   count=0;
901   for (i=0; i < (MagickOffsetType) length; i+=count)
902   {
903     quantum=(size_t) MagickMin(length-i,sizeof(buffer));
904     (void) ReadBlobStream(image,quantum,buffer,&count);
905     if (count <= 0)
906       {
907         count=0;
908         if (errno != EINTR)
909           break;
910       }
911   }
912   return(i < (MagickOffsetType) length ? MagickFalse : MagickTrue);
913 }
914 \f
915 /*
916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
917 %                                                                             %
918 %                                                                             %
919 %                                                                             %
920 +   D u p l i c a t e s B l o b                                               %
921 %                                                                             %
922 %                                                                             %
923 %                                                                             %
924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
925 %
926 %  DuplicateBlob() duplicates a blob descriptor.
927 %
928 %  The format of the DuplicateBlob method is:
929 %
930 %      void DuplicateBlob(Image *image,const Image *duplicate)
931 %
932 %  A description of each parameter follows:
933 %
934 %    o image: the image.
935 %
936 %    o duplicate: the duplicate image.
937 %
938 */
939 MagickExport void DuplicateBlob(Image *image,const Image *duplicate)
940 {
941   assert(image != (Image *) NULL);
942   assert(image->signature == MagickCoreSignature);
943   if (image->debug != MagickFalse)
944     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
945   assert(duplicate != (Image *) NULL);
946   assert(duplicate->signature == MagickCoreSignature);
947   DestroyBlob(image);
948   image->blob=ReferenceBlob(duplicate->blob);
949 }
950 \f
951 /*
952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953 %                                                                             %
954 %                                                                             %
955 %                                                                             %
956 +  E O F B l o b                                                              %
957 %                                                                             %
958 %                                                                             %
959 %                                                                             %
960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
961 %
962 %  EOFBlob() returns a non-zero value when EOF has been detected reading from
963 %  a blob or file.
964 %
965 %  The format of the EOFBlob method is:
966 %
967 %      int EOFBlob(const Image *image)
968 %
969 %  A description of each parameter follows:
970 %
971 %    o image: the image.
972 %
973 */
974 MagickExport int EOFBlob(const Image *image)
975 {
976   assert(image != (Image *) NULL);
977   assert(image->signature == MagickCoreSignature);
978   if (image->debug != MagickFalse)
979     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
980   assert(image->blob != (BlobInfo *) NULL);
981   assert(image->blob->type != UndefinedStream);
982   switch (image->blob->type)
983   {
984     case UndefinedStream:
985     case StandardStream:
986       break;
987     case FileStream:
988     case PipeStream:
989     {
990       image->blob->eof=feof(image->blob->file_info.file) != 0 ? MagickTrue :
991         MagickFalse;
992       break;
993     }
994     case ZipStream:
995     {
996       image->blob->eof=MagickFalse;
997       break;
998     }
999     case BZipStream:
1000     {
1001 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1002       int
1003         status;
1004
1005       status=0;
1006       (void) BZ2_bzerror(image->blob->file_info.bzfile,&status);
1007       image->blob->eof=status == BZ_UNEXPECTED_EOF ? MagickTrue : MagickFalse;
1008 #endif
1009       break;
1010     }
1011     case FifoStream:
1012     {
1013       image->blob->eof=MagickFalse;
1014       break;
1015     }
1016     case BlobStream:
1017       break;
1018     case CustomStream:
1019       break;
1020   }
1021   return((int) image->blob->eof);
1022 }
1023 \f
1024 /*
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 %                                                                             %
1027 %                                                                             %
1028 %                                                                             %
1029 %   F i l e T o B l o b                                                       %
1030 %                                                                             %
1031 %                                                                             %
1032 %                                                                             %
1033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1034 %
1035 %  FileToBlob() returns the contents of a file as a buffer terminated with
1036 %  the '\0' character.  The length of the buffer (not including the extra
1037 %  terminating '\0' character) is returned via the 'length' parameter.  Free
1038 %  the buffer with RelinquishMagickMemory().
1039 %
1040 %  The format of the FileToBlob method is:
1041 %
1042 %      void *FileToBlob(const char *filename,const size_t extent,
1043 %        size_t *length,ExceptionInfo *exception)
1044 %
1045 %  A description of each parameter follows:
1046 %
1047 %    o blob:  FileToBlob() returns the contents of a file as a blob.  If
1048 %      an error occurs NULL is returned.
1049 %
1050 %    o filename: the filename.
1051 %
1052 %    o extent:  The maximum length of the blob.
1053 %
1054 %    o length: On return, this reflects the actual length of the blob.
1055 %
1056 %    o exception: return any errors or warnings in this structure.
1057 %
1058 */
1059 MagickExport void *FileToBlob(const char *filename,const size_t extent,
1060   size_t *length,ExceptionInfo *exception)
1061 {
1062   int
1063     file;
1064
1065   MagickOffsetType
1066     offset;
1067
1068   register size_t
1069     i;
1070
1071   ssize_t
1072     count;
1073
1074   unsigned char
1075     *blob;
1076
1077   void
1078     *map;
1079
1080   assert(filename != (const char *) NULL);
1081   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1082   assert(exception != (ExceptionInfo *) NULL);
1083   *length=0;
1084   file=fileno(stdin);
1085   if (LocaleCompare(filename,"-") != 0)
1086     file=open_utf8(filename,O_RDONLY | O_BINARY,0);
1087   if (file == -1)
1088     {
1089       ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
1090       return(NULL);
1091     }
1092   offset=(MagickOffsetType) lseek(file,0,SEEK_END);
1093   count=0;
1094   if ((file == fileno(stdin)) || (offset < 0) ||
1095       (offset != (MagickOffsetType) ((ssize_t) offset)))
1096     {
1097       size_t
1098         quantum;
1099
1100       struct stat
1101         file_stats;
1102
1103       /*
1104         Stream is not seekable.
1105       */
1106       offset=(MagickOffsetType) lseek(file,0,SEEK_SET);
1107       quantum=(size_t) MagickMaxBufferExtent;
1108       if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1109         quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1110       blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
1111       for (i=0; blob != (unsigned char *) NULL; i+=count)
1112       {
1113         count=read(file,blob+i,quantum);
1114         if (count <= 0)
1115           {
1116             count=0;
1117             if (errno != EINTR)
1118               break;
1119           }
1120         if (~((size_t) i) < (quantum+1))
1121           {
1122             blob=(unsigned char *) RelinquishMagickMemory(blob);
1123             break;
1124           }
1125         blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
1126           sizeof(*blob));
1127         if ((size_t) (i+count) >= extent)
1128           break;
1129       }
1130       if (LocaleCompare(filename,"-") != 0)
1131         file=close(file);
1132       if (blob == (unsigned char *) NULL)
1133         {
1134           (void) ThrowMagickException(exception,GetMagickModule(),
1135             ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1136           return(NULL);
1137         }
1138       if (file == -1)
1139         {
1140           blob=(unsigned char *) RelinquishMagickMemory(blob);
1141           ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1142           return(NULL);
1143         }
1144       *length=(size_t) MagickMin(i+count,extent);
1145       blob[*length]='\0';
1146       return(blob);
1147     }
1148   *length=(size_t) MagickMin(offset,(MagickOffsetType)
1149     MagickMin(extent,SSIZE_MAX));
1150   blob=(unsigned char *) NULL;
1151   if (~(*length) >= (MagickPathExtent-1))
1152     blob=(unsigned char *) AcquireQuantumMemory(*length+MagickPathExtent,
1153       sizeof(*blob));
1154   if (blob == (unsigned char *) NULL)
1155     {
1156       file=close(file);
1157       (void) ThrowMagickException(exception,GetMagickModule(),
1158         ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1159       return(NULL);
1160     }
1161   map=MapBlob(file,ReadMode,0,*length);
1162   if (map != (unsigned char *) NULL)
1163     {
1164       (void) memcpy(blob,map,*length);
1165       (void) UnmapBlob(map,*length);
1166     }
1167   else
1168     {
1169       (void) lseek(file,0,SEEK_SET);
1170       for (i=0; i < *length; i+=count)
1171       {
1172         count=read(file,blob+i,(size_t) MagickMin(*length-i,SSIZE_MAX));
1173         if (count <= 0)
1174           {
1175             count=0;
1176             if (errno != EINTR)
1177               break;
1178           }
1179       }
1180       if (i < *length)
1181         {
1182           file=close(file)-1;
1183           blob=(unsigned char *) RelinquishMagickMemory(blob);
1184           ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1185           return(NULL);
1186         }
1187     }
1188   blob[*length]='\0';
1189   if (LocaleCompare(filename,"-") != 0)
1190     file=close(file);
1191   if (file == -1)
1192     {
1193       blob=(unsigned char *) RelinquishMagickMemory(blob);
1194       ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1195     }
1196   return(blob);
1197 }
1198 \f
1199 /*
1200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201 %                                                                             %
1202 %                                                                             %
1203 %                                                                             %
1204 %   F i l e T o I m a g e                                                     %
1205 %                                                                             %
1206 %                                                                             %
1207 %                                                                             %
1208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 %
1210 %  FileToImage() write the contents of a file to an image.
1211 %
1212 %  The format of the FileToImage method is:
1213 %
1214 %      MagickBooleanType FileToImage(Image *,const char *filename)
1215 %
1216 %  A description of each parameter follows:
1217 %
1218 %    o image: the image.
1219 %
1220 %    o filename: the filename.
1221 %
1222 */
1223
1224 static inline ssize_t WriteBlobStream(Image *image,const size_t length,
1225   const void *data)
1226 {
1227   MagickSizeType
1228     extent;
1229
1230   register unsigned char
1231     *q;
1232
1233   assert(image->blob != (BlobInfo *) NULL);
1234   assert(image->blob->type != UndefinedStream);
1235   assert(data != NULL);
1236   if (image->blob->type != BlobStream)
1237     return(WriteBlob(image,length,(const unsigned char *) data));
1238   extent=(MagickSizeType) (image->blob->offset+(MagickOffsetType) length);
1239   if (extent >= image->blob->extent)
1240     {
1241       extent=image->blob->extent+image->blob->quantum+length;
1242       image->blob->quantum<<=1;
1243       if (SetBlobExtent(image,extent) == MagickFalse)
1244         return(0);
1245     }
1246   q=image->blob->data+image->blob->offset;
1247   (void) memcpy(q,data,length);
1248   image->blob->offset+=length;
1249   if (image->blob->offset >= (MagickOffsetType) image->blob->length)
1250     image->blob->length=(size_t) image->blob->offset;
1251   return((ssize_t) length);
1252 }
1253
1254 MagickExport MagickBooleanType FileToImage(Image *image,const char *filename,
1255   ExceptionInfo *exception)
1256 {
1257   int
1258     file;
1259
1260   size_t
1261     length,
1262     quantum;
1263
1264   ssize_t
1265     count;
1266
1267   struct stat
1268     file_stats;
1269
1270   unsigned char
1271     *blob;
1272
1273   assert(image != (const Image *) NULL);
1274   assert(image->signature == MagickCoreSignature);
1275   assert(filename != (const char *) NULL);
1276   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1277   file=fileno(stdin);
1278   if (LocaleCompare(filename,"-") != 0)
1279     file=open_utf8(filename,O_RDONLY | O_BINARY,0);
1280   if (file == -1)
1281     {
1282       ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
1283       return(MagickFalse);
1284     }
1285   quantum=(size_t) MagickMaxBufferExtent;
1286   if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1287     quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1288   blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
1289   if (blob == (unsigned char *) NULL)
1290     {
1291       file=close(file);
1292       ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
1293         filename);
1294       return(MagickFalse);
1295     }
1296   for ( ; ; )
1297   {
1298     count=read(file,blob,quantum);
1299     if (count <= 0)
1300       {
1301         count=0;
1302         if (errno != EINTR)
1303           break;
1304       }
1305     length=(size_t) count;
1306     count=WriteBlobStream(image,length,blob);
1307     if (count != (ssize_t) length)
1308       {
1309         ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1310         break;
1311       }
1312   }
1313   file=close(file);
1314   if (file == -1)
1315     ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1316   blob=(unsigned char *) RelinquishMagickMemory(blob);
1317   return(MagickTrue);
1318 }
1319 \f
1320 /*
1321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 %                                                                             %
1323 %                                                                             %
1324 %                                                                             %
1325 +   G e t B l o b E r r o r                                                   %
1326 %                                                                             %
1327 %                                                                             %
1328 %                                                                             %
1329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 %
1331 %  GetBlobError() returns MagickTrue if the blob associated with the specified
1332 %  image encountered an error.
1333 %
1334 %  The format of the GetBlobError method is:
1335 %
1336 %       MagickBooleanType GetBlobError(const Image *image)
1337 %
1338 %  A description of each parameter follows:
1339 %
1340 %    o image: the image.
1341 %
1342 */
1343 MagickExport MagickBooleanType GetBlobError(const Image *image)
1344 {
1345   assert(image != (const Image *) NULL);
1346   assert(image->signature == MagickCoreSignature);
1347   if (image->debug != MagickFalse)
1348     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1349   return(image->blob->status);
1350 }
1351 \f
1352 /*
1353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 %                                                                             %
1355 %                                                                             %
1356 %                                                                             %
1357 +   G e t B l o b F i l e H a n d l e                                         %
1358 %                                                                             %
1359 %                                                                             %
1360 %                                                                             %
1361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 %
1363 %  GetBlobFileHandle() returns the file handle associated with the image blob.
1364 %
1365 %  The format of the GetBlobFile method is:
1366 %
1367 %      FILE *GetBlobFileHandle(const Image *image)
1368 %
1369 %  A description of each parameter follows:
1370 %
1371 %    o image: the image.
1372 %
1373 */
1374 MagickExport FILE *GetBlobFileHandle(const Image *image)
1375 {
1376   assert(image != (const Image *) NULL);
1377   assert(image->signature == MagickCoreSignature);
1378   return(image->blob->file_info.file);
1379 }
1380 \f
1381 /*
1382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 %                                                                             %
1384 %                                                                             %
1385 %                                                                             %
1386 +   G e t B l o b I n f o                                                     %
1387 %                                                                             %
1388 %                                                                             %
1389 %                                                                             %
1390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 %
1392 %  GetBlobInfo() initializes the BlobInfo structure.
1393 %
1394 %  The format of the GetBlobInfo method is:
1395 %
1396 %      void GetBlobInfo(BlobInfo *blob_info)
1397 %
1398 %  A description of each parameter follows:
1399 %
1400 %    o blob_info: Specifies a pointer to a BlobInfo structure.
1401 %
1402 */
1403 MagickExport void GetBlobInfo(BlobInfo *blob_info)
1404 {
1405   assert(blob_info != (BlobInfo *) NULL);
1406   (void) ResetMagickMemory(blob_info,0,sizeof(*blob_info));
1407   blob_info->type=UndefinedStream;
1408   blob_info->quantum=(size_t) MagickMaxBlobExtent;
1409   blob_info->properties.st_mtime=time((time_t *) NULL);
1410   blob_info->properties.st_ctime=time((time_t *) NULL);
1411   blob_info->debug=IsEventLogging();
1412   blob_info->reference_count=1;
1413   blob_info->semaphore=AcquireSemaphoreInfo();
1414   blob_info->signature=MagickCoreSignature;
1415 }
1416 \f
1417 /*
1418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419 %                                                                             %
1420 %                                                                             %
1421 %                                                                             %
1422 %  G e t B l o b P r o p e r t i e s                                          %
1423 %                                                                             %
1424 %                                                                             %
1425 %                                                                             %
1426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427 %
1428 %  GetBlobProperties() returns information about an image blob.
1429 %
1430 %  The format of the GetBlobProperties method is:
1431 %
1432 %      const struct stat *GetBlobProperties(const Image *image)
1433 %
1434 %  A description of each parameter follows:
1435 %
1436 %    o image: the image.
1437 %
1438 */
1439 MagickExport const struct stat *GetBlobProperties(const Image *image)
1440 {
1441   assert(image != (Image *) NULL);
1442   assert(image->signature == MagickCoreSignature);
1443   if (image->debug != MagickFalse)
1444     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1445   return(&image->blob->properties);
1446 }
1447 \f
1448 /*
1449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1450 %                                                                             %
1451 %                                                                             %
1452 %                                                                             %
1453 +  G e t B l o b S i z e                                                      %
1454 %                                                                             %
1455 %                                                                             %
1456 %                                                                             %
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458 %
1459 %  GetBlobSize() returns the current length of the image file or blob; zero is
1460 %  returned if the size cannot be determined.
1461 %
1462 %  The format of the GetBlobSize method is:
1463 %
1464 %      MagickSizeType GetBlobSize(const Image *image)
1465 %
1466 %  A description of each parameter follows:
1467 %
1468 %    o image: the image.
1469 %
1470 */
1471 MagickExport MagickSizeType GetBlobSize(const Image *image)
1472 {
1473   MagickSizeType
1474     extent;
1475
1476   assert(image != (Image *) NULL);
1477   assert(image->signature == MagickCoreSignature);
1478   if (image->debug != MagickFalse)
1479     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1480   assert(image->blob != (BlobInfo *) NULL);
1481   extent=0;
1482   switch (image->blob->type)
1483   {
1484     case UndefinedStream:
1485     case StandardStream:
1486     {
1487       extent=image->blob->size;
1488       break;
1489     }
1490     case FileStream:
1491     {
1492       if (fstat(fileno(image->blob->file_info.file),&image->blob->properties) == 0)
1493         extent=(MagickSizeType) image->blob->properties.st_size;
1494       break;
1495     }
1496     case PipeStream:
1497     {
1498       extent=image->blob->size;
1499       break;
1500     }
1501     case ZipStream:
1502     case BZipStream:
1503     {
1504       MagickBooleanType
1505         status;
1506
1507       status=GetPathAttributes(image->filename,&image->blob->properties);
1508       if (status != MagickFalse)
1509         extent=(MagickSizeType) image->blob->properties.st_size;
1510       break;
1511     }
1512     case FifoStream:
1513       break;
1514     case BlobStream:
1515     {
1516       extent=(MagickSizeType) image->blob->length;
1517       break;
1518     }
1519     case CustomStream:
1520       break;
1521   }
1522   return(extent);
1523 }
1524 \f
1525 /*
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1527 %                                                                             %
1528 %                                                                             %
1529 %                                                                             %
1530 +   G e t B l o b S t r e a m D a t a                                         %
1531 %                                                                             %
1532 %                                                                             %
1533 %                                                                             %
1534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535 %
1536 %  GetBlobStreamData() returns the stream data for the image.
1537 %
1538 %  The format of the GetBlobStreamData method is:
1539 %
1540 %      void *GetBlobStreamData(const Image *image)
1541 %
1542 %  A description of each parameter follows:
1543 %
1544 %    o image: the image.
1545 %
1546 */
1547 MagickExport void *GetBlobStreamData(const Image *image)
1548 {
1549   assert(image != (const Image *) NULL);
1550   assert(image->signature == MagickCoreSignature);
1551   return(image->blob->data);
1552 }
1553 \f
1554 /*
1555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556 %                                                                             %
1557 %                                                                             %
1558 %                                                                             %
1559 +   G e t B l o b S t r e a m H a n d l e r                                   %
1560 %                                                                             %
1561 %                                                                             %
1562 %                                                                             %
1563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1564 %
1565 %  GetBlobStreamHandler() returns the stream handler for the image.
1566 %
1567 %  The format of the GetBlobStreamHandler method is:
1568 %
1569 %      StreamHandler GetBlobStreamHandler(const Image *image)
1570 %
1571 %  A description of each parameter follows:
1572 %
1573 %    o image: the image.
1574 %
1575 */
1576 MagickExport StreamHandler GetBlobStreamHandler(const Image *image)
1577 {
1578   assert(image != (const Image *) NULL);
1579   assert(image->signature == MagickCoreSignature);
1580   if (image->debug != MagickFalse)
1581     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1582   return(image->blob->stream);
1583 }
1584 \f
1585 /*
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 %                                                                             %
1588 %                                                                             %
1589 %                                                                             %
1590 %   I m a g e T o B l o b                                                     %
1591 %                                                                             %
1592 %                                                                             %
1593 %                                                                             %
1594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 %
1596 %  ImageToBlob() implements direct to memory image formats.  It returns the
1597 %  image as a formatted blob and its length.  The magick member of the Image
1598 %  structure determines the format of the returned blob (GIF, JPEG, PNG,
1599 %  etc.).  This method is the equivalent of WriteImage(), but writes the
1600 %  formatted "file" to a memory buffer rather than to an actual file.
1601 %
1602 %  The format of the ImageToBlob method is:
1603 %
1604 %      void *ImageToBlob(const ImageInfo *image_info,Image *image,
1605 %        size_t *length,ExceptionInfo *exception)
1606 %
1607 %  A description of each parameter follows:
1608 %
1609 %    o image_info: the image info.
1610 %
1611 %    o image: the image.
1612 %
1613 %    o length: return the actual length of the blob.
1614 %
1615 %    o exception: return any errors or warnings in this structure.
1616 %
1617 */
1618 MagickExport void *ImageToBlob(const ImageInfo *image_info,
1619   Image *image,size_t *length,ExceptionInfo *exception)
1620 {
1621   const MagickInfo
1622     *magick_info;
1623
1624   ImageInfo
1625     *blob_info;
1626
1627   MagickBooleanType
1628     status;
1629
1630   void
1631     *blob;
1632
1633   assert(image_info != (const ImageInfo *) NULL);
1634   assert(image_info->signature == MagickCoreSignature);
1635   if (image_info->debug != MagickFalse)
1636     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1637       image_info->filename);
1638   assert(image != (Image *) NULL);
1639   assert(image->signature == MagickCoreSignature);
1640   assert(exception != (ExceptionInfo *) NULL);
1641   *length=0;
1642   blob=(unsigned char *) NULL;
1643   blob_info=CloneImageInfo(image_info);
1644   blob_info->adjoin=MagickFalse;
1645   (void) SetImageInfo(blob_info,1,exception);
1646   if (*blob_info->magick != '\0')
1647     (void) CopyMagickString(image->magick,blob_info->magick,MagickPathExtent);
1648   magick_info=GetMagickInfo(image->magick,exception);
1649   if (magick_info == (const MagickInfo *) NULL)
1650     {
1651       (void) ThrowMagickException(exception,GetMagickModule(),
1652         MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
1653         image->magick);
1654       blob_info=DestroyImageInfo(blob_info);
1655       return(blob);
1656     }
1657   (void) CopyMagickString(blob_info->magick,image->magick,MagickPathExtent);
1658   if (GetMagickBlobSupport(magick_info) != MagickFalse)
1659     {
1660       /*
1661         Native blob support for this image format.
1662       */
1663       blob_info->length=0;
1664       blob_info->blob=AcquireQuantumMemory(MagickMaxBlobExtent,
1665         sizeof(unsigned char));
1666       if (blob_info->blob == NULL)
1667         (void) ThrowMagickException(exception,GetMagickModule(),
1668           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1669       else
1670         {
1671           (void) CloseBlob(image);
1672           image->blob->exempt=MagickTrue;
1673           *image->filename='\0';
1674           status=WriteImage(blob_info,image,exception);
1675           *length=image->blob->length;
1676           blob=DetachBlob(image->blob);
1677           if (status == MagickFalse)
1678             blob=RelinquishMagickMemory(blob);
1679           else
1680             blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
1681         }
1682     }
1683   else
1684     {
1685       char
1686         unique[MagickPathExtent];
1687
1688       int
1689         file;
1690
1691       /*
1692         Write file to disk in blob image format.
1693       */
1694       file=AcquireUniqueFileResource(unique);
1695       if (file == -1)
1696         {
1697           ThrowFileException(exception,BlobError,"UnableToWriteBlob",
1698             image_info->filename);
1699         }
1700       else
1701         {
1702           blob_info->file=fdopen(file,"wb");
1703           if (blob_info->file != (FILE *) NULL)
1704             {
1705               (void) FormatLocaleString(image->filename,MagickPathExtent,
1706                 "%s:%s",image->magick,unique);
1707               status=WriteImage(blob_info,image,exception);
1708               (void) CloseBlob(image);
1709               (void) fclose(blob_info->file);
1710               if (status != MagickFalse)
1711                 blob=FileToBlob(unique,~0UL,length,exception);
1712             }
1713           (void) RelinquishUniqueFileResource(unique);
1714         }
1715     }
1716   blob_info=DestroyImageInfo(blob_info);
1717   return(blob);
1718 }
1719 \f
1720 /*
1721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1722 %                                                                             %
1723 %                                                                             %
1724 %                                                                             %
1725 +  I m a g e T o C u s t o m S t r e a m                                      %
1726 %                                                                             %
1727 %                                                                             %
1728 %                                                                             %
1729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1730 %
1731 %  ImageToCustomStream() is the equivalent of WriteImage(), but writes the
1732 %  formatted "file" to the custom stream rather than to an actual file.
1733 %
1734 %  The format of the ImageToCustomStream method is:
1735 %
1736 %      void ImageToCustomStream(const ImageInfo *image_info,Image *image,
1737 %        ExceptionInfo *exception)
1738 %
1739 %  A description of each parameter follows:
1740 %
1741 %    o image_info: the image info.
1742 %
1743 %    o image: the image.
1744 %
1745 %    o exception: return any errors or warnings in this structure.
1746 %
1747 */
1748 MagickExport void ImageToCustomStream(const ImageInfo *image_info,Image *image,
1749   ExceptionInfo *exception)
1750 {
1751   const MagickInfo
1752     *magick_info;
1753
1754   ImageInfo
1755     *blob_info;
1756
1757   MagickBooleanType
1758     status;
1759
1760   assert(image_info != (const ImageInfo *) NULL);
1761   assert(image_info->signature == MagickCoreSignature);
1762   if (image_info->debug != MagickFalse)
1763     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1764       image_info->filename);
1765   assert(image != (Image *) NULL);
1766   assert(image->signature == MagickCoreSignature);
1767   assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
1768   assert(image_info->custom_stream->signature == MagickCoreSignature);
1769   assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
1770   assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
1771   assert(exception != (ExceptionInfo *) NULL);
1772   blob_info=CloneImageInfo(image_info);
1773   blob_info->adjoin=MagickFalse;
1774   (void) SetImageInfo(blob_info,1,exception);
1775   if (*blob_info->magick != '\0')
1776     (void) CopyMagickString(image->magick,blob_info->magick,MagickPathExtent);
1777   magick_info=GetMagickInfo(image->magick,exception);
1778   if (magick_info == (const MagickInfo *) NULL)
1779     {
1780       (void) ThrowMagickException(exception,GetMagickModule(),
1781         MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
1782         image->magick);
1783       blob_info=DestroyImageInfo(blob_info);
1784       return;
1785     }
1786   (void) CopyMagickString(blob_info->magick,image->magick,MagickPathExtent);
1787   if (GetMagickBlobSupport(magick_info) != MagickFalse)
1788     {
1789       /*
1790         Native blob support for this image format.
1791       */
1792       (void) CloseBlob(image);
1793       *image->filename='\0';
1794       (void) WriteImage(blob_info,image,exception);
1795       (void) CloseBlob(image);
1796     }
1797   else
1798     {
1799       char
1800         unique[MagickPathExtent];
1801
1802       int
1803         file;
1804
1805       unsigned char
1806         *blob;
1807
1808       /*
1809         Write file to disk in blob image format.
1810       */
1811       blob_info->custom_stream=(CustomStreamInfo *) NULL;
1812       blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
1813         sizeof(*blob));
1814       if (blob == (unsigned char *) NULL)
1815         {
1816           ThrowFileException(exception,BlobError,"UnableToWriteBlob",
1817             image_info->filename);
1818           blob_info=DestroyImageInfo(blob_info);
1819           return;
1820         }
1821       file=AcquireUniqueFileResource(unique);
1822       if (file == -1)
1823         {
1824           ThrowFileException(exception,BlobError,"UnableToWriteBlob",
1825             image_info->filename);
1826           blob=(unsigned char *) RelinquishMagickMemory(blob);
1827           blob_info=DestroyImageInfo(blob_info);
1828           return;
1829         }
1830       blob_info->file=fdopen(file,"wb+");
1831       if (blob_info->file != (FILE *) NULL)
1832         {
1833           ssize_t
1834             count;
1835
1836           (void) FormatLocaleString(image->filename,MagickPathExtent,
1837             "%s:%s",image->magick,unique);
1838           status=WriteImage(blob_info,image,exception);
1839           (void) CloseBlob(image);
1840           if (status != MagickFalse)
1841             {
1842               (void) fseek(blob_info->file,0,SEEK_SET);
1843               count=(ssize_t) MagickMaxBufferExtent;
1844               while (count == (ssize_t) MagickMaxBufferExtent)
1845               {
1846                 count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
1847                   blob_info->file);
1848                 image_info->custom_stream->writer(blob,count,
1849                   image_info->custom_stream->data);
1850               }
1851             }
1852           (void) fclose(blob_info->file);
1853         }
1854       blob=(unsigned char *) RelinquishMagickMemory(blob);
1855       (void) RelinquishUniqueFileResource(unique);
1856     }
1857   blob_info=DestroyImageInfo(blob_info);
1858 }
1859 \f
1860 /*
1861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862 %                                                                             %
1863 %                                                                             %
1864 %                                                                             %
1865 %   I m a g e T o F i l e                                                     %
1866 %                                                                             %
1867 %                                                                             %
1868 %                                                                             %
1869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1870 %
1871 %  ImageToFile() writes an image to a file.  It returns MagickFalse if an error
1872 %  occurs otherwise MagickTrue.
1873 %
1874 %  The format of the ImageToFile method is:
1875 %
1876 %       MagickBooleanType ImageToFile(Image *image,char *filename,
1877 %         ExceptionInfo *exception)
1878 %
1879 %  A description of each parameter follows:
1880 %
1881 %    o image: the image.
1882 %
1883 %    o filename: Write the image to this file.
1884 %
1885 %    o exception: return any errors or warnings in this structure.
1886 %
1887 */
1888 MagickExport MagickBooleanType ImageToFile(Image *image,char *filename,
1889   ExceptionInfo *exception)
1890 {
1891   int
1892     file;
1893
1894   register const unsigned char
1895     *p;
1896
1897   register size_t
1898     i;
1899
1900   size_t
1901     length,
1902     quantum;
1903
1904   ssize_t
1905     count;
1906
1907   struct stat
1908     file_stats;
1909
1910   unsigned char
1911     *buffer;
1912
1913   assert(image != (Image *) NULL);
1914   assert(image->signature == MagickCoreSignature);
1915   assert(image->blob != (BlobInfo *) NULL);
1916   assert(image->blob->type != UndefinedStream);
1917   if (image->debug != MagickFalse)
1918     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1919   assert(filename != (const char *) NULL);
1920   if (*filename == '\0')
1921     file=AcquireUniqueFileResource(filename);
1922   else
1923     if (LocaleCompare(filename,"-") == 0)
1924       file=fileno(stdout);
1925     else
1926       file=open_utf8(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
1927   if (file == -1)
1928     {
1929       ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1930       return(MagickFalse);
1931     }
1932   quantum=(size_t) MagickMaxBufferExtent;
1933   if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1934     quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1935   buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
1936   if (buffer == (unsigned char *) NULL)
1937     {
1938       file=close(file)-1;
1939       (void) ThrowMagickException(exception,GetMagickModule(),
1940         ResourceLimitError,"MemoryAllocationError","`%s'",filename);
1941       return(MagickFalse);
1942     }
1943   length=0;
1944   p=(const unsigned char *) ReadBlobStream(image,quantum,buffer,&count);
1945   for (i=0; count > 0; )
1946   {
1947     length=(size_t) count;
1948     for (i=0; i < length; i+=count)
1949     {
1950       count=write(file,p+i,(size_t) (length-i));
1951       if (count <= 0)
1952         {
1953           count=0;
1954           if (errno != EINTR)
1955             break;
1956         }
1957     }
1958     if (i < length)
1959       break;
1960     p=(const unsigned char *) ReadBlobStream(image,quantum,buffer,&count);
1961   }
1962   if (LocaleCompare(filename,"-") != 0)
1963     file=close(file);
1964   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1965   if ((file == -1) || (i < length))
1966     {
1967       if (file != -1)
1968         file=close(file);
1969       ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1970       return(MagickFalse);
1971     }
1972   return(MagickTrue);
1973 }
1974 \f
1975 /*
1976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977 %                                                                             %
1978 %                                                                             %
1979 %                                                                             %
1980 %   I m a g e s T o B l o b                                                   %
1981 %                                                                             %
1982 %                                                                             %
1983 %                                                                             %
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985 %
1986 %  ImagesToBlob() implements direct to memory image formats.  It returns the
1987 %  image sequence as a blob and its length.  The magick member of the ImageInfo
1988 %  structure determines the format of the returned blob (GIF, JPEG,  PNG, etc.)
1989 %
1990 %  Note, some image formats do not permit multiple images to the same image
1991 %  stream (e.g. JPEG).  in this instance, just the first image of the
1992 %  sequence is returned as a blob.
1993 %
1994 %  The format of the ImagesToBlob method is:
1995 %
1996 %      void *ImagesToBlob(const ImageInfo *image_info,Image *images,
1997 %        size_t *length,ExceptionInfo *exception)
1998 %
1999 %  A description of each parameter follows:
2000 %
2001 %    o image_info: the image info.
2002 %
2003 %    o images: the image list.
2004 %
2005 %    o length: return the actual length of the blob.
2006 %
2007 %    o exception: return any errors or warnings in this structure.
2008 %
2009 */
2010 MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images,
2011   size_t *length,ExceptionInfo *exception)
2012 {
2013   const MagickInfo
2014     *magick_info;
2015
2016   ImageInfo
2017     *blob_info;
2018
2019   MagickBooleanType
2020     status;
2021
2022   void
2023     *blob;
2024
2025   assert(image_info != (const ImageInfo *) NULL);
2026   assert(image_info->signature == MagickCoreSignature);
2027   if (image_info->debug != MagickFalse)
2028     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2029       image_info->filename);
2030   assert(images != (Image *) NULL);
2031   assert(images->signature == MagickCoreSignature);
2032   assert(exception != (ExceptionInfo *) NULL);
2033   *length=0;
2034   blob=(unsigned char *) NULL;
2035   blob_info=CloneImageInfo(image_info);
2036   (void) SetImageInfo(blob_info,(unsigned int) GetImageListLength(images),
2037     exception);
2038   if (*blob_info->magick != '\0')
2039     (void) CopyMagickString(images->magick,blob_info->magick,MagickPathExtent);
2040   magick_info=GetMagickInfo(images->magick,exception);
2041   if (magick_info == (const MagickInfo *) NULL)
2042     {
2043       (void) ThrowMagickException(exception,GetMagickModule(),
2044         MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
2045         images->magick);
2046       blob_info=DestroyImageInfo(blob_info);
2047       return(blob);
2048     }
2049   if (GetMagickAdjoin(magick_info) == MagickFalse)
2050     {
2051       blob_info=DestroyImageInfo(blob_info);
2052       return(ImageToBlob(image_info,images,length,exception));
2053     }
2054   (void) CopyMagickString(blob_info->magick,images->magick,MagickPathExtent);
2055   if (GetMagickBlobSupport(magick_info) != MagickFalse)
2056     {
2057       /*
2058         Native blob support for this images format.
2059       */
2060       blob_info->length=0;
2061       blob_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
2062         sizeof(unsigned char));
2063       if (blob_info->blob == (void *) NULL)
2064         (void) ThrowMagickException(exception,GetMagickModule(),
2065           ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
2066       else
2067         {
2068           (void) CloseBlob(images);
2069           images->blob->exempt=MagickTrue;
2070           *images->filename='\0';
2071           status=WriteImages(blob_info,images,images->filename,exception);
2072           *length=images->blob->length;
2073           blob=DetachBlob(images->blob);
2074           if (status == MagickFalse)
2075             blob=RelinquishMagickMemory(blob);
2076           else
2077             blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
2078         }
2079     }
2080   else
2081     {
2082       char
2083         filename[MagickPathExtent],
2084         unique[MagickPathExtent];
2085
2086       int
2087         file;
2088
2089       /*
2090         Write file to disk in blob images format.
2091       */
2092       file=AcquireUniqueFileResource(unique);
2093       if (file == -1)
2094         {
2095           ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",
2096             image_info->filename);
2097         }
2098       else
2099         {
2100           blob_info->file=fdopen(file,"wb");
2101           if (blob_info->file != (FILE *) NULL)
2102             {
2103               (void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
2104                 images->magick,unique);
2105               status=WriteImages(blob_info,images,filename,exception);
2106               (void) CloseBlob(images);
2107               (void) fclose(blob_info->file);
2108               if (status != MagickFalse)
2109                 blob=FileToBlob(unique,~0UL,length,exception);
2110             }
2111           (void) RelinquishUniqueFileResource(unique);
2112         }
2113     }
2114   blob_info=DestroyImageInfo(blob_info);
2115   return(blob);
2116 }
2117 \f
2118 /*
2119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2120 %                                                                             %
2121 %                                                                             %
2122 %                                                                             %
2123 +  I m a g e s T o C u s t o m B l o b                                        %
2124 %                                                                             %
2125 %                                                                             %
2126 %                                                                             %
2127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2128 %
2129 %  ImagesToCustomStream() is the equivalent of WriteImages(), but writes the
2130 %  formatted "file" to the custom stream rather than to an actual file.
2131 %
2132 %  The format of the ImageToCustomStream method is:
2133 %
2134 %      void ImagesToCustomStream(const ImageInfo *image_info,Image *images,
2135 %        ExceptionInfo *exception)
2136 %
2137 %  A description of each parameter follows:
2138 %
2139 %    o image_info: the image info.
2140 %
2141 %    o images: the image list.
2142 %
2143 %    o exception: return any errors or warnings in this structure.
2144 %
2145 */
2146 MagickExport void ImagesToCustomStream(const ImageInfo *image_info,
2147   Image *images,ExceptionInfo *exception)
2148 {
2149   const MagickInfo
2150     *magick_info;
2151
2152   ImageInfo
2153     *blob_info;
2154
2155   MagickBooleanType
2156     status;
2157
2158   assert(image_info != (const ImageInfo *) NULL);
2159   assert(image_info->signature == MagickCoreSignature);
2160   if (image_info->debug != MagickFalse)
2161     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2162       image_info->filename);
2163   assert(images != (Image *) NULL);
2164   assert(images->signature == MagickCoreSignature);
2165   assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
2166   assert(image_info->custom_stream->signature == MagickCoreSignature);
2167   assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
2168   assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
2169   assert(exception != (ExceptionInfo *) NULL);
2170   blob_info=CloneImageInfo(image_info);
2171   (void) SetImageInfo(blob_info,(unsigned int) GetImageListLength(images),
2172     exception);
2173   if (*blob_info->magick != '\0')
2174     (void) CopyMagickString(images->magick,blob_info->magick,MagickPathExtent);
2175   magick_info=GetMagickInfo(images->magick,exception);
2176   if (magick_info == (const MagickInfo *) NULL)
2177     {
2178       (void) ThrowMagickException(exception,GetMagickModule(),
2179         MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
2180         images->magick);
2181       blob_info=DestroyImageInfo(blob_info);
2182       return;
2183     }
2184   (void) CopyMagickString(blob_info->magick,images->magick,MagickPathExtent);
2185   if (GetMagickBlobSupport(magick_info) != MagickFalse)
2186     {
2187       /*
2188         Native blob support for this image format.
2189       */
2190       (void) CloseBlob(images);
2191       *images->filename='\0';
2192       (void) WriteImages(blob_info,images,images->filename,exception);
2193       (void) CloseBlob(images);
2194     }
2195   else
2196     {
2197       char
2198         filename[MagickPathExtent],
2199         unique[MagickPathExtent];
2200
2201       int
2202         file;
2203
2204       unsigned char
2205         *blob;
2206
2207       /*
2208         Write file to disk in blob image format.
2209       */
2210       blob_info->custom_stream=(CustomStreamInfo *) NULL;
2211       blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
2212         sizeof(*blob));
2213       if (blob == (unsigned char *) NULL)
2214         {
2215           ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2216             image_info->filename);
2217           blob_info=DestroyImageInfo(blob_info);
2218           return;
2219         }
2220       file=AcquireUniqueFileResource(unique);
2221       if (file == -1)
2222         {
2223           ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2224             image_info->filename);
2225           blob=(unsigned char *) RelinquishMagickMemory(blob);
2226           blob_info=DestroyImageInfo(blob_info);
2227           return;
2228         }
2229       blob_info->file=fdopen(file,"wb+");
2230       if (blob_info->file != (FILE *) NULL)
2231         {
2232           ssize_t
2233             count;
2234
2235           (void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
2236             images->magick,unique);
2237           status=WriteImages(blob_info,images,filename,exception);
2238           (void) CloseBlob(images);
2239           if (status != MagickFalse)
2240             {
2241               (void) fseek(blob_info->file,0,SEEK_SET);
2242               count=(ssize_t) MagickMaxBufferExtent;
2243               while (count == (ssize_t) MagickMaxBufferExtent)
2244               {
2245                 count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
2246                   blob_info->file);
2247                 image_info->custom_stream->writer(blob,count,
2248                   image_info->custom_stream->data);
2249               }
2250             }
2251           (void) fclose(blob_info->file);
2252         }
2253       blob=(unsigned char *) RelinquishMagickMemory(blob);
2254       (void) RelinquishUniqueFileResource(unique);
2255     }
2256   blob_info=DestroyImageInfo(blob_info);
2257   return;
2258 }
2259 \f
2260 /*
2261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262 %                                                                             %
2263 %                                                                             %
2264 %                                                                             %
2265 %   I n j e c t I m a g e B l o b                                             %
2266 %                                                                             %
2267 %                                                                             %
2268 %                                                                             %
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 %
2271 %  InjectImageBlob() injects the image with a copy of itself in the specified
2272 %  format (e.g. inject JPEG into a PDF image).
2273 %
2274 %  The format of the InjectImageBlob method is:
2275 %
2276 %      MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
2277 %        Image *image,Image *inject_image,const char *format,
2278 %        ExceptionInfo *exception)
2279 %
2280 %  A description of each parameter follows:
2281 %
2282 %    o image_info: the image info..
2283 %
2284 %    o image: the image.
2285 %
2286 %    o inject_image: inject into the image stream.
2287 %
2288 %    o format: the image format.
2289 %
2290 %    o exception: return any errors or warnings in this structure.
2291 %
2292 */
2293 MagickExport MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
2294   Image *image,Image *inject_image,const char *format,ExceptionInfo *exception)
2295 {
2296   char
2297     filename[MagickPathExtent];
2298
2299   FILE
2300     *unique_file;
2301
2302   Image
2303     *byte_image;
2304
2305   ImageInfo
2306     *write_info;
2307
2308   int
2309     file;
2310
2311   MagickBooleanType
2312     status;
2313
2314   register ssize_t
2315     i;
2316
2317   size_t
2318     quantum;
2319
2320   ssize_t
2321     count;
2322
2323   struct stat
2324     file_stats;
2325
2326   unsigned char
2327     *buffer;
2328
2329   /*
2330     Write inject image to a temporary file.
2331   */
2332   assert(image_info != (ImageInfo *) NULL);
2333   assert(image_info->signature == MagickCoreSignature);
2334   assert(image != (Image *) NULL);
2335   assert(image->signature == MagickCoreSignature);
2336   if (image->debug != MagickFalse)
2337     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2338   assert(inject_image != (Image *) NULL);
2339   assert(inject_image->signature == MagickCoreSignature);
2340   assert(exception != (ExceptionInfo *) NULL);
2341   unique_file=(FILE *) NULL;
2342   file=AcquireUniqueFileResource(filename);
2343   if (file != -1)
2344     unique_file=fdopen(file,"wb");
2345   if ((file == -1) || (unique_file == (FILE *) NULL))
2346     {
2347       (void) CopyMagickString(image->filename,filename,MagickPathExtent);
2348       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2349         image->filename);
2350       return(MagickFalse);
2351     }
2352   byte_image=CloneImage(inject_image,0,0,MagickFalse,exception);
2353   if (byte_image == (Image *) NULL)
2354     {
2355       (void) fclose(unique_file);
2356       (void) RelinquishUniqueFileResource(filename);
2357       return(MagickFalse);
2358     }
2359   (void) FormatLocaleString(byte_image->filename,MagickPathExtent,"%s:%s",
2360     format,filename);
2361   DestroyBlob(byte_image);
2362   byte_image->blob=CloneBlobInfo((BlobInfo *) NULL);
2363   write_info=CloneImageInfo(image_info);
2364   SetImageInfoFile(write_info,unique_file);
2365   status=WriteImage(write_info,byte_image,exception);
2366   write_info=DestroyImageInfo(write_info);
2367   byte_image=DestroyImage(byte_image);
2368   (void) fclose(unique_file);
2369   if (status == MagickFalse)
2370     {
2371       (void) RelinquishUniqueFileResource(filename);
2372       return(MagickFalse);
2373     }
2374   /*
2375     Inject into image stream.
2376   */
2377   file=open_utf8(filename,O_RDONLY | O_BINARY,0);
2378   if (file == -1)
2379     {
2380       (void) RelinquishUniqueFileResource(filename);
2381       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
2382         image_info->filename);
2383       return(MagickFalse);
2384     }
2385   quantum=(size_t) MagickMaxBufferExtent;
2386   if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
2387     quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
2388   buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
2389   if (buffer == (unsigned char *) NULL)
2390     {
2391       (void) RelinquishUniqueFileResource(filename);
2392       file=close(file);
2393       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2394         image->filename);
2395     }
2396   for (i=0; ; i+=count)
2397   {
2398     count=read(file,buffer,quantum);
2399     if (count <= 0)
2400       {
2401         count=0;
2402         if (errno != EINTR)
2403           break;
2404       }
2405     status=WriteBlobStream(image,(size_t) count,buffer) == count ? MagickTrue :
2406       MagickFalse;
2407   }
2408   file=close(file);
2409   if (file == -1)
2410     ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",filename);
2411   (void) RelinquishUniqueFileResource(filename);
2412   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2413   return(status);
2414 }
2415 \f
2416 /*
2417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2418 %                                                                             %
2419 %                                                                             %
2420 %                                                                             %
2421 %   I s B l o b E x e m p t                                                   %
2422 %                                                                             %
2423 %                                                                             %
2424 %                                                                             %
2425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426 %
2427 %  IsBlobExempt() returns true if the blob is exempt.
2428 %
2429 %  The format of the IsBlobExempt method is:
2430 %
2431 %       MagickBooleanType IsBlobExempt(const Image *image)
2432 %
2433 %  A description of each parameter follows:
2434 %
2435 %    o image: the image.
2436 %
2437 */
2438 MagickExport MagickBooleanType IsBlobExempt(const Image *image)
2439 {
2440   assert(image != (const Image *) NULL);
2441   assert(image->signature == MagickCoreSignature);
2442   if (image->debug != MagickFalse)
2443     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2444   return(image->blob->exempt);
2445 }
2446 \f
2447 /*
2448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2449 %                                                                             %
2450 %                                                                             %
2451 %                                                                             %
2452 %   I s B l o b S e e k a b l e                                               %
2453 %                                                                             %
2454 %                                                                             %
2455 %                                                                             %
2456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457 %
2458 %  IsBlobSeekable() returns true if the blob is seekable.
2459 %
2460 %  The format of the IsBlobSeekable method is:
2461 %
2462 %       MagickBooleanType IsBlobSeekable(const Image *image)
2463 %
2464 %  A description of each parameter follows:
2465 %
2466 %    o image: the image.
2467 %
2468 */
2469 MagickExport MagickBooleanType IsBlobSeekable(const Image *image)
2470 {
2471   MagickBooleanType
2472     seekable;
2473
2474   assert(image != (const Image *) NULL);
2475   assert(image->signature == MagickCoreSignature);
2476   if (image->debug != MagickFalse)
2477     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2478   switch (image->blob->type)
2479   {
2480     case FileStream:
2481     case BlobStream:
2482     case ZipStream:
2483     {
2484       seekable=MagickTrue;
2485       break;
2486     }
2487     case UndefinedStream:
2488     case StandardStream:
2489     case BZipStream:
2490     case FifoStream:
2491     case PipeStream:
2492     default:
2493     {
2494       seekable=MagickFalse;
2495       break;
2496     }
2497     case CustomStream:
2498     {
2499       if ((image->blob->custom_stream->seeker != (CustomStreamSeeker) NULL) &&
2500           (image->blob->custom_stream->teller != (CustomStreamTeller) NULL))
2501         seekable=MagickTrue;
2502       else
2503         seekable=MagickFalse;
2504       break;
2505     }
2506   }
2507   return(seekable);
2508 }
2509 \f
2510 /*
2511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2512 %                                                                             %
2513 %                                                                             %
2514 %                                                                             %
2515 %   I s B l o b T e m p o r a r y                                             %
2516 %                                                                             %
2517 %                                                                             %
2518 %                                                                             %
2519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2520 %
2521 %  IsBlobTemporary() returns true if the blob is temporary.
2522 %
2523 %  The format of the IsBlobTemporary method is:
2524 %
2525 %       MagickBooleanType IsBlobTemporary(const Image *image)
2526 %
2527 %  A description of each parameter follows:
2528 %
2529 %    o image: the image.
2530 %
2531 */
2532 MagickExport MagickBooleanType IsBlobTemporary(const Image *image)
2533 {
2534   assert(image != (const Image *) NULL);
2535   assert(image->signature == MagickCoreSignature);
2536   if (image->debug != MagickFalse)
2537     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2538   return(image->blob->temporary);
2539 }
2540 \f
2541 /*
2542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543 %                                                                             %
2544 %                                                                             %
2545 %                                                                             %
2546 +  M a p B l o b                                                              %
2547 %                                                                             %
2548 %                                                                             %
2549 %                                                                             %
2550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551 %
2552 %  MapBlob() creates a mapping from a file to a binary large object.
2553 %
2554 %  The format of the MapBlob method is:
2555 %
2556 %      void *MapBlob(int file,const MapMode mode,const MagickOffsetType offset,
2557 %        const size_t length)
2558 %
2559 %  A description of each parameter follows:
2560 %
2561 %    o file: map this file descriptor.
2562 %
2563 %    o mode: ReadMode, WriteMode, or IOMode.
2564 %
2565 %    o offset: starting at this offset within the file.
2566 %
2567 %    o length: the length of the mapping is returned in this pointer.
2568 %
2569 */
2570 MagickExport void *MapBlob(int file,const MapMode mode,
2571   const MagickOffsetType offset,const size_t length)
2572 {
2573 #if defined(MAGICKCORE_HAVE_MMAP)
2574   int
2575     flags,
2576     protection;
2577
2578   void
2579     *map;
2580
2581   /*
2582     Map file.
2583   */
2584   flags=0;
2585   if (file == -1)
2586 #if defined(MAP_ANONYMOUS)
2587     flags|=MAP_ANONYMOUS;
2588 #else
2589     return(NULL);
2590 #endif
2591   switch (mode)
2592   {
2593     case ReadMode:
2594     default:
2595     {
2596       protection=PROT_READ;
2597       flags|=MAP_PRIVATE;
2598       break;
2599     }
2600     case WriteMode:
2601     {
2602       protection=PROT_WRITE;
2603       flags|=MAP_SHARED;
2604       break;
2605     }
2606     case IOMode:
2607     {
2608       protection=PROT_READ | PROT_WRITE;
2609       flags|=MAP_SHARED;
2610       break;
2611     }
2612   }
2613 #if !defined(MAGICKCORE_HAVE_HUGEPAGES) || !defined(MAP_HUGETLB)
2614   map=mmap((char *) NULL,length,protection,flags,file,(off_t) offset);
2615 #else
2616   map=mmap((char *) NULL,length,protection,flags | MAP_HUGETLB,file,(off_t)
2617     offset);
2618   if (map == MAP_FAILED)
2619     map=mmap((char *) NULL,length,protection,flags,file,(off_t) offset);
2620 #endif
2621   if (map == MAP_FAILED)
2622     return(NULL);
2623   return(map);
2624 #else
2625   (void) file;
2626   (void) mode;
2627   (void) offset;
2628   (void) length;
2629   return(NULL);
2630 #endif
2631 }
2632 \f
2633 /*
2634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635 %                                                                             %
2636 %                                                                             %
2637 %                                                                             %
2638 +  M S B O r d e r L o n g                                                    %
2639 %                                                                             %
2640 %                                                                             %
2641 %                                                                             %
2642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2643 %
2644 %  MSBOrderLong() converts a least-significant byte first buffer of integers to
2645 %  most-significant byte first.
2646 %
2647 %  The format of the MSBOrderLong method is:
2648 %
2649 %      void MSBOrderLong(unsigned char *buffer,const size_t length)
2650 %
2651 %  A description of each parameter follows.
2652 %
2653 %   o  buffer:  Specifies a pointer to a buffer of integers.
2654 %
2655 %   o  length:  Specifies the length of the buffer.
2656 %
2657 */
2658 MagickExport void MSBOrderLong(unsigned char *buffer,const size_t length)
2659 {
2660   int
2661     c;
2662
2663   register unsigned char
2664     *p,
2665     *q;
2666
2667   assert(buffer != (unsigned char *) NULL);
2668   q=buffer+length;
2669   while (buffer < q)
2670   {
2671     p=buffer+3;
2672     c=(int) (*p);
2673     *p=(*buffer);
2674     *buffer++=(unsigned char) c;
2675     p=buffer+1;
2676     c=(int) (*p);
2677     *p=(*buffer);
2678     *buffer++=(unsigned char) c;
2679     buffer+=2;
2680   }
2681 }
2682 \f
2683 /*
2684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2685 %                                                                             %
2686 %                                                                             %
2687 %                                                                             %
2688 +  M S B O r d e r S h o r t                                                  %
2689 %                                                                             %
2690 %                                                                             %
2691 %                                                                             %
2692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2693 %
2694 %  MSBOrderShort() converts a least-significant byte first buffer of integers
2695 %  to most-significant byte first.
2696 %
2697 %  The format of the MSBOrderShort method is:
2698 %
2699 %      void MSBOrderShort(unsigned char *p,const size_t length)
2700 %
2701 %  A description of each parameter follows.
2702 %
2703 %   o  p:  Specifies a pointer to a buffer of integers.
2704 %
2705 %   o  length:  Specifies the length of the buffer.
2706 %
2707 */
2708 MagickExport void MSBOrderShort(unsigned char *p,const size_t length)
2709 {
2710   int
2711     c;
2712
2713   register unsigned char
2714     *q;
2715
2716   assert(p != (unsigned char *) NULL);
2717   q=p+length;
2718   while (p < q)
2719   {
2720     c=(int) (*p);
2721     *p=(*(p+1));
2722     p++;
2723     *p++=(unsigned char) c;
2724   }
2725 }
2726 \f
2727 /*
2728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2729 %                                                                             %
2730 %                                                                             %
2731 %                                                                             %
2732 +   O p e n B l o b                                                           %
2733 %                                                                             %
2734 %                                                                             %
2735 %                                                                             %
2736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2737 %
2738 %  OpenBlob() opens a file associated with the image.  A file name of '-' sets
2739 %  the file to stdin for type 'r' and stdout for type 'w'.  If the filename
2740 %  suffix is '.gz' or '.Z', the image is decompressed for type 'r' and
2741 %  compressed for type 'w'.  If the filename prefix is '|', it is piped to or
2742 %  from a system command.
2743 %
2744 %  The format of the OpenBlob method is:
2745 %
2746 %       MagickBooleanType OpenBlob(const ImageInfo *image_info,Image *image,
2747 %        const BlobMode mode,ExceptionInfo *exception)
2748 %
2749 %  A description of each parameter follows:
2750 %
2751 %    o image_info: the image info.
2752 %
2753 %    o image: the image.
2754 %
2755 %    o mode: the mode for opening the file.
2756 %
2757 */
2758
2759 static inline MagickBooleanType SetStreamBuffering(const ImageInfo *image_info,
2760   Image *image)
2761 {
2762   const char
2763     *option;
2764
2765   int
2766     status;
2767
2768   size_t
2769     size;
2770
2771   size=16384;
2772   option=GetImageOption(image_info,"stream:buffer-size");
2773   if (option != (const char *) NULL)
2774     size=StringToUnsignedLong(option);
2775   status=setvbuf(image->blob->file_info.file,(char *) NULL,size == 0 ?
2776     _IONBF : _IOFBF,size);
2777   return(status == 0 ? MagickTrue : MagickFalse);
2778 }
2779
2780 MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info,
2781   Image *image,const BlobMode mode,ExceptionInfo *exception)
2782 {
2783   char
2784     extension[MagickPathExtent],
2785     filename[MagickPathExtent];
2786
2787   const char
2788     *type;
2789
2790   MagickBooleanType
2791     status;
2792
2793   PolicyRights
2794     rights;
2795
2796   assert(image_info != (ImageInfo *) NULL);
2797   assert(image_info->signature == MagickCoreSignature);
2798   if (image_info->debug != MagickFalse)
2799     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2800       image_info->filename);
2801   assert(image != (Image *) NULL);
2802   assert(image->signature == MagickCoreSignature);
2803   if (image_info->blob != (void *) NULL)
2804     {
2805       if (image_info->stream != (StreamHandler) NULL)
2806         image->blob->stream=(StreamHandler) image_info->stream;
2807       AttachBlob(image->blob,image_info->blob,image_info->length);
2808       return(MagickTrue);
2809     }
2810   if ((image_info->custom_stream != (CustomStreamInfo *) NULL) &&
2811       (*image->filename == '\0'))
2812     {
2813       image->blob->type=CustomStream;
2814       image->blob->custom_stream=image_info->custom_stream;
2815       return(MagickTrue);
2816     }
2817   (void) DetachBlob(image->blob);
2818   switch (mode)
2819   {
2820     default: type="r"; break;
2821     case ReadBlobMode: type="r"; break;
2822     case ReadBinaryBlobMode: type="rb"; break;
2823     case WriteBlobMode: type="w"; break;
2824     case WriteBinaryBlobMode: type="w+b"; break;
2825     case AppendBlobMode: type="a"; break;
2826     case AppendBinaryBlobMode: type="a+b"; break;
2827   }
2828   if (*type != 'r')
2829     image->blob->synchronize=image_info->synchronize;
2830   if (image_info->stream != (StreamHandler) NULL)
2831     {
2832       image->blob->stream=image_info->stream;
2833       if (*type == 'w')
2834         {
2835           image->blob->type=FifoStream;
2836           return(MagickTrue);
2837         }
2838     }
2839   /*
2840     Open image file.
2841   */
2842   *filename='\0';
2843   (void) CopyMagickString(filename,image->filename,MagickPathExtent);
2844   rights=ReadPolicyRights;
2845   if (*type == 'w')
2846     rights=WritePolicyRights;
2847   if (IsRightsAuthorized(PathPolicyDomain,rights,filename) == MagickFalse)
2848     {
2849       errno=EPERM;
2850       (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
2851         "NotAuthorized","`%s'",filename);
2852       return(MagickFalse);
2853     }
2854   if ((LocaleCompare(filename,"-") == 0) ||
2855       ((*filename == '\0') && (image_info->file == (FILE *) NULL)))
2856     {
2857       image->blob->file_info.file=(*type == 'r') ? stdin : stdout;
2858 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
2859       if (strchr(type,'b') != (char *) NULL)
2860         setmode(fileno(image->blob->file_info.file),_O_BINARY);
2861 #endif
2862       image->blob->type=StandardStream;
2863       image->blob->exempt=MagickTrue;
2864       return(SetStreamBuffering(image_info,image));
2865     }
2866   if (LocaleNCompare(filename,"fd:",3) == 0)
2867     {
2868       char
2869         fileMode[MagickPathExtent];
2870
2871       *fileMode =(*type);
2872       fileMode[1]='\0';
2873       image->blob->file_info.file=fdopen(StringToLong(filename+3),fileMode);
2874 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
2875       if (strchr(type,'b') != (char *) NULL)
2876         setmode(fileno(image->blob->file_info.file),_O_BINARY);
2877 #endif
2878       image->blob->type=StandardStream;
2879       image->blob->exempt=MagickTrue;
2880       return(SetStreamBuffering(image_info,image));
2881     }
2882 #if defined(MAGICKCORE_HAVE_POPEN) && defined(MAGICKCORE_PIPES_SUPPORT)
2883   if (*filename == '|')
2884     {
2885       char
2886         fileMode[MagickPathExtent],
2887         *sanitize_command;
2888
2889       /*
2890         Pipe image to or from a system command.
2891       */
2892 #if defined(SIGPIPE)
2893       if (*type == 'w')
2894         (void) signal(SIGPIPE,SIG_IGN);
2895 #endif
2896       *fileMode =(*type);
2897       fileMode[1]='\0';
2898       sanitize_command=SanitizeString(filename+1);
2899       image->blob->file_info.file=(FILE *) popen_utf8(sanitize_command,
2900         fileMode);
2901       sanitize_command=DestroyString(sanitize_command);
2902       if (image->blob->file_info.file == (FILE *) NULL)
2903         {
2904           ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
2905           return(MagickFalse);
2906         }
2907       image->blob->type=PipeStream;
2908       image->blob->exempt=MagickTrue;
2909       return(SetStreamBuffering(image_info,image));
2910     }
2911 #endif
2912   status=GetPathAttributes(filename,&image->blob->properties);
2913 #if defined(S_ISFIFO)
2914   if ((status != MagickFalse) && S_ISFIFO(image->blob->properties.st_mode))
2915     {
2916       image->blob->file_info.file=(FILE *) fopen_utf8(filename,type);
2917       if (image->blob->file_info.file == (FILE *) NULL)
2918         {
2919           ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
2920           return(MagickFalse);
2921         }
2922       image->blob->type=FileStream;
2923       image->blob->exempt=MagickTrue;
2924       return(SetStreamBuffering(image_info,image));
2925     }
2926 #endif
2927   GetPathComponent(image->filename,ExtensionPath,extension);
2928   if (*type == 'w')
2929     {
2930       (void) CopyMagickString(filename,image->filename,MagickPathExtent);
2931       if ((image_info->adjoin == MagickFalse) ||
2932           (strchr(filename,'%') != (char *) NULL))
2933         {
2934           /*
2935             Form filename for multi-part images.
2936           */
2937           (void) InterpretImageFilename(image_info,image,image->filename,(int)
2938             image->scene,filename,exception);
2939           if ((LocaleCompare(filename,image->filename) == 0) &&
2940               ((GetPreviousImageInList(image) != (Image *) NULL) ||
2941                (GetNextImageInList(image) != (Image *) NULL)))
2942             {
2943               char
2944                 path[MagickPathExtent];
2945
2946               GetPathComponent(image->filename,RootPath,path);
2947               if (*extension == '\0')
2948                 (void) FormatLocaleString(filename,MagickPathExtent,"%s-%.20g",
2949                   path,(double) image->scene);
2950               else
2951                 (void) FormatLocaleString(filename,MagickPathExtent,
2952                   "%s-%.20g.%s",path,(double) image->scene,extension);
2953             }
2954           (void) CopyMagickString(image->filename,filename,MagickPathExtent);
2955 #if defined(macintosh)
2956           SetApplicationType(filename,image_info->magick,'8BIM');
2957 #endif
2958         }
2959     }
2960   if (image_info->file != (FILE *) NULL)
2961     {
2962       image->blob->file_info.file=image_info->file;
2963       image->blob->type=FileStream;
2964       image->blob->exempt=MagickTrue;
2965     }
2966   else
2967     if (*type == 'r')
2968       {
2969         image->blob->file_info.file=(FILE *) fopen_utf8(filename,type);
2970         if (image->blob->file_info.file != (FILE *) NULL)
2971           {
2972             size_t
2973               count;
2974
2975             unsigned char
2976               magick[3];
2977
2978             image->blob->type=FileStream;
2979             (void) SetStreamBuffering(image_info,image);
2980             (void) ResetMagickMemory(magick,0,sizeof(magick));
2981             count=fread(magick,1,sizeof(magick),image->blob->file_info.file);
2982             (void) fseek(image->blob->file_info.file,-((off_t) count),SEEK_CUR);
2983 #if defined(MAGICKCORE_POSIX_SUPPORT)
2984             (void) fflush(image->blob->file_info.file);
2985 #endif
2986             (void) LogMagickEvent(BlobEvent,GetMagickModule(),
2987                "  read %.20g magic header bytes",(double) count);
2988 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2989             if (((int) magick[0] == 0x1F) && ((int) magick[1] == 0x8B) &&
2990                 ((int) magick[2] == 0x08))
2991               {
2992                 if (image->blob->file_info.file != (FILE *) NULL)
2993                   (void) fclose(image->blob->file_info.file);
2994                 image->blob->file_info.file=(FILE *) NULL;
2995                 image->blob->file_info.gzfile=gzopen(filename,type);
2996                 if (image->blob->file_info.gzfile != (gzFile) NULL)
2997                   image->blob->type=ZipStream;
2998                }
2999 #endif
3000 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3001             if (strncmp((char *) magick,"BZh",3) == 0)
3002               {
3003                 if (image->blob->file_info.file != (FILE *) NULL)
3004                   (void) fclose(image->blob->file_info.file);
3005                 image->blob->file_info.file=(FILE *) NULL;
3006                 image->blob->file_info.bzfile=BZ2_bzopen(filename,type);
3007                 if (image->blob->file_info.bzfile != (BZFILE *) NULL)
3008                   image->blob->type=BZipStream;
3009               }
3010 #endif
3011             if (image->blob->type == FileStream)
3012               {
3013                 const MagickInfo
3014                   *magick_info;
3015
3016                 ExceptionInfo
3017                   *sans_exception;
3018
3019                 size_t
3020                   length;
3021
3022                 sans_exception=AcquireExceptionInfo();
3023                 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3024                 sans_exception=DestroyExceptionInfo(sans_exception);
3025                 length=(size_t) image->blob->properties.st_size;
3026                 if ((magick_info != (const MagickInfo *) NULL) &&
3027                     (GetMagickBlobSupport(magick_info) != MagickFalse) &&
3028                     (length > MagickMaxBufferExtent) &&
3029                     (AcquireMagickResource(MapResource,length) != MagickFalse))
3030                   {
3031                     void
3032                       *blob;
3033
3034                     blob=MapBlob(fileno(image->blob->file_info.file),ReadMode,0,
3035                       length);
3036                     if (blob == (void *) NULL)
3037                       RelinquishMagickResource(MapResource,length);
3038                     else
3039                       {
3040                         /*
3041                           Format supports blobs-- use memory-mapped I/O.
3042                         */
3043                         if (image_info->file != (FILE *) NULL)
3044                           image->blob->exempt=MagickFalse;
3045                         else
3046                           {
3047                             (void) fclose(image->blob->file_info.file);
3048                             image->blob->file_info.file=(FILE *) NULL;
3049                           }
3050                         AttachBlob(image->blob,blob,length);
3051                         image->blob->mapped=MagickTrue;
3052                       }
3053                   }
3054               }
3055           }
3056         }
3057       else
3058 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3059         if ((LocaleCompare(extension,"Z") == 0) ||
3060             (LocaleCompare(extension,"gz") == 0) ||
3061             (LocaleCompare(extension,"wmz") == 0) ||
3062             (LocaleCompare(extension,"svgz") == 0))
3063           {
3064             if (mode == WriteBinaryBlobMode)
3065               type="wb";
3066             image->blob->file_info.gzfile=gzopen(filename,type);
3067             if (image->blob->file_info.gzfile != (gzFile) NULL)
3068               image->blob->type=ZipStream;
3069           }
3070         else
3071 #endif
3072 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3073           if (LocaleCompare(extension,"bz2") == 0)
3074             {
3075               image->blob->file_info.bzfile=BZ2_bzopen(filename,type);
3076               if (image->blob->file_info.bzfile != (BZFILE *) NULL)
3077                 image->blob->type=BZipStream;
3078             }
3079           else
3080 #endif
3081             {
3082               image->blob->file_info.file=(FILE *) fopen_utf8(filename,type);
3083               if (image->blob->file_info.file != (FILE *) NULL)
3084                 {
3085                   image->blob->type=FileStream;
3086                   (void) SetStreamBuffering(image_info,image);
3087                 }
3088        }
3089   image->blob->status=MagickFalse;
3090   if (image->blob->type != UndefinedStream)
3091     image->blob->size=GetBlobSize(image);
3092   else
3093     {
3094       ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3095       return(MagickFalse);
3096     }
3097   return(MagickTrue);
3098 }
3099 \f
3100 /*
3101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3102 %                                                                             %
3103 %                                                                             %
3104 %                                                                             %
3105 +   P i n g B l o b                                                           %
3106 %                                                                             %
3107 %                                                                             %
3108 %                                                                             %
3109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3110 %
3111 %  PingBlob() returns all the attributes of an image or image sequence except
3112 %  for the pixels.  It is much faster and consumes far less memory than
3113 %  BlobToImage().  On failure, a NULL image is returned and exception
3114 %  describes the reason for the failure.
3115 %
3116 %  The format of the PingBlob method is:
3117 %
3118 %      Image *PingBlob(const ImageInfo *image_info,const void *blob,
3119 %        const size_t length,ExceptionInfo *exception)
3120 %
3121 %  A description of each parameter follows:
3122 %
3123 %    o image_info: the image info.
3124 %
3125 %    o blob: the address of a character stream in one of the image formats
3126 %      understood by ImageMagick.
3127 %
3128 %    o length: This size_t integer reflects the length in bytes of the blob.
3129 %
3130 %    o exception: return any errors or warnings in this structure.
3131 %
3132 */
3133
3134 #if defined(__cplusplus) || defined(c_plusplus)
3135 extern "C" {
3136 #endif
3137
3138 static size_t PingStream(const Image *magick_unused(image),
3139   const void *magick_unused(pixels),const size_t columns)
3140 {
3141   magick_unreferenced(image);
3142   magick_unreferenced(pixels);
3143   return(columns);
3144 }
3145
3146 #if defined(__cplusplus) || defined(c_plusplus)
3147 }
3148 #endif
3149
3150 MagickExport Image *PingBlob(const ImageInfo *image_info,const void *blob,
3151   const size_t length,ExceptionInfo *exception)
3152 {
3153   Image
3154     *image;
3155
3156   ImageInfo
3157     *ping_info;
3158
3159   assert(image_info != (ImageInfo *) NULL);
3160   assert(image_info->signature == MagickCoreSignature);
3161   if (image_info->debug != MagickFalse)
3162     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3163       image_info->filename);
3164   assert(exception != (ExceptionInfo *) NULL);
3165   if ((blob == (const void *) NULL) || (length == 0))
3166     {
3167       (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
3168         "UnrecognizedImageFormat","`%s'",image_info->magick);
3169       return((Image *) NULL);
3170     }
3171   ping_info=CloneImageInfo(image_info);
3172   ping_info->blob=(void *) AcquireQuantumMemory(length,sizeof(unsigned char));
3173   if (ping_info->blob == (const void *) NULL)
3174     {
3175       (void) ThrowMagickException(exception,GetMagickModule(),
3176         ResourceLimitFatalError,"MemoryAllocationFailed","`%s'","");
3177       return((Image *) NULL);
3178     }
3179   (void) memcpy(ping_info->blob,blob,length);
3180   ping_info->length=length;
3181   ping_info->ping=MagickTrue;
3182   image=ReadStream(ping_info,&PingStream,exception);
3183   ping_info->blob=(void *) RelinquishMagickMemory(ping_info->blob);
3184   ping_info=DestroyImageInfo(ping_info);
3185   return(image);
3186 }
3187 \f
3188 /*
3189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3190 %                                                                             %
3191 %                                                                             %
3192 %                                                                             %
3193 +  R e a d B l o b                                                            %
3194 %                                                                             %
3195 %                                                                             %
3196 %                                                                             %
3197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3198 %
3199 %  ReadBlob() reads data from the blob or image file and returns it.  It
3200 %  returns the number of bytes read. If length is zero, ReadBlob() returns
3201 %  zero and has no other results. If length is greater than SSIZE_MAX, the
3202 %  result is unspecified.
3203 %
3204 %  The format of the ReadBlob method is:
3205 %
3206 %      ssize_t ReadBlob(Image *image,const size_t length,void *data)
3207 %
3208 %  A description of each parameter follows:
3209 %
3210 %    o image: the image.
3211 %
3212 %    o length:  Specifies an integer representing the number of bytes to read
3213 %      from the file.
3214 %
3215 %    o data:  Specifies an area to place the information requested from the
3216 %      file.
3217 %
3218 */
3219 MagickExport ssize_t ReadBlob(Image *image,const size_t length,void *data)
3220 {
3221   int
3222     c;
3223
3224   register unsigned char
3225     *q;
3226
3227   ssize_t
3228     count;
3229
3230   assert(image != (Image *) NULL);
3231   assert(image->signature == MagickCoreSignature);
3232   assert(image->blob != (BlobInfo *) NULL);
3233   assert(image->blob->type != UndefinedStream);
3234   if (length == 0)
3235     return(0);
3236   assert(data != (void *) NULL);
3237   count=0;
3238   q=(unsigned char *) data;
3239   switch (image->blob->type)
3240   {
3241     case UndefinedStream:
3242       break;
3243     case StandardStream:
3244     case FileStream:
3245     case PipeStream:
3246     {
3247       switch (length)
3248       {
3249         default:
3250         {
3251           count=(ssize_t) fread(q,1,length,image->blob->file_info.file);
3252           break;
3253         }
3254         case 4:
3255         {
3256           c=getc(image->blob->file_info.file);
3257           if (c == EOF)
3258             break;
3259           *q++=(unsigned char) c;
3260           count++;
3261         }
3262         case 3:
3263         {
3264           c=getc(image->blob->file_info.file);
3265           if (c == EOF)
3266             break;
3267           *q++=(unsigned char) c;
3268           count++;
3269         }
3270         case 2:
3271         {
3272           c=getc(image->blob->file_info.file);
3273           if (c == EOF)
3274             break;
3275           *q++=(unsigned char) c;
3276           count++;
3277         }
3278         case 1:
3279         {
3280           c=getc(image->blob->file_info.file);
3281           if (c == EOF)
3282             break;
3283           *q++=(unsigned char) c;
3284           count++;
3285         }
3286         case 0:
3287           break;
3288       }
3289       break;
3290     }
3291     case ZipStream:
3292     {
3293 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3294       switch (length)
3295       {
3296         default:
3297         {
3298           count=(ssize_t) gzread(image->blob->file_info.gzfile,q,
3299             (unsigned int) length);
3300           break;
3301         }
3302         case 4:
3303         {
3304           c=gzgetc(image->blob->file_info.gzfile);
3305           if (c == EOF)
3306             break;
3307           *q++=(unsigned char) c;
3308           count++;
3309         }
3310         case 3:
3311         {
3312           c=gzgetc(image->blob->file_info.gzfile);
3313           if (c == EOF)
3314             break;
3315           *q++=(unsigned char) c;
3316           count++;
3317         }
3318         case 2:
3319         {
3320           c=gzgetc(image->blob->file_info.gzfile);
3321           if (c == EOF)
3322             break;
3323           *q++=(unsigned char) c;
3324           count++;
3325         }
3326         case 1:
3327         {
3328           c=gzgetc(image->blob->file_info.gzfile);
3329           if (c == EOF)
3330             break;
3331           *q++=(unsigned char) c;
3332           count++;
3333         }
3334         case 0:
3335           break;
3336       }
3337 #endif
3338       break;
3339     }
3340     case BZipStream:
3341     {
3342 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3343       count=(ssize_t) BZ2_bzread(image->blob->file_info.bzfile,q,(int) length);
3344 #endif
3345       break;
3346     }
3347     case FifoStream:
3348       break;
3349     case BlobStream:
3350     {
3351       register const unsigned char
3352         *p;
3353
3354       if (image->blob->offset >= (MagickOffsetType) image->blob->length)
3355         {
3356           image->blob->eof=MagickTrue;
3357           break;
3358         }
3359       p=image->blob->data+image->blob->offset;
3360       count=(ssize_t) MagickMin(length,image->blob->length-image->blob->offset);
3361       image->blob->offset+=count;
3362       if (count != (ssize_t) length)
3363         image->blob->eof=MagickTrue;
3364       (void) memcpy(q,p,(size_t) count);
3365       break;
3366     }
3367     case CustomStream:
3368     {
3369       count=image->blob->custom_stream->reader(q,length,
3370         image->blob->custom_stream->data);
3371       break;
3372     }
3373   }
3374   return(count);
3375 }
3376 \f
3377 /*
3378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3379 %                                                                             %
3380 %                                                                             %
3381 %                                                                             %
3382 +  R e a d B l o b B y t e                                                    %
3383 %                                                                             %
3384 %                                                                             %
3385 %                                                                             %
3386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3387 %
3388 %  ReadBlobByte() reads a single byte from the image file and returns it.
3389 %
3390 %  The format of the ReadBlobByte method is:
3391 %
3392 %      int ReadBlobByte(Image *image)
3393 %
3394 %  A description of each parameter follows.
3395 %
3396 %    o image: the image.
3397 %
3398 */
3399 MagickExport int ReadBlobByte(Image *image)
3400 {
3401   register const unsigned char
3402     *p;
3403
3404   ssize_t
3405     count;
3406
3407   unsigned char
3408     buffer[1];
3409
3410   assert(image != (Image *) NULL);
3411   assert(image->signature == MagickCoreSignature);
3412   p=(const unsigned char *) ReadBlobStream(image,1,buffer,&count);
3413   if (count != 1)
3414     return(EOF);
3415   return((int) (*p));
3416 }
3417 \f
3418 /*
3419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3420 %                                                                             %
3421 %                                                                             %
3422 %                                                                             %
3423 +  R e a d B l o b D o u b l e                                                %
3424 %                                                                             %
3425 %                                                                             %
3426 %                                                                             %
3427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3428 %
3429 %  ReadBlobDouble() reads a double value as a 64-bit quantity in the byte-order
3430 %  specified by the endian member of the image structure.
3431 %
3432 %  The format of the ReadBlobDouble method is:
3433 %
3434 %      double ReadBlobDouble(Image *image)
3435 %
3436 %  A description of each parameter follows.
3437 %
3438 %    o image: the image.
3439 %
3440 */
3441 MagickExport double ReadBlobDouble(Image *image)
3442 {
3443   union
3444   {
3445     MagickSizeType
3446       unsigned_value;
3447
3448     double
3449       double_value;
3450   } quantum;
3451
3452   quantum.double_value=0.0;
3453   quantum.unsigned_value=ReadBlobLongLong(image);
3454   return(quantum.double_value);
3455 }
3456 \f
3457 /*
3458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3459 %                                                                             %
3460 %                                                                             %
3461 %                                                                             %
3462 +  R e a d B l o b F l o a t                                                  %
3463 %                                                                             %
3464 %                                                                             %
3465 %                                                                             %
3466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3467 %
3468 %  ReadBlobFloat() reads a float value as a 32-bit quantity in the byte-order
3469 %  specified by the endian member of the image structure.
3470 %
3471 %  The format of the ReadBlobFloat method is:
3472 %
3473 %      float ReadBlobFloat(Image *image)
3474 %
3475 %  A description of each parameter follows.
3476 %
3477 %    o image: the image.
3478 %
3479 */
3480 MagickExport float ReadBlobFloat(Image *image)
3481 {
3482   union
3483   {
3484     unsigned int
3485       unsigned_value;
3486
3487     float
3488       float_value;
3489   } quantum;
3490
3491   quantum.float_value=0.0;
3492   quantum.unsigned_value=ReadBlobLong(image);
3493   return(quantum.float_value);
3494 }
3495 \f
3496 /*
3497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3498 %                                                                             %
3499 %                                                                             %
3500 %                                                                             %
3501 +  R e a d B l o b L o n g                                                    %
3502 %                                                                             %
3503 %                                                                             %
3504 %                                                                             %
3505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3506 %
3507 %  ReadBlobLong() reads a unsigned int value as a 32-bit quantity in the
3508 %  byte-order specified by the endian member of the image structure.
3509 %
3510 %  The format of the ReadBlobLong method is:
3511 %
3512 %      unsigned int ReadBlobLong(Image *image)
3513 %
3514 %  A description of each parameter follows.
3515 %
3516 %    o image: the image.
3517 %
3518 */
3519 MagickExport unsigned int ReadBlobLong(Image *image)
3520 {
3521   register const unsigned char
3522     *p;
3523
3524   ssize_t
3525     count;
3526
3527   unsigned char
3528     buffer[4];
3529
3530   unsigned int
3531     value;
3532
3533   assert(image != (Image *) NULL);
3534   assert(image->signature == MagickCoreSignature);
3535   *buffer='\0';
3536   p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
3537   if (count != 4)
3538     return(0UL);
3539   if (image->endian == LSBEndian)
3540     {
3541       value=(unsigned int) (*p++);
3542       value|=(unsigned int) (*p++) << 8;
3543       value|=(unsigned int) (*p++) << 16;
3544       value|=(unsigned int) (*p++) << 24;
3545       return(value & 0xffffffff);
3546     }
3547   value=(unsigned int) (*p++) << 24;
3548   value|=(unsigned int) (*p++) << 16;
3549   value|=(unsigned int) (*p++) << 8;
3550   value|=(unsigned int) (*p++);
3551   return(value & 0xffffffff);
3552 }
3553 \f
3554 /*
3555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3556 %                                                                             %
3557 %                                                                             %
3558 %                                                                             %
3559 +  R e a d B l o b L o n g L o n g                                            %
3560 %                                                                             %
3561 %                                                                             %
3562 %                                                                             %
3563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3564 %
3565 %  ReadBlobLongLong() reads a long long value as a 64-bit quantity in the
3566 %  byte-order specified by the endian member of the image structure.
3567 %
3568 %  The format of the ReadBlobLongLong method is:
3569 %
3570 %      MagickSizeType ReadBlobLongLong(Image *image)
3571 %
3572 %  A description of each parameter follows.
3573 %
3574 %    o image: the image.
3575 %
3576 */
3577 MagickExport MagickSizeType ReadBlobLongLong(Image *image)
3578 {
3579   MagickSizeType
3580     value;
3581
3582   register const unsigned char
3583     *p;
3584
3585   ssize_t
3586     count;
3587
3588   unsigned char
3589     buffer[8];
3590
3591   assert(image != (Image *) NULL);
3592   assert(image->signature == MagickCoreSignature);
3593   *buffer='\0';
3594   p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
3595   if (count != 8)
3596     return(MagickULLConstant(0));
3597   if (image->endian == LSBEndian)
3598     {
3599       value=(MagickSizeType) (*p++);
3600       value|=(MagickSizeType) (*p++) << 8;
3601       value|=(MagickSizeType) (*p++) << 16;
3602       value|=(MagickSizeType) (*p++) << 24;
3603       value|=(MagickSizeType) (*p++) << 32;
3604       value|=(MagickSizeType) (*p++) << 40;
3605       value|=(MagickSizeType) (*p++) << 48;
3606       value|=(MagickSizeType) (*p++) << 56;
3607       return(value & MagickULLConstant(0xffffffffffffffff));
3608     }
3609   value=(MagickSizeType) (*p++) << 56;
3610   value|=(MagickSizeType) (*p++) << 48;
3611   value|=(MagickSizeType) (*p++) << 40;
3612   value|=(MagickSizeType) (*p++) << 32;
3613   value|=(MagickSizeType) (*p++) << 24;
3614   value|=(MagickSizeType) (*p++) << 16;
3615   value|=(MagickSizeType) (*p++) << 8;
3616   value|=(MagickSizeType) (*p++);
3617   return(value & MagickULLConstant(0xffffffffffffffff));
3618 }
3619 \f
3620 /*
3621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3622 %                                                                             %
3623 %                                                                             %
3624 %                                                                             %
3625 +  R e a d B l o b S h o r t                                                  %
3626 %                                                                             %
3627 %                                                                             %
3628 %                                                                             %
3629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3630 %
3631 %  ReadBlobShort() reads a short value as a 16-bit quantity in the byte-order
3632 %  specified by the endian member of the image structure.
3633 %
3634 %  The format of the ReadBlobShort method is:
3635 %
3636 %      unsigned short ReadBlobShort(Image *image)
3637 %
3638 %  A description of each parameter follows.
3639 %
3640 %    o image: the image.
3641 %
3642 */
3643 MagickExport unsigned short ReadBlobShort(Image *image)
3644 {
3645   register const unsigned char
3646     *p;
3647
3648   register unsigned short
3649     value;
3650
3651   ssize_t
3652     count;
3653
3654   unsigned char
3655     buffer[2];
3656
3657   assert(image != (Image *) NULL);
3658   assert(image->signature == MagickCoreSignature);
3659   *buffer='\0';
3660   p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
3661   if (count != 2)
3662     return((unsigned short) 0U);
3663   if (image->endian == LSBEndian)
3664     {
3665       value=(unsigned short) (*p++);
3666       value|=(unsigned short) (*p++) << 8;
3667       return(value);
3668     }
3669   value=(unsigned short) (*p++) << 8;
3670   value|=(unsigned short) (*p++);
3671   return(value);
3672 }
3673 \f
3674 /*
3675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3676 %                                                                             %
3677 %                                                                             %
3678 %                                                                             %
3679 +  R e a d B l o b L S B L o n g                                              %
3680 %                                                                             %
3681 %                                                                             %
3682 %                                                                             %
3683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3684 %
3685 %  ReadBlobLSBLong() reads a unsigned int value as a 32-bit quantity in
3686 %  least-significant byte first order.
3687 %
3688 %  The format of the ReadBlobLSBLong method is:
3689 %
3690 %      unsigned int ReadBlobLSBLong(Image *image)
3691 %
3692 %  A description of each parameter follows.
3693 %
3694 %    o image: the image.
3695 %
3696 */
3697 MagickExport unsigned int ReadBlobLSBLong(Image *image)
3698 {
3699   register const unsigned char
3700     *p;
3701
3702   register unsigned int
3703     value;
3704
3705   ssize_t
3706     count;
3707
3708   unsigned char
3709     buffer[4];
3710
3711   assert(image != (Image *) NULL);
3712   assert(image->signature == MagickCoreSignature);
3713   *buffer='\0';
3714   p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
3715   if (count != 4)
3716     return(0U);
3717   value=(unsigned int) (*p++);
3718   value|=(unsigned int) (*p++) << 8;
3719   value|=(unsigned int) (*p++) << 16;
3720   value|=(unsigned int) (*p++) << 24;
3721   return(value & 0xffffffff);
3722 }
3723 \f
3724 /*
3725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3726 %                                                                             %
3727 %                                                                             %
3728 %                                                                             %
3729 +  R e a d B l o b L S B S i g n e d L o n g                                  %
3730 %                                                                             %
3731 %                                                                             %
3732 %                                                                             %
3733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3734 %
3735 %  ReadBlobLSBSignedLong() reads a signed int value as a 32-bit quantity in
3736 %  least-significant byte first order.
3737 %
3738 %  The format of the ReadBlobLSBSignedLong method is:
3739 %
3740 %      signed int ReadBlobLSBSignedLong(Image *image)
3741 %
3742 %  A description of each parameter follows.
3743 %
3744 %    o image: the image.
3745 %
3746 */
3747 MagickExport signed int ReadBlobLSBSignedLong(Image *image)
3748 {
3749   union
3750   {
3751     unsigned int
3752       unsigned_value;
3753
3754     signed int
3755       signed_value;
3756   } quantum;
3757
3758   quantum.unsigned_value=ReadBlobLSBLong(image);
3759   return(quantum.signed_value);
3760 }
3761 \f
3762 /*
3763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764 %                                                                             %
3765 %                                                                             %
3766 %                                                                             %
3767 +  R e a d B l o b L S B S h o r t                                            %
3768 %                                                                             %
3769 %                                                                             %
3770 %                                                                             %
3771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3772 %
3773 %  ReadBlobLSBShort() reads a short value as a 16-bit quantity in
3774 %  least-significant byte first order.
3775 %
3776 %  The format of the ReadBlobLSBShort method is:
3777 %
3778 %      unsigned short ReadBlobLSBShort(Image *image)
3779 %
3780 %  A description of each parameter follows.
3781 %
3782 %    o image: the image.
3783 %
3784 */
3785 MagickExport unsigned short ReadBlobLSBShort(Image *image)
3786 {
3787   register const unsigned char
3788     *p;
3789
3790   register unsigned short
3791     value;
3792
3793   ssize_t
3794     count;
3795
3796   unsigned char
3797     buffer[2];
3798
3799   assert(image != (Image *) NULL);
3800   assert(image->signature == MagickCoreSignature);
3801   *buffer='\0';
3802   p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
3803   if (count != 2)
3804     return((unsigned short) 0U);
3805   value=(unsigned int) (*p++);
3806   value|=(unsigned int) (*p++) << 8;
3807   return(value & 0xffff);
3808 }
3809 \f
3810 /*
3811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3812 %                                                                             %
3813 %                                                                             %
3814 %                                                                             %
3815 +  R e a d B l o b L S B S i g n e d S h o r t                                %
3816 %                                                                             %
3817 %                                                                             %
3818 %                                                                             %
3819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3820 %
3821 %  ReadBlobLSBSignedShort() reads a signed short value as a 16-bit quantity in
3822 %  least-significant byte-order.
3823 %
3824 %  The format of the ReadBlobLSBSignedShort method is:
3825 %
3826 %      signed short ReadBlobLSBSignedShort(Image *image)
3827 %
3828 %  A description of each parameter follows.
3829 %
3830 %    o image: the image.
3831 %
3832 */
3833 MagickExport signed short ReadBlobLSBSignedShort(Image *image)
3834 {
3835   union
3836   {
3837     unsigned short
3838       unsigned_value;
3839
3840     signed short
3841       signed_value;
3842   } quantum;
3843
3844   quantum.unsigned_value=ReadBlobLSBShort(image);
3845   return(quantum.signed_value);
3846 }
3847 \f
3848 /*
3849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3850 %                                                                             %
3851 %                                                                             %
3852 %                                                                             %
3853 +  R e a d B l o b M S B L o n g                                              %
3854 %                                                                             %
3855 %                                                                             %
3856 %                                                                             %
3857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3858 %
3859 %  ReadBlobMSBLong() reads a unsigned int value as a 32-bit quantity in
3860 %  most-significant byte first order.
3861 %
3862 %  The format of the ReadBlobMSBLong method is:
3863 %
3864 %      unsigned int ReadBlobMSBLong(Image *image)
3865 %
3866 %  A description of each parameter follows.
3867 %
3868 %    o image: the image.
3869 %
3870 */
3871 MagickExport unsigned int ReadBlobMSBLong(Image *image)
3872 {
3873   register const unsigned char
3874     *p;
3875
3876   register unsigned int
3877     value;
3878
3879   ssize_t
3880     count;
3881
3882   unsigned char
3883     buffer[4];
3884
3885   assert(image != (Image *) NULL);
3886   assert(image->signature == MagickCoreSignature);
3887   *buffer='\0';
3888   p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
3889   if (count != 4)
3890     return(0UL);
3891   value=(unsigned int) (*p++) << 24;
3892   value|=(unsigned int) (*p++) << 16;
3893   value|=(unsigned int) (*p++) << 8;
3894   value|=(unsigned int) (*p++);
3895   return(value);
3896 }
3897 \f
3898 /*
3899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3900 %                                                                             %
3901 %                                                                             %
3902 %                                                                             %
3903 +  R e a d B l o b M S B L o n g L o n g                                      %
3904 %                                                                             %
3905 %                                                                             %
3906 %                                                                             %
3907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3908 %
3909 %  ReadBlobMSBLongLong() reads a unsigned long long value as a 64-bit quantity
3910 %  in most-significant byte first order.
3911 %
3912 %  The format of the ReadBlobMSBLongLong method is:
3913 %
3914 %      unsigned int ReadBlobMSBLongLong(Image *image)
3915 %
3916 %  A description of each parameter follows.
3917 %
3918 %    o image: the image.
3919 %
3920 */
3921 MagickExport MagickSizeType ReadBlobMSBLongLong(Image *image)
3922 {
3923   register const unsigned char
3924     *p;
3925
3926   register MagickSizeType
3927     value;
3928
3929   ssize_t
3930     count;
3931
3932   unsigned char
3933     buffer[8];
3934
3935   assert(image != (Image *) NULL);
3936   assert(image->signature == MagickCoreSignature);
3937   *buffer='\0';
3938   p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
3939   if (count != 8)
3940     return(MagickULLConstant(0));
3941   value=(MagickSizeType) (*p++) << 56;
3942   value|=(MagickSizeType) (*p++) << 48;
3943   value|=(MagickSizeType) (*p++) << 40;
3944   value|=(MagickSizeType) (*p++) << 32;
3945   value|=(MagickSizeType) (*p++) << 24;
3946   value|=(MagickSizeType) (*p++) << 16;
3947   value|=(MagickSizeType) (*p++) << 8;
3948   value|=(MagickSizeType) (*p++);
3949   return(value & MagickULLConstant(0xffffffffffffffff));
3950 }
3951 \f
3952 /*
3953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3954 %                                                                             %
3955 %                                                                             %
3956 %                                                                             %
3957 +  R e a d B l o b M S B S h o r t                                            %
3958 %                                                                             %
3959 %                                                                             %
3960 %                                                                             %
3961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3962 %
3963 %  ReadBlobMSBShort() reads a short value as a 16-bit quantity in
3964 %  most-significant byte first order.
3965 %
3966 %  The format of the ReadBlobMSBShort method is:
3967 %
3968 %      unsigned short ReadBlobMSBShort(Image *image)
3969 %
3970 %  A description of each parameter follows.
3971 %
3972 %    o image: the image.
3973 %
3974 */
3975 MagickExport unsigned short ReadBlobMSBShort(Image *image)
3976 {
3977   register const unsigned char
3978     *p;
3979
3980   register unsigned short
3981     value;
3982
3983   ssize_t
3984     count;
3985
3986   unsigned char
3987     buffer[2];
3988
3989   assert(image != (Image *) NULL);
3990   assert(image->signature == MagickCoreSignature);
3991   *buffer='\0';
3992   p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
3993   if (count != 2)
3994     return((unsigned short) 0U);
3995   value=(unsigned short) (*p++) << 8;
3996   value|=(unsigned short) (*p++);
3997   return(value & 0xffff);
3998 }
3999 \f
4000 /*
4001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4002 %                                                                             %
4003 %                                                                             %
4004 %                                                                             %
4005 +  R e a d B l o b M S B S i g n e d L o n g                                  %
4006 %                                                                             %
4007 %                                                                             %
4008 %                                                                             %
4009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4010 %
4011 %  ReadBlobMSBSignedLong() reads a signed int value as a 32-bit quantity in
4012 %  most-significant byte-order.
4013 %
4014 %  The format of the ReadBlobMSBSignedLong method is:
4015 %
4016 %      signed int ReadBlobMSBSignedLong(Image *image)
4017 %
4018 %  A description of each parameter follows.
4019 %
4020 %    o image: the image.
4021 %
4022 */
4023 MagickExport signed int ReadBlobMSBSignedLong(Image *image)
4024 {
4025   union
4026   {
4027     unsigned int
4028       unsigned_value;
4029
4030     signed int
4031       signed_value;
4032   } quantum;
4033
4034   quantum.unsigned_value=ReadBlobMSBLong(image);
4035   return(quantum.signed_value);
4036 }
4037 \f
4038 /*
4039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4040 %                                                                             %
4041 %                                                                             %
4042 %                                                                             %
4043 +  R e a d B l o b M S B S i g n e d S h o r t                                %
4044 %                                                                             %
4045 %                                                                             %
4046 %                                                                             %
4047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4048 %
4049 %  ReadBlobMSBSignedShort() reads a signed short value as a 16-bit quantity in
4050 %  most-significant byte-order.
4051 %
4052 %  The format of the ReadBlobMSBSignedShort method is:
4053 %
4054 %      signed short ReadBlobMSBSignedShort(Image *image)
4055 %
4056 %  A description of each parameter follows.
4057 %
4058 %    o image: the image.
4059 %
4060 */
4061 MagickExport signed short ReadBlobMSBSignedShort(Image *image)
4062 {
4063   union
4064   {
4065     unsigned short
4066       unsigned_value;
4067
4068     signed short
4069       signed_value;
4070   } quantum;
4071
4072   quantum.unsigned_value=ReadBlobMSBShort(image);
4073   return(quantum.signed_value);
4074 }
4075 \f
4076 /*
4077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4078 %                                                                             %
4079 %                                                                             %
4080 %                                                                             %
4081 +  R e a d B l o b S i g n e d L o n g                                        %
4082 %                                                                             %
4083 %                                                                             %
4084 %                                                                             %
4085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4086 %
4087 %  ReadBlobSignedLong() reads a signed int value as a 32-bit quantity in the
4088 %  byte-order specified by the endian member of the image structure.
4089 %
4090 %  The format of the ReadBlobSignedLong method is:
4091 %
4092 %      signed int ReadBlobSignedLong(Image *image)
4093 %
4094 %  A description of each parameter follows.
4095 %
4096 %    o image: the image.
4097 %
4098 */
4099 MagickExport signed int ReadBlobSignedLong(Image *image)
4100 {
4101   union
4102   {
4103     unsigned int
4104       unsigned_value;
4105
4106     signed int
4107       signed_value;
4108   } quantum;
4109
4110   quantum.unsigned_value=ReadBlobLong(image);
4111   return(quantum.signed_value);
4112 }
4113 \f
4114 /*
4115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4116 %                                                                             %
4117 %                                                                             %
4118 %                                                                             %
4119 +  R e a d B l o b S i g n e d S h o r t                                      %
4120 %                                                                             %
4121 %                                                                             %
4122 %                                                                             %
4123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4124 %
4125 %  ReadBlobSignedShort() reads a signed short value as a 16-bit quantity in the
4126 %  byte-order specified by the endian member of the image structure.
4127 %
4128 %  The format of the ReadBlobSignedShort method is:
4129 %
4130 %      signed short ReadBlobSignedShort(Image *image)
4131 %
4132 %  A description of each parameter follows.
4133 %
4134 %    o image: the image.
4135 %
4136 */
4137 MagickExport signed short ReadBlobSignedShort(Image *image)
4138 {
4139   union
4140   {
4141     unsigned short
4142       unsigned_value;
4143
4144     signed short
4145       signed_value;
4146   } quantum;
4147
4148   quantum.unsigned_value=ReadBlobShort(image);
4149   return(quantum.signed_value);
4150 }
4151 \f
4152 /*
4153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4154 %                                                                             %
4155 %                                                                             %
4156 %                                                                             %
4157 +  R e a d B l o b S t r e a m                                                %
4158 %                                                                             %
4159 %                                                                             %
4160 %                                                                             %
4161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4162 %
4163 %  ReadBlobStream() reads data from the blob or image file and returns it.  It
4164 %  returns a pointer to the data buffer you supply or to the image memory
4165 %  buffer if its supported (zero-copy). If length is zero, ReadBlobStream()
4166 %  returns a count of zero and has no other results. If length is greater than
4167 %  SSIZE_MAX, the result is unspecified.
4168 %
4169 %  The format of the ReadBlobStream method is:
4170 %
4171 %      const void *ReadBlobStream(Image *image,const size_t length,void *data,
4172 %        ssize_t *count)
4173 %
4174 %  A description of each parameter follows:
4175 %
4176 %    o image: the image.
4177 %
4178 %    o length:  Specifies an integer representing the number of bytes to read
4179 %      from the file.
4180 %
4181 %    o count: returns the number of bytes read.
4182 %
4183 %    o data:  Specifies an area to place the information requested from the
4184 %      file.
4185 %
4186 */
4187 MagickExport const void *ReadBlobStream(Image *image,const size_t length,
4188   void *data,ssize_t *count)
4189 {
4190   assert(image != (Image *) NULL);
4191   assert(image->signature == MagickCoreSignature);
4192   assert(image->blob != (BlobInfo *) NULL);
4193   assert(image->blob->type != UndefinedStream);
4194   assert(count != (ssize_t *) NULL);
4195   if (image->blob->type != BlobStream)
4196     {
4197       assert(data != NULL);
4198       *count=ReadBlob(image,length,(unsigned char *) data);
4199       return(data);
4200     }
4201   if (image->blob->offset >= (MagickOffsetType) image->blob->length)
4202     {
4203       *count=0;
4204       image->blob->eof=MagickTrue;
4205       return(data);
4206     }
4207   data=image->blob->data+image->blob->offset;
4208   *count=(ssize_t) MagickMin(length,image->blob->length-image->blob->offset);
4209   image->blob->offset+=(*count);
4210   if (*count != (ssize_t) length)
4211     image->blob->eof=MagickTrue;
4212   return(data);
4213 }
4214 \f
4215 /*
4216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4217 %                                                                             %
4218 %                                                                             %
4219 %                                                                             %
4220 +   R e a d B l o b S t r i n g                                               %
4221 %                                                                             %
4222 %                                                                             %
4223 %                                                                             %
4224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4225 %
4226 %  ReadBlobString() reads characters from a blob or file until a newline
4227 %  character is read or an end-of-file condition is encountered.
4228 %
4229 %  The format of the ReadBlobString method is:
4230 %
4231 %      char *ReadBlobString(Image *image,char *string)
4232 %
4233 %  A description of each parameter follows:
4234 %
4235 %    o image: the image.
4236 %
4237 %    o string: the address of a character buffer.
4238 %
4239 */
4240 MagickExport char *ReadBlobString(Image *image,char *string)
4241 {
4242   register const unsigned char
4243     *p;
4244
4245   register ssize_t
4246     i;
4247
4248   ssize_t
4249     count;
4250
4251   unsigned char
4252     buffer[1];
4253
4254   assert(image != (Image *) NULL);
4255   assert(image->signature == MagickCoreSignature);
4256   for (i=0; i < (MagickPathExtent-1L); i++)
4257   {
4258     p=(const unsigned char *) ReadBlobStream(image,1,buffer,&count);
4259     if (count != 1)
4260       {
4261         if (i == 0)
4262           return((char *) NULL);
4263         break;
4264       }
4265     string[i]=(char) (*p);
4266     if ((string[i] == '\r') || (string[i] == '\n'))
4267       break;
4268   }
4269   if (string[i] == '\r')
4270     (void) ReadBlobStream(image,1,buffer,&count);
4271   string[i]='\0';
4272   return(string);
4273 }
4274 \f
4275 /*
4276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4277 %                                                                             %
4278 %                                                                             %
4279 %                                                                             %
4280 +   R e f e r e n c e B l o b                                                 %
4281 %                                                                             %
4282 %                                                                             %
4283 %                                                                             %
4284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4285 %
4286 %  ReferenceBlob() increments the reference count associated with the pixel
4287 %  blob returning a pointer to the blob.
4288 %
4289 %  The format of the ReferenceBlob method is:
4290 %
4291 %      BlobInfo ReferenceBlob(BlobInfo *blob_info)
4292 %
4293 %  A description of each parameter follows:
4294 %
4295 %    o blob_info: the blob_info.
4296 %
4297 */
4298 MagickExport BlobInfo *ReferenceBlob(BlobInfo *blob)
4299 {
4300   assert(blob != (BlobInfo *) NULL);
4301   assert(blob->signature == MagickCoreSignature);
4302   if (blob->debug != MagickFalse)
4303     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4304   LockSemaphoreInfo(blob->semaphore);
4305   blob->reference_count++;
4306   UnlockSemaphoreInfo(blob->semaphore);
4307   return(blob);
4308 }
4309 \f
4310 /*
4311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4312 %                                                                             %
4313 %                                                                             %
4314 %                                                                             %
4315 +  S e e k B l o b                                                            %
4316 %                                                                             %
4317 %                                                                             %
4318 %                                                                             %
4319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4320 %
4321 %  SeekBlob() sets the offset in bytes from the beginning of a blob or file
4322 %  and returns the resulting offset.
4323 %
4324 %  The format of the SeekBlob method is:
4325 %
4326 %      MagickOffsetType SeekBlob(Image *image,const MagickOffsetType offset,
4327 %        const int whence)
4328 %
4329 %  A description of each parameter follows:
4330 %
4331 %    o image: the image.
4332 %
4333 %    o offset:  Specifies an integer representing the offset in bytes.
4334 %
4335 %    o whence:  Specifies an integer representing how the offset is
4336 %      treated relative to the beginning of the blob as follows:
4337 %
4338 %        SEEK_SET  Set position equal to offset bytes.
4339 %        SEEK_CUR  Set position to current location plus offset.
4340 %        SEEK_END  Set position to EOF plus offset.
4341 %
4342 */
4343 MagickExport MagickOffsetType SeekBlob(Image *image,
4344   const MagickOffsetType offset,const int whence)
4345 {
4346   assert(image != (Image *) NULL);
4347   assert(image->signature == MagickCoreSignature);
4348   if (image->debug != MagickFalse)
4349     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4350   assert(image->blob != (BlobInfo *) NULL);
4351   assert(image->blob->type != UndefinedStream);
4352   switch (image->blob->type)
4353   {
4354     case UndefinedStream:
4355       break;
4356     case StandardStream:
4357     case PipeStream:
4358       return(-1);
4359     case FileStream:
4360     {
4361       if ((offset < 0) && (whence == SEEK_SET))
4362         return(-1);
4363       if (fseek(image->blob->file_info.file,offset,whence) < 0)
4364         return(-1);
4365       image->blob->offset=TellBlob(image);
4366       break;
4367     }
4368     case ZipStream:
4369     {
4370 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4371       if (gzseek(image->blob->file_info.gzfile,(off_t) offset,whence) < 0)
4372         return(-1);
4373 #endif
4374       image->blob->offset=TellBlob(image);
4375       break;
4376     }
4377     case BZipStream:
4378       return(-1);
4379     case FifoStream:
4380       return(-1);
4381     case BlobStream:
4382     {
4383       switch (whence)
4384       {
4385         case SEEK_SET:
4386         default:
4387         {
4388           if (offset < 0)
4389             return(-1);
4390           image->blob->offset=offset;
4391           break;
4392         }
4393         case SEEK_CUR:
4394         {
4395           if ((image->blob->offset+offset) < 0)
4396             return(-1);
4397           image->blob->offset+=offset;
4398           break;
4399         }
4400         case SEEK_END:
4401         {
4402           if (((MagickOffsetType) image->blob->length+offset) < 0)
4403             return(-1);
4404           image->blob->offset=image->blob->length+offset;
4405           break;
4406         }
4407       }
4408       if (image->blob->offset < (MagickOffsetType)
4409           ((off_t) image->blob->length))
4410         {
4411           image->blob->eof=MagickFalse;
4412           break;
4413         }
4414       if (image->blob->offset < (MagickOffsetType)
4415           ((off_t) image->blob->extent))
4416         break;
4417       if (image->blob->mapped != MagickFalse)
4418         {
4419           image->blob->eof=MagickTrue;
4420           return(-1);
4421         }
4422       image->blob->extent=(size_t) (image->blob->offset+image->blob->quantum);
4423       image->blob->quantum<<=1;
4424       image->blob->data=(unsigned char *) ResizeQuantumMemory(image->blob->data,
4425         image->blob->extent+1,sizeof(*image->blob->data));
4426       (void) SyncBlob(image);
4427       if (image->blob->data == NULL)
4428         {
4429           (void) DetachBlob(image->blob);
4430           return(-1);
4431         }
4432       break;
4433     }
4434     case CustomStream:
4435     {
4436       if (image->blob->custom_stream->seeker == (CustomStreamSeeker) NULL)
4437         return(-1);
4438       image->blob->offset=image->blob->custom_stream->seeker(offset,whence,
4439         image->blob->custom_stream->data);
4440       break;
4441     }
4442   }
4443   return(image->blob->offset);
4444 }
4445 \f
4446 /*
4447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4448 %                                                                             %
4449 %                                                                             %
4450 %                                                                             %
4451 +   S e t B l o b E x e m p t                                                 %
4452 %                                                                             %
4453 %                                                                             %
4454 %                                                                             %
4455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4456 %
4457 %  SetBlobExempt() sets the blob exempt status.
4458 %
4459 %  The format of the SetBlobExempt method is:
4460 %
4461 %      MagickBooleanType SetBlobExempt(const Image *image,
4462 %        const MagickBooleanType exempt)
4463 %
4464 %  A description of each parameter follows:
4465 %
4466 %    o image: the image.
4467 %
4468 %    o exempt: Set to true if this blob is exempt from being closed.
4469 %
4470 */
4471 MagickExport void SetBlobExempt(Image *image,const MagickBooleanType exempt)
4472 {
4473   assert(image != (const Image *) NULL);
4474   assert(image->signature == MagickCoreSignature);
4475   if (image->debug != MagickFalse)
4476     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4477   image->blob->exempt=exempt;
4478 }
4479 \f
4480 /*
4481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482 %                                                                             %
4483 %                                                                             %
4484 %                                                                             %
4485 +  S e t B l o b E x t e n t                                                  %
4486 %                                                                             %
4487 %                                                                             %
4488 %                                                                             %
4489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4490 %
4491 %  SetBlobExtent() ensures enough space is allocated for the blob.  If the
4492 %  method is successful, subsequent writes to bytes in the specified range are
4493 %  guaranteed not to fail.
4494 %
4495 %  The format of the SetBlobExtent method is:
4496 %
4497 %      MagickBooleanType SetBlobExtent(Image *image,const MagickSizeType extent)
4498 %
4499 %  A description of each parameter follows:
4500 %
4501 %    o image: the image.
4502 %
4503 %    o extent:  the blob maximum extent.
4504 %
4505 */
4506 MagickExport MagickBooleanType SetBlobExtent(Image *image,
4507   const MagickSizeType extent)
4508 {
4509   assert(image != (Image *) NULL);
4510   assert(image->signature == MagickCoreSignature);
4511   if (image->debug != MagickFalse)
4512     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4513   assert(image->blob != (BlobInfo *) NULL);
4514   assert(image->blob->type != UndefinedStream);
4515   switch (image->blob->type)
4516   {
4517     case UndefinedStream:
4518       break;
4519     case StandardStream:
4520       return(MagickFalse);
4521     case FileStream:
4522     {
4523       MagickOffsetType
4524         offset;
4525
4526       ssize_t
4527         count;
4528
4529       if (extent != (MagickSizeType) ((off_t) extent))
4530         return(MagickFalse);
4531       offset=SeekBlob(image,0,SEEK_END);
4532       if (offset < 0)
4533         return(MagickFalse);
4534       if ((MagickSizeType) offset >= extent)
4535         break;
4536       offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
4537       if (offset < 0)
4538         break;
4539       count=(ssize_t) fwrite((const unsigned char *) "",1,1,
4540         image->blob->file_info.file);
4541 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
4542       if (image->blob->synchronize != MagickFalse)
4543         {
4544           int
4545             file;
4546
4547           file=fileno(image->blob->file_info.file);
4548           if ((file == -1) || (offset < 0))
4549             return(MagickFalse);
4550           (void) posix_fallocate(file,offset,extent-offset);
4551         }
4552 #endif
4553       offset=SeekBlob(image,offset,SEEK_SET);
4554       if (count != 1)
4555         return(MagickFalse);
4556       break;
4557     }
4558     case PipeStream:
4559     case ZipStream:
4560       return(MagickFalse);
4561     case BZipStream:
4562       return(MagickFalse);
4563     case FifoStream:
4564       return(MagickFalse);
4565     case BlobStream:
4566     {
4567       if (extent != (MagickSizeType) ((size_t) extent))
4568         return(MagickFalse);
4569       if (image->blob->mapped != MagickFalse)
4570         {
4571           MagickOffsetType
4572             offset;
4573
4574           ssize_t
4575             count;
4576
4577           (void) UnmapBlob(image->blob->data,image->blob->length);
4578           RelinquishMagickResource(MapResource,image->blob->length);
4579           if (extent != (MagickSizeType) ((off_t) extent))
4580             return(MagickFalse);
4581           offset=SeekBlob(image,0,SEEK_END);
4582           if (offset < 0)
4583             return(MagickFalse);
4584           if ((MagickSizeType) offset >= extent)
4585             break;
4586           offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
4587           count=(ssize_t) fwrite((const unsigned char *) "",1,1,
4588             image->blob->file_info.file);
4589 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
4590           if (image->blob->synchronize != MagickFalse)
4591             {
4592               int
4593                 file;
4594
4595               file=fileno(image->blob->file_info.file);
4596               if ((file == -1) || (offset < 0))
4597                 return(MagickFalse);
4598               (void) posix_fallocate(file,offset,extent-offset);
4599             }
4600 #endif
4601           offset=SeekBlob(image,offset,SEEK_SET);
4602           if (count != 1)
4603             return(MagickFalse);
4604           (void) AcquireMagickResource(MapResource,extent);
4605           image->blob->data=(unsigned char*) MapBlob(fileno(
4606             image->blob->file_info.file),WriteMode,0,(size_t) extent);
4607           image->blob->extent=(size_t) extent;
4608           image->blob->length=(size_t) extent;
4609           (void) SyncBlob(image);
4610           break;
4611         }
4612       image->blob->extent=(size_t) extent;
4613       image->blob->data=(unsigned char *) ResizeQuantumMemory(image->blob->data,
4614         image->blob->extent+1,sizeof(*image->blob->data));
4615       (void) SyncBlob(image);
4616       if (image->blob->data == (unsigned char *) NULL)
4617         {
4618           (void) DetachBlob(image->blob);
4619           return(MagickFalse);
4620         }
4621       break;
4622     }
4623     case CustomStream:
4624       break;
4625   }
4626   return(MagickTrue);
4627 }
4628 \f
4629 /*
4630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4631 %                                                                             %
4632 %                                                                             %
4633 %                                                                             %
4634 +  S e t C u s t o m S t r e a m D a t a                                      %
4635 %                                                                             %
4636 %                                                                             %
4637 %                                                                             %
4638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4639 %
4640 %  SetCustomStreamData() sets the stream info data member.
4641 %
4642 %  The format of the SetCustomStreamData method is:
4643 %
4644 %      void SetCustomStreamData(CustomStreamInfo *custom_stream,void *)
4645 %
4646 %  A description of each parameter follows:
4647 %
4648 %    o custom_stream: your custom stream.
4649 %
4650 %    o void: your data.
4651 %
4652 */
4653 MagickExport void SetCustomStreamData(CustomStreamInfo *custom_stream,
4654   void *data)
4655 {
4656   assert(custom_stream != (CustomStreamInfo *) NULL);
4657   assert(custom_stream->signature == MagickCoreSignature);
4658   custom_stream->data=data;
4659 }
4660 \f
4661 /*
4662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4663 %                                                                             %
4664 %                                                                             %
4665 %                                                                             %
4666 +  S e t C u s t o m S t r e a m R e a d e r                                  %
4667 %                                                                             %
4668 %                                                                             %
4669 %                                                                             %
4670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4671 %
4672 %  SetCustomStreamReader() sets the stream info reader member.
4673 %
4674 %  The format of the SetCustomStreamReader method is:
4675 %
4676 %      void SetCustomStreamReader(CustomStreamInfo *custom_stream,
4677 %        CustomStreamHandler reader)
4678 %
4679 %  A description of each parameter follows:
4680 %
4681 %    o custom_stream: your custom stream.
4682 %
4683 %    o reader: your custom stream reader.
4684 %
4685 */
4686 MagickExport void SetCustomStreamReader(CustomStreamInfo *custom_stream,
4687   CustomStreamHandler reader)
4688 {
4689   assert(custom_stream != (CustomStreamInfo *) NULL);
4690   assert(custom_stream->signature == MagickCoreSignature);
4691   custom_stream->reader=reader;
4692 }
4693 \f
4694 /*
4695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4696 %                                                                             %
4697 %                                                                             %
4698 %                                                                             %
4699 +  S e t C u s t o m S t r e a m S e e k e r                                  %
4700 %                                                                             %
4701 %                                                                             %
4702 %                                                                             %
4703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704 %
4705 %  SetCustomStreamSeeker() sets the stream info seeker member.
4706 %
4707 %  The format of the SetCustomStreamReader method is:
4708 %
4709 %      void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
4710 %        CustomStreamSeeker seeker)
4711 %
4712 %  A description of each parameter follows:
4713 %
4714 %    o custom_stream: your custom stream.
4715 %
4716 %    o seeker: your custom stream seeker.
4717 %
4718 */
4719 MagickExport void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
4720   CustomStreamSeeker seeker)
4721 {
4722   assert(custom_stream != (CustomStreamInfo *) NULL);
4723   assert(custom_stream->signature == MagickCoreSignature);
4724   custom_stream->seeker=seeker;
4725 }
4726 \f
4727 /*
4728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4729 %                                                                             %
4730 %                                                                             %
4731 %                                                                             %
4732 +  S e t C u s t o m S t r e a m T e l l e r                                  %
4733 %                                                                             %
4734 %                                                                             %
4735 %                                                                             %
4736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4737 %
4738 %  SetCustomStreamTeller() sets the stream info teller member.
4739 %
4740 %  The format of the SetCustomStreamTeller method is:
4741 %
4742 %      void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
4743 %        CustomStreamTeller *teller)
4744 %
4745 %  A description of each parameter follows:
4746 %
4747 %    o custom_stream: your custom stream.
4748 %
4749 %    o teller: your custom stream teller.
4750 %
4751 */
4752 MagickExport void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
4753   CustomStreamTeller teller)
4754 {
4755   assert(custom_stream != (CustomStreamInfo *) NULL);
4756   assert(custom_stream->signature == MagickCoreSignature);
4757   custom_stream->teller=teller;
4758 }
4759 \f
4760 /*
4761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4762 %                                                                             %
4763 %                                                                             %
4764 %                                                                             %
4765 +  S e t C u s t o m S t r e a m W r i t e r                                  %
4766 %                                                                             %
4767 %                                                                             %
4768 %                                                                             %
4769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4770 %
4771 %  SetCustomStreamWriter() sets the stream info writer member.
4772 %
4773 %  The format of the SetCustomStreamWriter method is:
4774 %
4775 %      void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
4776 %        CustomStreamHandler *writer)
4777 %
4778 %  A description of each parameter follows:
4779 %
4780 %    o custom_stream: your custom stream.
4781 %
4782 %    o writer: your custom stream writer.
4783 %
4784 */
4785 MagickExport void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
4786   CustomStreamHandler writer)
4787 {
4788   assert(custom_stream != (CustomStreamInfo *) NULL);
4789   assert(custom_stream->signature == MagickCoreSignature);
4790   custom_stream->writer=writer;
4791 }
4792 \f
4793 /*
4794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4795 %                                                                             %
4796 %                                                                             %
4797 %                                                                             %
4798 +  S y n c B l o b                                                            %
4799 %                                                                             %
4800 %                                                                             %
4801 %                                                                             %
4802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4803 %
4804 %  SyncBlob() flushes the datastream if it is a file or synchronizes the data
4805 %  attributes if it is an blob.
4806 %
4807 %  The format of the SyncBlob method is:
4808 %
4809 %      int SyncBlob(Image *image)
4810 %
4811 %  A description of each parameter follows:
4812 %
4813 %    o image: the image.
4814 %
4815 */
4816 static int SyncBlob(Image *image)
4817 {
4818   int
4819     status;
4820
4821   assert(image != (Image *) NULL);
4822   assert(image->signature == MagickCoreSignature);
4823   if (image->debug != MagickFalse)
4824     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4825   assert(image->blob != (BlobInfo *) NULL);
4826   assert(image->blob->type != UndefinedStream);
4827   status=0;
4828   switch (image->blob->type)
4829   {
4830     case UndefinedStream:
4831     case StandardStream:
4832       break;
4833     case FileStream:
4834     case PipeStream:
4835     {
4836       status=fflush(image->blob->file_info.file);
4837       break;
4838     }
4839     case ZipStream:
4840     {
4841 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4842       status=gzflush(image->blob->file_info.gzfile,Z_SYNC_FLUSH);
4843 #endif
4844       break;
4845     }
4846     case BZipStream:
4847     {
4848 #if defined(MAGICKCORE_BZLIB_DELEGATE)
4849       status=BZ2_bzflush(image->blob->file_info.bzfile);
4850 #endif
4851       break;
4852     }
4853     case FifoStream:
4854       break;
4855     case BlobStream:
4856       break;
4857     case CustomStream:
4858       break;
4859   }
4860   return(status);
4861 }
4862 \f
4863 /*
4864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865 %                                                                             %
4866 %                                                                             %
4867 %                                                                             %
4868 +  T e l l B l o b                                                            %
4869 %                                                                             %
4870 %                                                                             %
4871 %                                                                             %
4872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4873 %
4874 %  TellBlob() obtains the current value of the blob or file position.
4875 %
4876 %  The format of the TellBlob method is:
4877 %
4878 %      MagickOffsetType TellBlob(const Image *image)
4879 %
4880 %  A description of each parameter follows:
4881 %
4882 %    o image: the image.
4883 %
4884 */
4885 MagickExport MagickOffsetType TellBlob(const Image *image)
4886 {
4887   MagickOffsetType
4888     offset;
4889
4890   assert(image != (Image *) NULL);
4891   assert(image->signature == MagickCoreSignature);
4892   if (image->debug != MagickFalse)
4893     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4894   assert(image->blob != (BlobInfo *) NULL);
4895   assert(image->blob->type != UndefinedStream);
4896   offset=(-1);
4897   switch (image->blob->type)
4898   {
4899     case UndefinedStream:
4900     case StandardStream:
4901       break;
4902     case FileStream:
4903     {
4904       offset=ftell(image->blob->file_info.file);
4905       break;
4906     }
4907     case PipeStream:
4908       break;
4909     case ZipStream:
4910     {
4911 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4912       offset=(MagickOffsetType) gztell(image->blob->file_info.gzfile);
4913 #endif
4914       break;
4915     }
4916     case BZipStream:
4917       break;
4918     case FifoStream:
4919       break;
4920     case BlobStream:
4921     {
4922       offset=image->blob->offset;
4923       break;
4924     }
4925     case CustomStream:
4926     {
4927       if (image->blob->custom_stream->teller != (CustomStreamTeller) NULL)
4928         offset=image->blob->custom_stream->teller(image->blob->custom_stream->data);
4929       break;
4930     }
4931   }
4932   return(offset);
4933 }
4934 \f
4935 /*
4936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4937 %                                                                             %
4938 %                                                                             %
4939 %                                                                             %
4940 +  U n m a p B l o b                                                          %
4941 %                                                                             %
4942 %                                                                             %
4943 %                                                                             %
4944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4945 %
4946 %  UnmapBlob() deallocates the binary large object previously allocated with
4947 %  the MapBlob method.
4948 %
4949 %  The format of the UnmapBlob method is:
4950 %
4951 %       MagickBooleanType UnmapBlob(void *map,const size_t length)
4952 %
4953 %  A description of each parameter follows:
4954 %
4955 %    o map: the address  of the binary large object.
4956 %
4957 %    o length: the length of the binary large object.
4958 %
4959 */
4960 MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
4961 {
4962 #if defined(MAGICKCORE_HAVE_MMAP)
4963   int
4964     status;
4965
4966   status=munmap(map,length);
4967   return(status == -1 ? MagickFalse : MagickTrue);
4968 #else
4969   (void) map;
4970   (void) length;
4971   return(MagickFalse);
4972 #endif
4973 }
4974 \f
4975 /*
4976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4977 %                                                                             %
4978 %                                                                             %
4979 %                                                                             %
4980 %   C u s t o m S t r e a m T o I m a g e                                     %
4981 %                                                                             %
4982 %                                                                             %
4983 %                                                                             %
4984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4985 %
4986 %  CustomStreamToImage() is the equivalent of ReadImage(), but reads the
4987 %  formatted "file" from the suplied method rather than to an actual file.
4988 %
4989 %  The format of the CustomStreamToImage method is:
4990 %
4991 %      Image *CustomStreamToImage(const ImageInfo *image_info,
4992 %         ExceptionInfo *exception)
4993 %
4994 %  A description of each parameter follows:
4995 %
4996 %    o image_info: the image info.
4997 %
4998 %    o exception: return any errors or warnings in this structure.
4999 %
5000 */
5001 MagickExport Image *CustomStreamToImage(const ImageInfo *image_info,
5002   ExceptionInfo *exception)
5003 {
5004   const MagickInfo
5005     *magick_info;
5006
5007   Image
5008     *image;
5009
5010   ImageInfo
5011     *blob_info;
5012
5013   assert(image_info != (ImageInfo *) NULL);
5014   assert(image_info->signature == MagickCoreSignature);
5015   if (image_info->debug != MagickFalse)
5016     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5017       image_info->filename);
5018   assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
5019   assert(image_info->custom_stream->signature == MagickCoreSignature);
5020   assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
5021   assert(exception != (ExceptionInfo *) NULL);
5022   blob_info=CloneImageInfo(image_info);
5023   if (*blob_info->magick == '\0')
5024     (void) SetImageInfo(blob_info,0,exception);
5025   magick_info=GetMagickInfo(blob_info->magick,exception);
5026   if (magick_info == (const MagickInfo *) NULL)
5027     {
5028       (void) ThrowMagickException(exception,GetMagickModule(),
5029         MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
5030         blob_info->magick);
5031       blob_info=DestroyImageInfo(blob_info);
5032       return((Image *) NULL);
5033     }
5034   image=(Image *) NULL;
5035   if ((GetMagickBlobSupport(magick_info) != MagickFalse) ||
5036       (blob_info->custom_stream == (CustomStreamInfo *) NULL))
5037     {
5038       /*
5039         Native blob support for this image format or SetImageInfo changed the
5040         blob to a file.
5041       */
5042       image=ReadImage(blob_info,exception);
5043       if (image != (Image *) NULL)
5044         (void) CloseBlob(image);
5045     }
5046   else
5047     {
5048       char
5049         unique[MagickPathExtent];
5050
5051       int
5052         file;
5053
5054       ImageInfo
5055         *clone_info;
5056
5057       unsigned char
5058         *blob;
5059
5060       /*
5061         Write data to file on disk.
5062       */
5063       blob_info->custom_stream=(CustomStreamInfo *) NULL;
5064       blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
5065         sizeof(*blob));
5066       if (blob == (unsigned char *) NULL)
5067         {
5068           ThrowFileException(exception,BlobError,"UnableToReadBlob",
5069             image_info->filename);
5070           blob_info=DestroyImageInfo(blob_info);
5071           return((Image *) NULL);
5072         }
5073       file=AcquireUniqueFileResource(unique);
5074       if (file == -1)
5075         {
5076           ThrowFileException(exception,BlobError,"UnableToReadBlob",
5077             image_info->filename);
5078           blob=(unsigned char *) RelinquishMagickMemory(blob);
5079           blob_info=DestroyImageInfo(blob_info);
5080           return((Image *) NULL);
5081         }
5082       clone_info=CloneImageInfo(blob_info);
5083       blob_info->file=fdopen(file,"wb+");
5084       if (blob_info->file != (FILE *) NULL)
5085         {
5086           ssize_t
5087             count;
5088
5089           count=(ssize_t) MagickMaxBufferExtent;
5090           while (count == (ssize_t) MagickMaxBufferExtent)
5091           {
5092             count=image_info->custom_stream->reader(blob,MagickMaxBufferExtent,
5093               image_info->custom_stream->data);
5094             count=(ssize_t) write(file,(const char *) blob,count);
5095           }
5096           (void) fclose(blob_info->file);
5097           (void) FormatLocaleString(clone_info->filename,MagickPathExtent,
5098             "%s:%s",blob_info->magick,unique);
5099           image=ReadImage(clone_info,exception);
5100           if (image != (Image *) NULL)
5101             {
5102               Image
5103                 *images;
5104
5105               /*
5106                 Restore original filenames and image format.
5107               */
5108               for (images=GetFirstImageInList(image); images != (Image *) NULL; )
5109               {
5110                 (void) CopyMagickString(images->filename,image_info->filename,
5111                   MagickPathExtent);
5112                 (void) CopyMagickString(images->magick_filename,
5113                   image_info->filename,MagickPathExtent);
5114                 (void) CopyMagickString(images->magick,magick_info->name,
5115                   MagickPathExtent);
5116                 (void) CloseBlob(images);
5117                 images=GetNextImageInList(images);
5118               }
5119             }
5120         }
5121       clone_info=DestroyImageInfo(clone_info);
5122       blob=(unsigned char *) RelinquishMagickMemory(blob);
5123       (void) RelinquishUniqueFileResource(unique);
5124     }
5125   blob_info=DestroyImageInfo(blob_info);
5126   return(image);
5127 }
5128 \f
5129 /*
5130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5131 %                                                                             %
5132 %                                                                             %
5133 %                                                                             %
5134 +  W r i t e B l o b                                                          %
5135 %                                                                             %
5136 %                                                                             %
5137 %                                                                             %
5138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5139 %
5140 %  WriteBlob() writes data to a blob or image file.  It returns the number of
5141 %  bytes written.
5142 %
5143 %  The format of the WriteBlob method is:
5144 %
5145 %      ssize_t WriteBlob(Image *image,const size_t length,const void *data)
5146 %
5147 %  A description of each parameter follows:
5148 %
5149 %    o image: the image.
5150 %
5151 %    o length:  Specifies an integer representing the number of bytes to
5152 %      write to the file.
5153 %
5154 %    o data:  The address of the data to write to the blob or file.
5155 %
5156 */
5157 MagickExport ssize_t WriteBlob(Image *image,const size_t length,
5158   const void *data)
5159 {
5160   int
5161     c;
5162
5163   register const unsigned char
5164     *p;
5165
5166   ssize_t
5167     count;
5168
5169   assert(image != (Image *) NULL);
5170   assert(image->signature == MagickCoreSignature);
5171   assert(data != (const void *) NULL);
5172   assert(image->blob != (BlobInfo *) NULL);
5173   assert(image->blob->type != UndefinedStream);
5174   if (length == 0)
5175     return(0);
5176   count=0;
5177   p=(const unsigned char *) data;
5178   switch (image->blob->type)
5179   {
5180     case UndefinedStream:
5181       break;
5182     case StandardStream:
5183     case FileStream:
5184     case PipeStream:
5185     {
5186       switch (length)
5187       {
5188         default:
5189         {
5190           count=(ssize_t) fwrite((const char *) data,1,length,
5191             image->blob->file_info.file);
5192           break;
5193         }
5194         case 4:
5195         {
5196           c=putc((int) *p++,image->blob->file_info.file);
5197           if (c == EOF)
5198             break;
5199           count++;
5200         }
5201         case 3:
5202         {
5203           c=putc((int) *p++,image->blob->file_info.file);
5204           if (c == EOF)
5205             break;
5206           count++;
5207         }
5208         case 2:
5209         {
5210           c=putc((int) *p++,image->blob->file_info.file);
5211           if (c == EOF)
5212             break;
5213           count++;
5214         }
5215         case 1:
5216         {
5217           c=putc((int) *p++,image->blob->file_info.file);
5218           if (c == EOF)
5219             break;
5220           count++;
5221         }
5222         case 0:
5223           break;
5224       }
5225       break;
5226     }
5227     case ZipStream:
5228     {
5229 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5230       switch (length)
5231       {
5232         default:
5233         {
5234           count=(ssize_t) gzwrite(image->blob->file_info.gzfile,(void *) data,
5235             (unsigned int) length);
5236           break;
5237         }
5238         case 4:
5239         {
5240           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5241           if (c == EOF)
5242             break;
5243           count++;
5244         }
5245         case 3:
5246         {
5247           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5248           if (c == EOF)
5249             break;
5250           count++;
5251         }
5252         case 2:
5253         {
5254           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5255           if (c == EOF)
5256             break;
5257           count++;
5258         }
5259         case 1:
5260         {
5261           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5262           if (c == EOF)
5263             break;
5264           count++;
5265         }
5266         case 0:
5267           break;
5268       }
5269 #endif
5270       break;
5271     }
5272     case BZipStream:
5273     {
5274 #if defined(MAGICKCORE_BZLIB_DELEGATE)
5275       count=(ssize_t) BZ2_bzwrite(image->blob->file_info.bzfile,(void *) data,
5276         (int) length);
5277 #endif
5278       break;
5279     }
5280     case FifoStream:
5281     {
5282       count=(ssize_t) image->blob->stream(image,data,length);
5283       break;
5284     }
5285     case BlobStream:
5286     {
5287       register unsigned char
5288         *q;
5289
5290       if ((image->blob->offset+(MagickOffsetType) length) >=
5291           (MagickOffsetType) image->blob->extent)
5292         {
5293           if (image->blob->mapped != MagickFalse)
5294             return(0);
5295           image->blob->extent+=length+image->blob->quantum;
5296           image->blob->quantum<<=1;
5297           image->blob->data=(unsigned char *) ResizeQuantumMemory(
5298             image->blob->data,image->blob->extent+1,sizeof(*image->blob->data));
5299           (void) SyncBlob(image);
5300           if (image->blob->data == (unsigned char *) NULL)
5301             {
5302               (void) DetachBlob(image->blob);
5303               return(0);
5304             }
5305         }
5306       q=image->blob->data+image->blob->offset;
5307       (void) memcpy(q,p,length);
5308       image->blob->offset+=length;
5309       if (image->blob->offset >= (MagickOffsetType) image->blob->length)
5310         image->blob->length=(size_t) image->blob->offset;
5311       count=(ssize_t) length;
5312       break;
5313     }
5314     case CustomStream:
5315     {
5316       count=image->blob->custom_stream->writer((const unsigned char *) data,
5317         length,image->blob->custom_stream->data);
5318       break;
5319     }
5320   }
5321   return(count);
5322 }
5323 \f
5324 /*
5325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5326 %                                                                             %
5327 %                                                                             %
5328 %                                                                             %
5329 +  W r i t e B l o b B y t e                                                  %
5330 %                                                                             %
5331 %                                                                             %
5332 %                                                                             %
5333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5334 %
5335 %  WriteBlobByte() write an integer to a blob.  It returns the number of bytes
5336 %  written (either 0 or 1);
5337 %
5338 %  The format of the WriteBlobByte method is:
5339 %
5340 %      ssize_t WriteBlobByte(Image *image,const unsigned char value)
5341 %
5342 %  A description of each parameter follows.
5343 %
5344 %    o image: the image.
5345 %
5346 %    o value: Specifies the value to write.
5347 %
5348 */
5349 MagickExport ssize_t WriteBlobByte(Image *image,const unsigned char value)
5350 {
5351   assert(image != (Image *) NULL);
5352   assert(image->signature == MagickCoreSignature);
5353   return(WriteBlobStream(image,1,&value));
5354 }
5355 \f
5356 /*
5357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358 %                                                                             %
5359 %                                                                             %
5360 %                                                                             %
5361 +  W r i t e B l o b F l o a t                                                %
5362 %                                                                             %
5363 %                                                                             %
5364 %                                                                             %
5365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366 %
5367 %  WriteBlobFloat() writes a float value as a 32-bit quantity in the byte-order
5368 %  specified by the endian member of the image structure.
5369 %
5370 %  The format of the WriteBlobFloat method is:
5371 %
5372 %      ssize_t WriteBlobFloat(Image *image,const float value)
5373 %
5374 %  A description of each parameter follows.
5375 %
5376 %    o image: the image.
5377 %
5378 %    o value: Specifies the value to write.
5379 %
5380 */
5381 MagickExport ssize_t WriteBlobFloat(Image *image,const float value)
5382 {
5383   union
5384   {
5385     unsigned int
5386       unsigned_value;
5387
5388     float
5389       float_value;
5390   } quantum;
5391
5392   quantum.unsigned_value=0U;
5393   quantum.float_value=value;
5394   return(WriteBlobLong(image,quantum.unsigned_value));
5395 }
5396 \f
5397 /*
5398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5399 %                                                                             %
5400 %                                                                             %
5401 %                                                                             %
5402 +  W r i t e B l o b L o n g                                                  %
5403 %                                                                             %
5404 %                                                                             %
5405 %                                                                             %
5406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5407 %
5408 %  WriteBlobLong() writes a unsigned int value as a 32-bit quantity in the
5409 %  byte-order specified by the endian member of the image structure.
5410 %
5411 %  The format of the WriteBlobLong method is:
5412 %
5413 %      ssize_t WriteBlobLong(Image *image,const unsigned int value)
5414 %
5415 %  A description of each parameter follows.
5416 %
5417 %    o image: the image.
5418 %
5419 %    o value: Specifies the value to write.
5420 %
5421 */
5422 MagickExport ssize_t WriteBlobLong(Image *image,const unsigned int value)
5423 {
5424   unsigned char
5425     buffer[4];
5426
5427   assert(image != (Image *) NULL);
5428   assert(image->signature == MagickCoreSignature);
5429   if (image->endian == LSBEndian)
5430     {
5431       buffer[0]=(unsigned char) value;
5432       buffer[1]=(unsigned char) (value >> 8);
5433       buffer[2]=(unsigned char) (value >> 16);
5434       buffer[3]=(unsigned char) (value >> 24);
5435       return(WriteBlobStream(image,4,buffer));
5436     }
5437   buffer[0]=(unsigned char) (value >> 24);
5438   buffer[1]=(unsigned char) (value >> 16);
5439   buffer[2]=(unsigned char) (value >> 8);
5440   buffer[3]=(unsigned char) value;
5441   return(WriteBlobStream(image,4,buffer));
5442 }
5443 \f
5444 /*
5445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5446 %                                                                             %
5447 %                                                                             %
5448 %                                                                             %
5449 +   W r i t e B l o b S h o r t                                               %
5450 %                                                                             %
5451 %                                                                             %
5452 %                                                                             %
5453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5454 %
5455 %  WriteBlobShort() writes a short value as a 16-bit quantity in the
5456 %  byte-order specified by the endian member of the image structure.
5457 %
5458 %  The format of the WriteBlobShort method is:
5459 %
5460 %      ssize_t WriteBlobShort(Image *image,const unsigned short value)
5461 %
5462 %  A description of each parameter follows.
5463 %
5464 %    o image: the image.
5465 %
5466 %    o value:  Specifies the value to write.
5467 %
5468 */
5469 MagickExport ssize_t WriteBlobShort(Image *image,const unsigned short value)
5470 {
5471   unsigned char
5472     buffer[2];
5473
5474   assert(image != (Image *) NULL);
5475   assert(image->signature == MagickCoreSignature);
5476   if (image->endian == LSBEndian)
5477     {
5478       buffer[0]=(unsigned char) value;
5479       buffer[1]=(unsigned char) (value >> 8);
5480       return(WriteBlobStream(image,2,buffer));
5481     }
5482   buffer[0]=(unsigned char) (value >> 8);
5483   buffer[1]=(unsigned char) value;
5484   return(WriteBlobStream(image,2,buffer));
5485 }
5486 \f
5487 /*
5488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5489 %                                                                             %
5490 %                                                                             %
5491 %                                                                             %
5492 +  W r i t e B l o b L S B L o n g                                            %
5493 %                                                                             %
5494 %                                                                             %
5495 %                                                                             %
5496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5497 %
5498 %  WriteBlobLSBLong() writes a unsigned int value as a 32-bit quantity in
5499 %  least-significant byte first order.
5500 %
5501 %  The format of the WriteBlobLSBLong method is:
5502 %
5503 %      ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
5504 %
5505 %  A description of each parameter follows.
5506 %
5507 %    o image: the image.
5508 %
5509 %    o value: Specifies the value to write.
5510 %
5511 */
5512 MagickExport ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
5513 {
5514   unsigned char
5515     buffer[4];
5516
5517   assert(image != (Image *) NULL);
5518   assert(image->signature == MagickCoreSignature);
5519   buffer[0]=(unsigned char) value;
5520   buffer[1]=(unsigned char) (value >> 8);
5521   buffer[2]=(unsigned char) (value >> 16);
5522   buffer[3]=(unsigned char) (value >> 24);
5523   return(WriteBlobStream(image,4,buffer));
5524 }
5525 \f
5526 /*
5527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5528 %                                                                             %
5529 %                                                                             %
5530 %                                                                             %
5531 +   W r i t e B l o b L S B S h o r t                                         %
5532 %                                                                             %
5533 %                                                                             %
5534 %                                                                             %
5535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5536 %
5537 %  WriteBlobLSBShort() writes a unsigned short value as a 16-bit quantity in
5538 %  least-significant byte first order.
5539 %
5540 %  The format of the WriteBlobLSBShort method is:
5541 %
5542 %      ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
5543 %
5544 %  A description of each parameter follows.
5545 %
5546 %    o image: the image.
5547 %
5548 %    o value:  Specifies the value to write.
5549 %
5550 */
5551 MagickExport ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
5552 {
5553   unsigned char
5554     buffer[2];
5555
5556   assert(image != (Image *) NULL);
5557   assert(image->signature == MagickCoreSignature);
5558   buffer[0]=(unsigned char) value;
5559   buffer[1]=(unsigned char) (value >> 8);
5560   return(WriteBlobStream(image,2,buffer));
5561 }
5562 \f
5563 /*
5564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5565 %                                                                             %
5566 %                                                                             %
5567 %                                                                             %
5568 +  W r i t e B l o b L S B S i g n e d L o n g                                %
5569 %                                                                             %
5570 %                                                                             %
5571 %                                                                             %
5572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5573 %
5574 %  WriteBlobLSBSignedLong() writes a signed value as a 32-bit quantity in
5575 %  least-significant byte first order.
5576 %
5577 %  The format of the WriteBlobLSBSignedLong method is:
5578 %
5579 %      ssize_t WriteBlobLSBSignedLong(Image *image,const signed int value)
5580 %
5581 %  A description of each parameter follows.
5582 %
5583 %    o image: the image.
5584 %
5585 %    o value: Specifies the value to write.
5586 %
5587 */
5588 MagickExport ssize_t WriteBlobLSBSignedLong(Image *image,const signed int value)
5589 {
5590   union
5591   {
5592     unsigned int
5593       unsigned_value;
5594
5595     signed int
5596       signed_value;
5597   } quantum;
5598
5599   unsigned char
5600     buffer[4];
5601
5602   assert(image != (Image *) NULL);
5603   assert(image->signature == MagickCoreSignature);
5604   quantum.signed_value=value;
5605   buffer[0]=(unsigned char) quantum.unsigned_value;
5606   buffer[1]=(unsigned char) (quantum.unsigned_value >> 8);
5607   buffer[2]=(unsigned char) (quantum.unsigned_value >> 16);
5608   buffer[3]=(unsigned char) (quantum.unsigned_value >> 24);
5609   return(WriteBlobStream(image,4,buffer));
5610 }
5611 \f
5612 /*
5613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5614 %                                                                             %
5615 %                                                                             %
5616 %                                                                             %
5617 +   W r i t e B l o b L S B S i g n e d S h o r t                             %
5618 %                                                                             %
5619 %                                                                             %
5620 %                                                                             %
5621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5622 %
5623 %  WriteBlobLSBSignedShort() writes a signed short value as a 16-bit quantity
5624 %  in least-significant byte first order.
5625 %
5626 %  The format of the WriteBlobLSBSignedShort method is:
5627 %
5628 %      ssize_t WriteBlobLSBSignedShort(Image *image,const signed short value)
5629 %
5630 %  A description of each parameter follows.
5631 %
5632 %    o image: the image.
5633 %
5634 %    o value:  Specifies the value to write.
5635 %
5636 */
5637 MagickExport ssize_t WriteBlobLSBSignedShort(Image *image,
5638   const signed short value)
5639 {
5640   union
5641   {
5642     unsigned short
5643       unsigned_value;
5644
5645     signed short
5646       signed_value;
5647   } quantum;
5648
5649   unsigned char
5650     buffer[2];
5651
5652   assert(image != (Image *) NULL);
5653   assert(image->signature == MagickCoreSignature);
5654   quantum.signed_value=value;
5655   buffer[0]=(unsigned char) quantum.unsigned_value;
5656   buffer[1]=(unsigned char) (quantum.unsigned_value >> 8);
5657   return(WriteBlobStream(image,2,buffer));
5658 }
5659 \f
5660 /*
5661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5662 %                                                                             %
5663 %                                                                             %
5664 %                                                                             %
5665 +  W r i t e B l o b M S B L o n g                                            %
5666 %                                                                             %
5667 %                                                                             %
5668 %                                                                             %
5669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5670 %
5671 %  WriteBlobMSBLong() writes a unsigned int value as a 32-bit quantity in
5672 %  most-significant byte first order.
5673 %
5674 %  The format of the WriteBlobMSBLong method is:
5675 %
5676 %      ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
5677 %
5678 %  A description of each parameter follows.
5679 %
5680 %    o value:  Specifies the value to write.
5681 %
5682 %    o image: the image.
5683 %
5684 */
5685 MagickExport ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
5686 {
5687   unsigned char
5688     buffer[4];
5689
5690   assert(image != (Image *) NULL);
5691   assert(image->signature == MagickCoreSignature);
5692   buffer[0]=(unsigned char) (value >> 24);
5693   buffer[1]=(unsigned char) (value >> 16);
5694   buffer[2]=(unsigned char) (value >> 8);
5695   buffer[3]=(unsigned char) value;
5696   return(WriteBlobStream(image,4,buffer));
5697 }
5698 \f
5699 /*
5700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5701 %                                                                             %
5702 %                                                                             %
5703 %                                                                             %
5704 +  W r i t e B l o b M S B L o n g L o n g                                    %
5705 %                                                                             %
5706 %                                                                             %
5707 %                                                                             %
5708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5709 %
5710 %  WriteBlobMSBLongLong() writes a long long value as a 64-bit quantity in
5711 %  most-significant byte first order.
5712 %
5713 %  The format of the WriteBlobMSBLongLong method is:
5714 %
5715 %      ssize_t WriteBlobMSBLongLong(Image *image,const MagickSizeType value)
5716 %
5717 %  A description of each parameter follows.
5718 %
5719 %    o value:  Specifies the value to write.
5720 %
5721 %    o image: the image.
5722 %
5723 */
5724 MagickExport ssize_t WriteBlobMSBLongLong(Image *image,
5725   const MagickSizeType value)
5726 {
5727   unsigned char
5728     buffer[8];
5729
5730   assert(image != (Image *) NULL);
5731   assert(image->signature == MagickCoreSignature);
5732   buffer[0]=(unsigned char) (value >> 56);
5733   buffer[1]=(unsigned char) (value >> 48);
5734   buffer[2]=(unsigned char) (value >> 40);
5735   buffer[3]=(unsigned char) (value >> 32);
5736   buffer[4]=(unsigned char) (value >> 24);
5737   buffer[5]=(unsigned char) (value >> 16);
5738   buffer[6]=(unsigned char) (value >> 8);
5739   buffer[7]=(unsigned char) value;
5740   return(WriteBlobStream(image,8,buffer));
5741 }
5742 \f
5743 /*
5744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5745 %                                                                             %
5746 %                                                                             %
5747 %                                                                             %
5748 +  W r i t e B l o b M S B S i g n e d L o n g                                %
5749 %                                                                             %
5750 %                                                                             %
5751 %                                                                             %
5752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5753 %
5754 %  WriteBlobMSBSignedLong() writes a signed value as a 32-bit quantity in
5755 %  most-significant byte first order.
5756 %
5757 %  The format of the WriteBlobMSBSignedLong method is:
5758 %
5759 %      ssize_t WriteBlobMSBSignedLong(Image *image,const signed int value)
5760 %
5761 %  A description of each parameter follows.
5762 %
5763 %    o image: the image.
5764 %
5765 %    o value: Specifies the value to write.
5766 %
5767 */
5768 MagickExport ssize_t WriteBlobMSBSignedLong(Image *image,const signed int value)
5769 {
5770   union
5771   {
5772     unsigned int
5773       unsigned_value;
5774
5775     signed int
5776       signed_value;
5777   } quantum;
5778
5779   unsigned char
5780     buffer[4];
5781
5782   assert(image != (Image *) NULL);
5783   assert(image->signature == MagickCoreSignature);
5784   quantum.signed_value=value;
5785   buffer[0]=(unsigned char) (quantum.unsigned_value >> 24);
5786   buffer[1]=(unsigned char) (quantum.unsigned_value >> 16);
5787   buffer[2]=(unsigned char) (quantum.unsigned_value >> 8);
5788   buffer[3]=(unsigned char) quantum.unsigned_value;
5789   return(WriteBlobStream(image,4,buffer));
5790 }
5791 \f
5792 /*
5793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5794 %                                                                             %
5795 %                                                                             %
5796 %                                                                             %
5797 +   W r i t e B l o b M S B S i g n e d S h o r t                             %
5798 %                                                                             %
5799 %                                                                             %
5800 %                                                                             %
5801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5802 %
5803 %  WriteBlobMSBSignedShort() writes a signed short value as a 16-bit quantity
5804 %  in most-significant byte first order.
5805 %
5806 %  The format of the WriteBlobMSBSignedShort method is:
5807 %
5808 %      ssize_t WriteBlobMSBSignedShort(Image *image,const signed short value)
5809 %
5810 %  A description of each parameter follows.
5811 %
5812 %    o image: the image.
5813 %
5814 %    o value:  Specifies the value to write.
5815 %
5816 */
5817 MagickExport ssize_t WriteBlobMSBSignedShort(Image *image,
5818   const signed short value)
5819 {
5820   union
5821   {
5822     unsigned short
5823       unsigned_value;
5824
5825     signed short
5826       signed_value;
5827   } quantum;
5828
5829   unsigned char
5830     buffer[2];
5831
5832   assert(image != (Image *) NULL);
5833   assert(image->signature == MagickCoreSignature);
5834   quantum.signed_value=value;
5835   buffer[0]=(unsigned char) (quantum.unsigned_value >> 8);
5836   buffer[1]=(unsigned char) quantum.unsigned_value;
5837   return(WriteBlobStream(image,2,buffer));
5838 }
5839 \f
5840 /*
5841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5842 %                                                                             %
5843 %                                                                             %
5844 %                                                                             %
5845 +  W r i t e B l o b M S B S h o r t                                          %
5846 %                                                                             %
5847 %                                                                             %
5848 %                                                                             %
5849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5850 %
5851 %  WriteBlobMSBShort() writes a unsigned short value as a 16-bit quantity in
5852 %  most-significant byte first order.
5853 %
5854 %  The format of the WriteBlobMSBShort method is:
5855 %
5856 %      ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
5857 %
5858 %  A description of each parameter follows.
5859 %
5860 %   o  value:  Specifies the value to write.
5861 %
5862 %   o  file:  Specifies the file to write the data to.
5863 %
5864 */
5865 MagickExport ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
5866 {
5867   unsigned char
5868     buffer[2];
5869
5870   assert(image != (Image *) NULL);
5871   assert(image->signature == MagickCoreSignature);
5872   buffer[0]=(unsigned char) (value >> 8);
5873   buffer[1]=(unsigned char) value;
5874   return(WriteBlobStream(image,2,buffer));
5875 }
5876 \f
5877 /*
5878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5879 %                                                                             %
5880 %                                                                             %
5881 %                                                                             %
5882 +  W r i t e B l o b S t r i n g                                              %
5883 %                                                                             %
5884 %                                                                             %
5885 %                                                                             %
5886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5887 %
5888 %  WriteBlobString() write a string to a blob.  It returns the number of
5889 %  characters written.
5890 %
5891 %  The format of the WriteBlobString method is:
5892 %
5893 %      ssize_t WriteBlobString(Image *image,const char *string)
5894 %
5895 %  A description of each parameter follows.
5896 %
5897 %    o image: the image.
5898 %
5899 %    o string: Specifies the string to write.
5900 %
5901 */
5902 MagickExport ssize_t WriteBlobString(Image *image,const char *string)
5903 {
5904   assert(image != (Image *) NULL);
5905   assert(image->signature == MagickCoreSignature);
5906   assert(string != (const char *) NULL);
5907   return(WriteBlobStream(image,strlen(string),(const unsigned char *) string));
5908 }