]> granicus.if.org Git - imagemagick/blob - MagickCore/blob.c
Added decorators for unused arguments.
[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 *magick_unused(exception))
216 {
217   CustomStreamInfo
218     *custom_stream;
219
220   magick_unreferenced(exception);
221   custom_stream=(CustomStreamInfo *) AcquireMagickMemory(
222     sizeof(*custom_stream));
223   if (custom_stream == (CustomStreamInfo *) NULL)
224     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
225   (void) ResetMagickMemory(custom_stream,0,sizeof(*custom_stream));
226   custom_stream->signature=MagickCoreSignature;
227   return(custom_stream);
228 }
229 \f
230 /*
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 %                                                                             %
233 %                                                                             %
234 %                                                                             %
235 +   A t t a c h B l o b                                                       %
236 %                                                                             %
237 %                                                                             %
238 %                                                                             %
239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 %
241 %  AttachBlob() attaches a blob to the BlobInfo structure.
242 %
243 %  The format of the AttachBlob method is:
244 %
245 %      void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
246 %
247 %  A description of each parameter follows:
248 %
249 %    o blob_info: Specifies a pointer to a BlobInfo structure.
250 %
251 %    o blob: the address of a character stream in one of the image formats
252 %      understood by ImageMagick.
253 %
254 %    o length: This size_t integer reflects the length in bytes of the blob.
255 %
256 */
257 MagickExport void AttachBlob(BlobInfo *blob_info,const void *blob,
258   const size_t length)
259 {
260   assert(blob_info != (BlobInfo *) NULL);
261   if (blob_info->debug != MagickFalse)
262     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
263   blob_info->length=length;
264   blob_info->extent=length;
265   blob_info->quantum=(size_t) MagickMaxBlobExtent;
266   blob_info->offset=0;
267   blob_info->type=BlobStream;
268   blob_info->file_info.file=(FILE *) NULL;
269   blob_info->data=(unsigned char *) blob;
270   blob_info->mapped=MagickFalse;
271 }
272 \f
273 /*
274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275 %                                                                             %
276 %                                                                             %
277 %                                                                             %
278 +   B l o b T o F i l e                                                       %
279 %                                                                             %
280 %                                                                             %
281 %                                                                             %
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 %
284 %  BlobToFile() writes a blob to a file.  It returns MagickFalse if an error
285 %  occurs otherwise MagickTrue.
286 %
287 %  The format of the BlobToFile method is:
288 %
289 %       MagickBooleanType BlobToFile(char *filename,const void *blob,
290 %         const size_t length,ExceptionInfo *exception)
291 %
292 %  A description of each parameter follows:
293 %
294 %    o filename: Write the blob to this file.
295 %
296 %    o blob: the address of a blob.
297 %
298 %    o length: This length in bytes of the blob.
299 %
300 %    o exception: return any errors or warnings in this structure.
301 %
302 */
303 MagickExport MagickBooleanType BlobToFile(char *filename,const void *blob,
304   const size_t length,ExceptionInfo *exception)
305 {
306   int
307     file;
308
309   register size_t
310     i;
311
312   ssize_t
313     count;
314
315   assert(filename != (const char *) NULL);
316   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
317   assert(blob != (const void *) NULL);
318   if (*filename == '\0')
319     file=AcquireUniqueFileResource(filename);
320   else
321     file=open_utf8(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
322   if (file == -1)
323     {
324       ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
325       return(MagickFalse);
326     }
327   for (i=0; i < length; i+=count)
328   {
329     count=write(file,(const char *) blob+i,MagickMin(length-i,SSIZE_MAX));
330     if (count <= 0)
331       {
332         count=0;
333         if (errno != EINTR)
334           break;
335       }
336   }
337   file=close(file);
338   if ((file == -1) || (i < length))
339     {
340       ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
341       return(MagickFalse);
342     }
343   return(MagickTrue);
344 }
345 \f
346 /*
347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348 %                                                                             %
349 %                                                                             %
350 %                                                                             %
351 %   B l o b T o I m a g e                                                     %
352 %                                                                             %
353 %                                                                             %
354 %                                                                             %
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 %
357 %  BlobToImage() implements direct to memory image formats.  It returns the
358 %  blob as an image.
359 %
360 %  The format of the BlobToImage method is:
361 %
362 %      Image *BlobToImage(const ImageInfo *image_info,const void *blob,
363 %        const size_t length,ExceptionInfo *exception)
364 %
365 %  A description of each parameter follows:
366 %
367 %    o image_info: the image info.
368 %
369 %    o blob: the address of a character stream in one of the image formats
370 %      understood by ImageMagick.
371 %
372 %    o length: This size_t integer reflects the length in bytes of the blob.
373 %
374 %    o exception: return any errors or warnings in this structure.
375 %
376 */
377 MagickExport Image *BlobToImage(const ImageInfo *image_info,const void *blob,
378   const size_t length,ExceptionInfo *exception)
379 {
380   const MagickInfo
381     *magick_info;
382
383   Image
384     *image;
385
386   ImageInfo
387     *blob_info,
388     *clone_info;
389
390   MagickBooleanType
391     status;
392
393   assert(image_info != (ImageInfo *) NULL);
394   assert(image_info->signature == MagickCoreSignature);
395   if (image_info->debug != MagickFalse)
396     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
397       image_info->filename);
398   assert(exception != (ExceptionInfo *) NULL);
399   if ((blob == (const void *) NULL) || (length == 0))
400     {
401       (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
402         "ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
403       return((Image *) NULL);
404     }
405   blob_info=CloneImageInfo(image_info);
406   blob_info->blob=(void *) blob;
407   blob_info->length=length;
408   if (*blob_info->magick == '\0')
409     (void) SetImageInfo(blob_info,0,exception);
410   magick_info=GetMagickInfo(blob_info->magick,exception);
411   if (magick_info == (const MagickInfo *) NULL)
412     {
413       (void) ThrowMagickException(exception,GetMagickModule(),
414         MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
415         blob_info->magick);
416       blob_info=DestroyImageInfo(blob_info);
417       return((Image *) NULL);
418     }
419   if (GetMagickBlobSupport(magick_info) != MagickFalse)
420     {
421       /*
422         Native blob support for this image format.
423       */
424       (void) CopyMagickString(blob_info->filename,image_info->filename,
425         MagickPathExtent);
426       (void) CopyMagickString(blob_info->magick,image_info->magick,
427         MagickPathExtent);
428       image=ReadImage(blob_info,exception);
429       if (image != (Image *) NULL)
430         (void) DetachBlob(image->blob);
431       blob_info=DestroyImageInfo(blob_info);
432       return(image);
433     }
434   /*
435     Write blob to a temporary file on disk.
436   */
437   blob_info->blob=(void *) NULL;
438   blob_info->length=0;
439   *blob_info->filename='\0';
440   status=BlobToFile(blob_info->filename,blob,length,exception);
441   if (status == MagickFalse)
442     {
443       (void) RelinquishUniqueFileResource(blob_info->filename);
444       blob_info=DestroyImageInfo(blob_info);
445       return((Image *) NULL);
446     }
447   clone_info=CloneImageInfo(blob_info);
448   (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:%s",
449     blob_info->magick,blob_info->filename);
450   image=ReadImage(clone_info,exception);
451   if (image != (Image *) NULL)
452     {
453       Image
454         *images;
455
456       /*
457         Restore original filenames and image format.
458       */
459       for (images=GetFirstImageInList(image); images != (Image *) NULL; )
460       {
461         (void) CopyMagickString(images->filename,image_info->filename,
462           MagickPathExtent);
463         (void) CopyMagickString(images->magick_filename,image_info->filename,
464           MagickPathExtent);
465         (void) CopyMagickString(images->magick,magick_info->name,
466           MagickPathExtent);
467         images=GetNextImageInList(images);
468       }
469     }
470   clone_info=DestroyImageInfo(clone_info);
471   (void) RelinquishUniqueFileResource(blob_info->filename);
472   blob_info=DestroyImageInfo(blob_info);
473   return(image);
474 }
475 \f
476 /*
477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478 %                                                                             %
479 %                                                                             %
480 %                                                                             %
481 +   C l o n e B l o b I n f o                                                 %
482 %                                                                             %
483 %                                                                             %
484 %                                                                             %
485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486 %
487 %  CloneBlobInfo() makes a duplicate of the given blob info structure, or if
488 %  blob info is NULL, a new one.
489 %
490 %  The format of the CloneBlobInfo method is:
491 %
492 %      BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
493 %
494 %  A description of each parameter follows:
495 %
496 %    o blob_info: the blob info.
497 %
498 */
499 MagickExport BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
500 {
501   BlobInfo
502     *clone_info;
503
504   clone_info=(BlobInfo *) AcquireMagickMemory(sizeof(*clone_info));
505   if (clone_info == (BlobInfo *) NULL)
506     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
507   GetBlobInfo(clone_info);
508   if (blob_info == (BlobInfo *) NULL)
509     return(clone_info);
510   clone_info->length=blob_info->length;
511   clone_info->extent=blob_info->extent;
512   clone_info->synchronize=blob_info->synchronize;
513   clone_info->quantum=blob_info->quantum;
514   clone_info->mapped=blob_info->mapped;
515   clone_info->eof=blob_info->eof;
516   clone_info->offset=blob_info->offset;
517   clone_info->size=blob_info->size;
518   clone_info->exempt=blob_info->exempt;
519   clone_info->status=blob_info->status;
520   clone_info->temporary=blob_info->temporary;
521   clone_info->type=blob_info->type;
522   clone_info->file_info.file=blob_info->file_info.file;
523   clone_info->properties=blob_info->properties;
524   clone_info->stream=blob_info->stream;
525   clone_info->custom_stream=blob_info->custom_stream;
526   clone_info->data=blob_info->data;
527   clone_info->debug=IsEventLogging();
528   clone_info->reference_count=1;
529   return(clone_info);
530 }
531 \f
532 /*
533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
534 %                                                                             %
535 %                                                                             %
536 %                                                                             %
537 +   C l o s e B l o b                                                         %
538 %                                                                             %
539 %                                                                             %
540 %                                                                             %
541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
542 %
543 %  CloseBlob() closes a stream associated with the image.
544 %
545 %  The format of the CloseBlob method is:
546 %
547 %      MagickBooleanType CloseBlob(Image *image)
548 %
549 %  A description of each parameter follows:
550 %
551 %    o image: the image.
552 %
553 */
554 MagickExport MagickBooleanType CloseBlob(Image *image)
555 {
556   int
557     status;
558
559   /*
560     Close image file.
561   */
562   assert(image != (Image *) NULL);
563   assert(image->signature == MagickCoreSignature);
564   if (image->debug != MagickFalse)
565     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
566   assert(image->blob != (BlobInfo *) NULL);
567   if (image->blob->type == UndefinedStream)
568     return(MagickTrue);
569   status=SyncBlob(image);
570   switch (image->blob->type)
571   {
572     case UndefinedStream:
573     case StandardStream:
574       break;
575     case FileStream:
576     case PipeStream:
577     {
578       if (image->blob->synchronize != MagickFalse)
579         status=fsync(fileno(image->blob->file_info.file));
580       status=ferror(image->blob->file_info.file);
581       break;
582     }
583     case ZipStream:
584     {
585 #if defined(MAGICKCORE_ZLIB_DELEGATE)
586       (void) gzerror(image->blob->file_info.gzfile,&status);
587 #endif
588       break;
589     }
590     case BZipStream:
591     {
592 #if defined(MAGICKCORE_BZLIB_DELEGATE)
593       (void) BZ2_bzerror(image->blob->file_info.bzfile,&status);
594 #endif
595       break;
596     }
597     case FifoStream:
598       break;
599     case BlobStream:
600     {
601       if ((image->blob->file_info.file != (FILE *) NULL) &&
602           (image->blob->synchronize != MagickFalse))
603         {
604           (void) fsync(fileno(image->blob->file_info.file));
605           status=ferror(image->blob->file_info.file);
606         }
607       break;
608     }
609     case CustomStream:
610       break;
611   }
612   image->blob->status=status < 0 ? MagickTrue : MagickFalse;
613   image->blob->size=GetBlobSize(image);
614   image->extent=image->blob->size;
615   image->blob->eof=MagickFalse;
616   if (image->blob->exempt != MagickFalse)
617     {
618       image->blob->type=UndefinedStream;
619       return(image->blob->status);
620     }
621   switch (image->blob->type)
622   {
623     case UndefinedStream:
624     case StandardStream:
625       break;
626     case FileStream:
627     {
628       status=fclose(image->blob->file_info.file);
629       break;
630     }
631     case PipeStream:
632     {
633 #if defined(MAGICKCORE_HAVE_PCLOSE)
634       status=pclose(image->blob->file_info.file);
635 #endif
636       break;
637     }
638     case ZipStream:
639     {
640 #if defined(MAGICKCORE_ZLIB_DELEGATE)
641       status=gzclose(image->blob->file_info.gzfile);
642 #endif
643       break;
644     }
645     case BZipStream:
646     {
647 #if defined(MAGICKCORE_BZLIB_DELEGATE)
648       BZ2_bzclose(image->blob->file_info.bzfile);
649 #endif
650       break;
651     }
652     case FifoStream:
653       break;
654     case BlobStream:
655     {
656       if (image->blob->file_info.file != (FILE *) NULL)
657         status=fclose(image->blob->file_info.file);
658       break;
659     }
660     case CustomStream:
661       break;
662   }
663   (void) DetachBlob(image->blob);
664   image->blob->status=status < 0 ? MagickTrue : MagickFalse;
665   return(image->blob->status);
666 }
667 \f
668 /*
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 %                                                                             %
671 %                                                                             %
672 %                                                                             %
673 +   D e s t r o y B l o b                                                     %
674 %                                                                             %
675 %                                                                             %
676 %                                                                             %
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 %
679 %  DestroyBlob() deallocates memory associated with a blob.
680 %
681 %  The format of the DestroyBlob method is:
682 %
683 %      void DestroyBlob(Image *image)
684 %
685 %  A description of each parameter follows:
686 %
687 %    o image: the image.
688 %
689 */
690 MagickExport void DestroyBlob(Image *image)
691 {
692   MagickBooleanType
693     destroy;
694
695   assert(image != (Image *) NULL);
696   assert(image->signature == MagickCoreSignature);
697   if (image->debug != MagickFalse)
698     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
699   assert(image->blob != (BlobInfo *) NULL);
700   assert(image->blob->signature == MagickCoreSignature);
701   destroy=MagickFalse;
702   LockSemaphoreInfo(image->blob->semaphore);
703   image->blob->reference_count--;
704   assert(image->blob->reference_count >= 0);
705   if (image->blob->reference_count == 0)
706     destroy=MagickTrue;
707   UnlockSemaphoreInfo(image->blob->semaphore);
708   if (destroy == MagickFalse)
709     return;
710   (void) CloseBlob(image);
711   if (image->blob->mapped != MagickFalse)
712     {
713       (void) UnmapBlob(image->blob->data,image->blob->length);
714       RelinquishMagickResource(MapResource,image->blob->length);
715     }
716   if (image->blob->semaphore != (SemaphoreInfo *) NULL)
717     RelinquishSemaphoreInfo(&image->blob->semaphore);
718   image->blob->signature=(~MagickCoreSignature);
719   image->blob=(BlobInfo *) RelinquishMagickMemory(image->blob);
720 }
721 \f
722 /*
723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
724 %                                                                             %
725 %                                                                             %
726 %                                                                             %
727 +   D e s t r o y C u s t o m S t r e a m I n f o                             %
728 %                                                                             %
729 %                                                                             %
730 %                                                                             %
731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
732 %
733 %  DestroyCustomStreamInfo() destroys memory associated with the
734 %  CustomStreamInfo structure.
735 %
736 %  The format of the DestroyCustomStreamInfo method is:
737 %
738 %      CustomStreamInfo *DestroyCustomStreamInfo(CustomStreamInfo *stream_info)
739 %
740 %  A description of each parameter follows:
741 %
742 %    o custom_stream: the custom stream info.
743 %
744 */
745 MagickExport CustomStreamInfo *DestroyCustomStreamInfo(
746   CustomStreamInfo *custom_stream)
747 {
748   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
749   assert(custom_stream != (CustomStreamInfo *) NULL);
750   assert(custom_stream->signature == MagickCoreSignature);
751   custom_stream->signature=(~MagickCoreSignature);
752   custom_stream=(CustomStreamInfo *) RelinquishMagickMemory(custom_stream);
753   return(custom_stream);
754 }
755 \f
756 /*
757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758 %                                                                             %
759 %                                                                             %
760 %                                                                             %
761 +   D e t a c h B l o b                                                       %
762 %                                                                             %
763 %                                                                             %
764 %                                                                             %
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 %
767 %  DetachBlob() detaches a blob from the BlobInfo structure.
768 %
769 %  The format of the DetachBlob method is:
770 %
771 %      void *DetachBlob(BlobInfo *blob_info)
772 %
773 %  A description of each parameter follows:
774 %
775 %    o blob_info: Specifies a pointer to a BlobInfo structure.
776 %
777 */
778 MagickExport void *DetachBlob(BlobInfo *blob_info)
779 {
780   void
781     *data;
782
783   assert(blob_info != (BlobInfo *) NULL);
784   if (blob_info->debug != MagickFalse)
785     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
786   if (blob_info->mapped != MagickFalse)
787     {
788       (void) UnmapBlob(blob_info->data,blob_info->length);
789       blob_info->data=(unsigned char *) NULL;
790       RelinquishMagickResource(MapResource,blob_info->length);
791     }
792   blob_info->mapped=MagickFalse;
793   blob_info->length=0;
794   blob_info->offset=0;
795   blob_info->eof=MagickFalse;
796   blob_info->exempt=MagickFalse;
797   blob_info->type=UndefinedStream;
798   blob_info->file_info.file=(FILE *) NULL;
799   data=blob_info->data;
800   blob_info->data=(unsigned char *) NULL;
801   blob_info->stream=(StreamHandler) NULL;
802   blob_info->custom_stream=(CustomStreamInfo *) NULL;
803   return(data);
804 }
805 \f
806 /*
807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808 %                                                                             %
809 %                                                                             %
810 %                                                                             %
811 +   D i s a s s o c i a t e B l o b                                           %
812 %                                                                             %
813 %                                                                             %
814 %                                                                             %
815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816 %
817 %  DisassociateBlob() disassociates the image stream.  It checks if the
818 %  blob of the specified image is referenced by other images. If the reference
819 %  count is higher then 1 a new blob is assigned to the specified image.
820 %
821 %  The format of the DisassociateBlob method is:
822 %
823 %      void DisassociateBlob(const Image *image)
824 %
825 %  A description of each parameter follows:
826 %
827 %    o image: the image.
828 %
829 */
830 MagickExport void DisassociateBlob(Image *image)
831 {
832   BlobInfo
833     *blob;
834
835   MagickBooleanType
836     clone;
837
838   assert(image != (Image *) NULL);
839   assert(image->signature == MagickCoreSignature);
840   if (image->debug != MagickFalse)
841     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
842   assert(image->blob != (BlobInfo *) NULL);
843   assert(image->blob->signature == MagickCoreSignature);
844   clone=MagickFalse;
845   LockSemaphoreInfo(image->blob->semaphore);
846   assert(image->blob->reference_count >= 0);
847   if (image->blob->reference_count > 1)
848     clone=MagickTrue;
849   UnlockSemaphoreInfo(image->blob->semaphore);
850   if (clone == MagickFalse)
851     return;
852   blob=CloneBlobInfo(image->blob);
853   DestroyBlob(image);
854   image->blob=blob;
855 }
856 \f
857 /*
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 %                                                                             %
860 %                                                                             %
861 %                                                                             %
862 +  D i s c a r d B l o b B y t e s                                            %
863 %                                                                             %
864 %                                                                             %
865 %                                                                             %
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 %
868 %  DiscardBlobBytes() discards bytes in a blob.
869 %
870 %  The format of the DiscardBlobBytes method is:
871 %
872 %      MagickBooleanType DiscardBlobBytes(Image *image,
873 %        const MagickSizeType length)
874 %
875 %  A description of each parameter follows.
876 %
877 %    o image: the image.
878 %
879 %    o length:  the number of bytes to skip.
880 %
881 */
882 MagickExport MagickBooleanType DiscardBlobBytes(Image *image,
883   const MagickSizeType length)
884 {
885   register MagickOffsetType
886     i;
887
888   size_t
889     quantum;
890
891   ssize_t
892     count;
893
894   unsigned char
895     buffer[16384];
896
897   assert(image != (Image *) NULL);
898   assert(image->signature == MagickCoreSignature);
899   if (length != (MagickSizeType) ((MagickOffsetType) length))
900     return(MagickFalse);
901   count=0;
902   for (i=0; i < (MagickOffsetType) length; i+=count)
903   {
904     quantum=(size_t) MagickMin(length-i,sizeof(buffer));
905     (void) ReadBlobStream(image,quantum,buffer,&count);
906     if (count <= 0)
907       {
908         count=0;
909         if (errno != EINTR)
910           break;
911       }
912   }
913   return(i < (MagickOffsetType) length ? MagickFalse : MagickTrue);
914 }
915 \f
916 /*
917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918 %                                                                             %
919 %                                                                             %
920 %                                                                             %
921 +   D u p l i c a t e s B l o b                                               %
922 %                                                                             %
923 %                                                                             %
924 %                                                                             %
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926 %
927 %  DuplicateBlob() duplicates a blob descriptor.
928 %
929 %  The format of the DuplicateBlob method is:
930 %
931 %      void DuplicateBlob(Image *image,const Image *duplicate)
932 %
933 %  A description of each parameter follows:
934 %
935 %    o image: the image.
936 %
937 %    o duplicate: the duplicate image.
938 %
939 */
940 MagickExport void DuplicateBlob(Image *image,const Image *duplicate)
941 {
942   assert(image != (Image *) NULL);
943   assert(image->signature == MagickCoreSignature);
944   if (image->debug != MagickFalse)
945     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
946   assert(duplicate != (Image *) NULL);
947   assert(duplicate->signature == MagickCoreSignature);
948   DestroyBlob(image);
949   image->blob=ReferenceBlob(duplicate->blob);
950 }
951 \f
952 /*
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954 %                                                                             %
955 %                                                                             %
956 %                                                                             %
957 +  E O F B l o b                                                              %
958 %                                                                             %
959 %                                                                             %
960 %                                                                             %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 %
963 %  EOFBlob() returns a non-zero value when EOF has been detected reading from
964 %  a blob or file.
965 %
966 %  The format of the EOFBlob method is:
967 %
968 %      int EOFBlob(const Image *image)
969 %
970 %  A description of each parameter follows:
971 %
972 %    o image: the image.
973 %
974 */
975 MagickExport int EOFBlob(const Image *image)
976 {
977   assert(image != (Image *) NULL);
978   assert(image->signature == MagickCoreSignature);
979   if (image->debug != MagickFalse)
980     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
981   assert(image->blob != (BlobInfo *) NULL);
982   assert(image->blob->type != UndefinedStream);
983   switch (image->blob->type)
984   {
985     case UndefinedStream:
986     case StandardStream:
987       break;
988     case FileStream:
989     case PipeStream:
990     {
991       image->blob->eof=feof(image->blob->file_info.file) != 0 ? MagickTrue :
992         MagickFalse;
993       break;
994     }
995     case ZipStream:
996     {
997       image->blob->eof=MagickFalse;
998       break;
999     }
1000     case BZipStream:
1001     {
1002 #if defined(MAGICKCORE_BZLIB_DELEGATE)
1003       int
1004         status;
1005
1006       status=0;
1007       (void) BZ2_bzerror(image->blob->file_info.bzfile,&status);
1008       image->blob->eof=status == BZ_UNEXPECTED_EOF ? MagickTrue : MagickFalse;
1009 #endif
1010       break;
1011     }
1012     case FifoStream:
1013     {
1014       image->blob->eof=MagickFalse;
1015       break;
1016     }
1017     case BlobStream:
1018       break;
1019     case CustomStream:
1020       break;
1021   }
1022   return((int) image->blob->eof);
1023 }
1024 \f
1025 /*
1026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1027 %                                                                             %
1028 %                                                                             %
1029 %                                                                             %
1030 %   F i l e T o B l o b                                                       %
1031 %                                                                             %
1032 %                                                                             %
1033 %                                                                             %
1034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1035 %
1036 %  FileToBlob() returns the contents of a file as a buffer terminated with
1037 %  the '\0' character.  The length of the buffer (not including the extra
1038 %  terminating '\0' character) is returned via the 'length' parameter.  Free
1039 %  the buffer with RelinquishMagickMemory().
1040 %
1041 %  The format of the FileToBlob method is:
1042 %
1043 %      void *FileToBlob(const char *filename,const size_t extent,
1044 %        size_t *length,ExceptionInfo *exception)
1045 %
1046 %  A description of each parameter follows:
1047 %
1048 %    o blob:  FileToBlob() returns the contents of a file as a blob.  If
1049 %      an error occurs NULL is returned.
1050 %
1051 %    o filename: the filename.
1052 %
1053 %    o extent:  The maximum length of the blob.
1054 %
1055 %    o length: On return, this reflects the actual length of the blob.
1056 %
1057 %    o exception: return any errors or warnings in this structure.
1058 %
1059 */
1060 MagickExport void *FileToBlob(const char *filename,const size_t extent,
1061   size_t *length,ExceptionInfo *exception)
1062 {
1063   int
1064     file;
1065
1066   MagickOffsetType
1067     offset;
1068
1069   register size_t
1070     i;
1071
1072   ssize_t
1073     count;
1074
1075   unsigned char
1076     *blob;
1077
1078   void
1079     *map;
1080
1081   assert(filename != (const char *) NULL);
1082   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1083   assert(exception != (ExceptionInfo *) NULL);
1084   *length=0;
1085   file=fileno(stdin);
1086   if (LocaleCompare(filename,"-") != 0)
1087     file=open_utf8(filename,O_RDONLY | O_BINARY,0);
1088   if (file == -1)
1089     {
1090       ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
1091       return(NULL);
1092     }
1093   offset=(MagickOffsetType) lseek(file,0,SEEK_END);
1094   count=0;
1095   if ((file == fileno(stdin)) || (offset < 0) ||
1096       (offset != (MagickOffsetType) ((ssize_t) offset)))
1097     {
1098       size_t
1099         quantum;
1100
1101       struct stat
1102         file_stats;
1103
1104       /*
1105         Stream is not seekable.
1106       */
1107       offset=(MagickOffsetType) lseek(file,0,SEEK_SET);
1108       quantum=(size_t) MagickMaxBufferExtent;
1109       if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1110         quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1111       blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
1112       for (i=0; blob != (unsigned char *) NULL; i+=count)
1113       {
1114         count=read(file,blob+i,quantum);
1115         if (count <= 0)
1116           {
1117             count=0;
1118             if (errno != EINTR)
1119               break;
1120           }
1121         if (~((size_t) i) < (quantum+1))
1122           {
1123             blob=(unsigned char *) RelinquishMagickMemory(blob);
1124             break;
1125           }
1126         blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
1127           sizeof(*blob));
1128         if ((size_t) (i+count) >= extent)
1129           break;
1130       }
1131       if (LocaleCompare(filename,"-") != 0)
1132         file=close(file);
1133       if (blob == (unsigned char *) NULL)
1134         {
1135           (void) ThrowMagickException(exception,GetMagickModule(),
1136             ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1137           return(NULL);
1138         }
1139       if (file == -1)
1140         {
1141           blob=(unsigned char *) RelinquishMagickMemory(blob);
1142           ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1143           return(NULL);
1144         }
1145       *length=(size_t) MagickMin(i+count,extent);
1146       blob[*length]='\0';
1147       return(blob);
1148     }
1149   *length=(size_t) MagickMin(offset,(MagickOffsetType)
1150     MagickMin(extent,SSIZE_MAX));
1151   blob=(unsigned char *) NULL;
1152   if (~(*length) >= (MagickPathExtent-1))
1153     blob=(unsigned char *) AcquireQuantumMemory(*length+MagickPathExtent,
1154       sizeof(*blob));
1155   if (blob == (unsigned char *) NULL)
1156     {
1157       file=close(file);
1158       (void) ThrowMagickException(exception,GetMagickModule(),
1159         ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1160       return(NULL);
1161     }
1162   map=MapBlob(file,ReadMode,0,*length);
1163   if (map != (unsigned char *) NULL)
1164     {
1165       (void) memcpy(blob,map,*length);
1166       (void) UnmapBlob(map,*length);
1167     }
1168   else
1169     {
1170       (void) lseek(file,0,SEEK_SET);
1171       for (i=0; i < *length; i+=count)
1172       {
1173         count=read(file,blob+i,(size_t) MagickMin(*length-i,SSIZE_MAX));
1174         if (count <= 0)
1175           {
1176             count=0;
1177             if (errno != EINTR)
1178               break;
1179           }
1180       }
1181       if (i < *length)
1182         {
1183           file=close(file)-1;
1184           blob=(unsigned char *) RelinquishMagickMemory(blob);
1185           ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1186           return(NULL);
1187         }
1188     }
1189   blob[*length]='\0';
1190   if (LocaleCompare(filename,"-") != 0)
1191     file=close(file);
1192   if (file == -1)
1193     {
1194       blob=(unsigned char *) RelinquishMagickMemory(blob);
1195       ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1196     }
1197   return(blob);
1198 }
1199 \f
1200 /*
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1202 %                                                                             %
1203 %                                                                             %
1204 %                                                                             %
1205 %   F i l e T o I m a g e                                                     %
1206 %                                                                             %
1207 %                                                                             %
1208 %                                                                             %
1209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1210 %
1211 %  FileToImage() write the contents of a file to an image.
1212 %
1213 %  The format of the FileToImage method is:
1214 %
1215 %      MagickBooleanType FileToImage(Image *,const char *filename)
1216 %
1217 %  A description of each parameter follows:
1218 %
1219 %    o image: the image.
1220 %
1221 %    o filename: the filename.
1222 %
1223 */
1224
1225 static inline ssize_t WriteBlobStream(Image *image,const size_t length,
1226   const void *data)
1227 {
1228   MagickSizeType
1229     extent;
1230
1231   register unsigned char
1232     *q;
1233
1234   assert(image->blob != (BlobInfo *) NULL);
1235   assert(image->blob->type != UndefinedStream);
1236   assert(data != NULL);
1237   if (image->blob->type != BlobStream)
1238     return(WriteBlob(image,length,(const unsigned char *) data));
1239   extent=(MagickSizeType) (image->blob->offset+(MagickOffsetType) length);
1240   if (extent >= image->blob->extent)
1241     {
1242       extent=image->blob->extent+image->blob->quantum+length;
1243       image->blob->quantum<<=1;
1244       if (SetBlobExtent(image,extent) == MagickFalse)
1245         return(0);
1246     }
1247   q=image->blob->data+image->blob->offset;
1248   (void) memcpy(q,data,length);
1249   image->blob->offset+=length;
1250   if (image->blob->offset >= (MagickOffsetType) image->blob->length)
1251     image->blob->length=(size_t) image->blob->offset;
1252   return((ssize_t) length);
1253 }
1254
1255 MagickExport MagickBooleanType FileToImage(Image *image,const char *filename,
1256   ExceptionInfo *exception)
1257 {
1258   int
1259     file;
1260
1261   size_t
1262     length,
1263     quantum;
1264
1265   ssize_t
1266     count;
1267
1268   struct stat
1269     file_stats;
1270
1271   unsigned char
1272     *blob;
1273
1274   assert(image != (const Image *) NULL);
1275   assert(image->signature == MagickCoreSignature);
1276   assert(filename != (const char *) NULL);
1277   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1278   file=fileno(stdin);
1279   if (LocaleCompare(filename,"-") != 0)
1280     file=open_utf8(filename,O_RDONLY | O_BINARY,0);
1281   if (file == -1)
1282     {
1283       ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
1284       return(MagickFalse);
1285     }
1286   quantum=(size_t) MagickMaxBufferExtent;
1287   if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1288     quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1289   blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
1290   if (blob == (unsigned char *) NULL)
1291     {
1292       file=close(file);
1293       ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
1294         filename);
1295       return(MagickFalse);
1296     }
1297   for ( ; ; )
1298   {
1299     count=read(file,blob,quantum);
1300     if (count <= 0)
1301       {
1302         count=0;
1303         if (errno != EINTR)
1304           break;
1305       }
1306     length=(size_t) count;
1307     count=WriteBlobStream(image,length,blob);
1308     if (count != (ssize_t) length)
1309       {
1310         ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1311         break;
1312       }
1313   }
1314   file=close(file);
1315   if (file == -1)
1316     ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1317   blob=(unsigned char *) RelinquishMagickMemory(blob);
1318   return(MagickTrue);
1319 }
1320 \f
1321 /*
1322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323 %                                                                             %
1324 %                                                                             %
1325 %                                                                             %
1326 +   G e t B l o b E r r o r                                                   %
1327 %                                                                             %
1328 %                                                                             %
1329 %                                                                             %
1330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1331 %
1332 %  GetBlobError() returns MagickTrue if the blob associated with the specified
1333 %  image encountered an error.
1334 %
1335 %  The format of the GetBlobError method is:
1336 %
1337 %       MagickBooleanType GetBlobError(const Image *image)
1338 %
1339 %  A description of each parameter follows:
1340 %
1341 %    o image: the image.
1342 %
1343 */
1344 MagickExport MagickBooleanType GetBlobError(const Image *image)
1345 {
1346   assert(image != (const Image *) NULL);
1347   assert(image->signature == MagickCoreSignature);
1348   if (image->debug != MagickFalse)
1349     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1350   return(image->blob->status);
1351 }
1352 \f
1353 /*
1354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355 %                                                                             %
1356 %                                                                             %
1357 %                                                                             %
1358 +   G e t B l o b F i l e H a n d l e                                         %
1359 %                                                                             %
1360 %                                                                             %
1361 %                                                                             %
1362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363 %
1364 %  GetBlobFileHandle() returns the file handle associated with the image blob.
1365 %
1366 %  The format of the GetBlobFile method is:
1367 %
1368 %      FILE *GetBlobFileHandle(const Image *image)
1369 %
1370 %  A description of each parameter follows:
1371 %
1372 %    o image: the image.
1373 %
1374 */
1375 MagickExport FILE *GetBlobFileHandle(const Image *image)
1376 {
1377   assert(image != (const Image *) NULL);
1378   assert(image->signature == MagickCoreSignature);
1379   return(image->blob->file_info.file);
1380 }
1381 \f
1382 /*
1383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1384 %                                                                             %
1385 %                                                                             %
1386 %                                                                             %
1387 +   G e t B l o b I n f o                                                     %
1388 %                                                                             %
1389 %                                                                             %
1390 %                                                                             %
1391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 %
1393 %  GetBlobInfo() initializes the BlobInfo structure.
1394 %
1395 %  The format of the GetBlobInfo method is:
1396 %
1397 %      void GetBlobInfo(BlobInfo *blob_info)
1398 %
1399 %  A description of each parameter follows:
1400 %
1401 %    o blob_info: Specifies a pointer to a BlobInfo structure.
1402 %
1403 */
1404 MagickExport void GetBlobInfo(BlobInfo *blob_info)
1405 {
1406   assert(blob_info != (BlobInfo *) NULL);
1407   (void) ResetMagickMemory(blob_info,0,sizeof(*blob_info));
1408   blob_info->type=UndefinedStream;
1409   blob_info->quantum=(size_t) MagickMaxBlobExtent;
1410   blob_info->properties.st_mtime=time((time_t *) NULL);
1411   blob_info->properties.st_ctime=time((time_t *) NULL);
1412   blob_info->debug=IsEventLogging();
1413   blob_info->reference_count=1;
1414   blob_info->semaphore=AcquireSemaphoreInfo();
1415   blob_info->signature=MagickCoreSignature;
1416 }
1417 \f
1418 /*
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 %                                                                             %
1421 %                                                                             %
1422 %                                                                             %
1423 %  G e t B l o b P r o p e r t i e s                                          %
1424 %                                                                             %
1425 %                                                                             %
1426 %                                                                             %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 %
1429 %  GetBlobProperties() returns information about an image blob.
1430 %
1431 %  The format of the GetBlobProperties method is:
1432 %
1433 %      const struct stat *GetBlobProperties(const Image *image)
1434 %
1435 %  A description of each parameter follows:
1436 %
1437 %    o image: the image.
1438 %
1439 */
1440 MagickExport const struct stat *GetBlobProperties(const Image *image)
1441 {
1442   assert(image != (Image *) NULL);
1443   assert(image->signature == MagickCoreSignature);
1444   if (image->debug != MagickFalse)
1445     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1446   return(&image->blob->properties);
1447 }
1448 \f
1449 /*
1450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1451 %                                                                             %
1452 %                                                                             %
1453 %                                                                             %
1454 +  G e t B l o b S i z e                                                      %
1455 %                                                                             %
1456 %                                                                             %
1457 %                                                                             %
1458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459 %
1460 %  GetBlobSize() returns the current length of the image file or blob; zero is
1461 %  returned if the size cannot be determined.
1462 %
1463 %  The format of the GetBlobSize method is:
1464 %
1465 %      MagickSizeType GetBlobSize(const Image *image)
1466 %
1467 %  A description of each parameter follows:
1468 %
1469 %    o image: the image.
1470 %
1471 */
1472 MagickExport MagickSizeType GetBlobSize(const Image *image)
1473 {
1474   MagickSizeType
1475     extent;
1476
1477   assert(image != (Image *) NULL);
1478   assert(image->signature == MagickCoreSignature);
1479   if (image->debug != MagickFalse)
1480     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1481   assert(image->blob != (BlobInfo *) NULL);
1482   extent=0;
1483   switch (image->blob->type)
1484   {
1485     case UndefinedStream:
1486     case StandardStream:
1487     {
1488       extent=image->blob->size;
1489       break;
1490     }
1491     case FileStream:
1492     {
1493       if (fstat(fileno(image->blob->file_info.file),&image->blob->properties) == 0)
1494         extent=(MagickSizeType) image->blob->properties.st_size;
1495       break;
1496     }
1497     case PipeStream:
1498     {
1499       extent=image->blob->size;
1500       break;
1501     }
1502     case ZipStream:
1503     case BZipStream:
1504     {
1505       MagickBooleanType
1506         status;
1507
1508       status=GetPathAttributes(image->filename,&image->blob->properties);
1509       if (status != MagickFalse)
1510         extent=(MagickSizeType) image->blob->properties.st_size;
1511       break;
1512     }
1513     case FifoStream:
1514       break;
1515     case BlobStream:
1516     {
1517       extent=(MagickSizeType) image->blob->length;
1518       break;
1519     }
1520     case CustomStream:
1521       break;
1522   }
1523   return(extent);
1524 }
1525 \f
1526 /*
1527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 %                                                                             %
1529 %                                                                             %
1530 %                                                                             %
1531 +   G e t B l o b S t r e a m D a t a                                         %
1532 %                                                                             %
1533 %                                                                             %
1534 %                                                                             %
1535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 %
1537 %  GetBlobStreamData() returns the stream data for the image.
1538 %
1539 %  The format of the GetBlobStreamData method is:
1540 %
1541 %      void *GetBlobStreamData(const Image *image)
1542 %
1543 %  A description of each parameter follows:
1544 %
1545 %    o image: the image.
1546 %
1547 */
1548 MagickExport void *GetBlobStreamData(const Image *image)
1549 {
1550   assert(image != (const Image *) NULL);
1551   assert(image->signature == MagickCoreSignature);
1552   return(image->blob->data);
1553 }
1554 \f
1555 /*
1556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557 %                                                                             %
1558 %                                                                             %
1559 %                                                                             %
1560 +   G e t B l o b S t r e a m H a n d l e r                                   %
1561 %                                                                             %
1562 %                                                                             %
1563 %                                                                             %
1564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565 %
1566 %  GetBlobStreamHandler() returns the stream handler for the image.
1567 %
1568 %  The format of the GetBlobStreamHandler method is:
1569 %
1570 %      StreamHandler GetBlobStreamHandler(const Image *image)
1571 %
1572 %  A description of each parameter follows:
1573 %
1574 %    o image: the image.
1575 %
1576 */
1577 MagickExport StreamHandler GetBlobStreamHandler(const Image *image)
1578 {
1579   assert(image != (const Image *) NULL);
1580   assert(image->signature == MagickCoreSignature);
1581   if (image->debug != MagickFalse)
1582     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1583   return(image->blob->stream);
1584 }
1585 \f
1586 /*
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 %                                                                             %
1589 %                                                                             %
1590 %                                                                             %
1591 %   I m a g e T o B l o b                                                     %
1592 %                                                                             %
1593 %                                                                             %
1594 %                                                                             %
1595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 %
1597 %  ImageToBlob() implements direct to memory image formats.  It returns the
1598 %  image as a formatted blob and its length.  The magick member of the Image
1599 %  structure determines the format of the returned blob (GIF, JPEG, PNG,
1600 %  etc.).  This method is the equivalent of WriteImage(), but writes the
1601 %  formatted "file" to a memory buffer rather than to an actual file.
1602 %
1603 %  The format of the ImageToBlob method is:
1604 %
1605 %      void *ImageToBlob(const ImageInfo *image_info,Image *image,
1606 %        size_t *length,ExceptionInfo *exception)
1607 %
1608 %  A description of each parameter follows:
1609 %
1610 %    o image_info: the image info.
1611 %
1612 %    o image: the image.
1613 %
1614 %    o length: return the actual length of the blob.
1615 %
1616 %    o exception: return any errors or warnings in this structure.
1617 %
1618 */
1619 MagickExport void *ImageToBlob(const ImageInfo *image_info,
1620   Image *image,size_t *length,ExceptionInfo *exception)
1621 {
1622   const MagickInfo
1623     *magick_info;
1624
1625   ImageInfo
1626     *blob_info;
1627
1628   MagickBooleanType
1629     status;
1630
1631   void
1632     *blob;
1633
1634   assert(image_info != (const ImageInfo *) NULL);
1635   assert(image_info->signature == MagickCoreSignature);
1636   if (image_info->debug != MagickFalse)
1637     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1638       image_info->filename);
1639   assert(image != (Image *) NULL);
1640   assert(image->signature == MagickCoreSignature);
1641   assert(exception != (ExceptionInfo *) NULL);
1642   *length=0;
1643   blob=(unsigned char *) NULL;
1644   blob_info=CloneImageInfo(image_info);
1645   blob_info->adjoin=MagickFalse;
1646   (void) SetImageInfo(blob_info,1,exception);
1647   if (*blob_info->magick != '\0')
1648     (void) CopyMagickString(image->magick,blob_info->magick,MagickPathExtent);
1649   magick_info=GetMagickInfo(image->magick,exception);
1650   if (magick_info == (const MagickInfo *) NULL)
1651     {
1652       (void) ThrowMagickException(exception,GetMagickModule(),
1653         MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
1654         image->magick);
1655       blob_info=DestroyImageInfo(blob_info);
1656       return(blob);
1657     }
1658   (void) CopyMagickString(blob_info->magick,image->magick,MagickPathExtent);
1659   if (GetMagickBlobSupport(magick_info) != MagickFalse)
1660     {
1661       /*
1662         Native blob support for this image format.
1663       */
1664       blob_info->length=0;
1665       blob_info->blob=AcquireQuantumMemory(MagickMaxBlobExtent,
1666         sizeof(unsigned char));
1667       if (blob_info->blob == NULL)
1668         (void) ThrowMagickException(exception,GetMagickModule(),
1669           ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1670       else
1671         {
1672           (void) CloseBlob(image);
1673           image->blob->exempt=MagickTrue;
1674           *image->filename='\0';
1675           status=WriteImage(blob_info,image,exception);
1676           *length=image->blob->length;
1677           blob=DetachBlob(image->blob);
1678           if (status == MagickFalse)
1679             blob=RelinquishMagickMemory(blob);
1680           else
1681             blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
1682         }
1683     }
1684   else
1685     {
1686       char
1687         unique[MagickPathExtent];
1688
1689       int
1690         file;
1691
1692       /*
1693         Write file to disk in blob image format.
1694       */
1695       file=AcquireUniqueFileResource(unique);
1696       if (file == -1)
1697         {
1698           ThrowFileException(exception,BlobError,"UnableToWriteBlob",
1699             image_info->filename);
1700         }
1701       else
1702         {
1703           blob_info->file=fdopen(file,"wb");
1704           if (blob_info->file != (FILE *) NULL)
1705             {
1706               (void) FormatLocaleString(image->filename,MagickPathExtent,
1707                 "%s:%s",image->magick,unique);
1708               status=WriteImage(blob_info,image,exception);
1709               (void) CloseBlob(image);
1710               (void) fclose(blob_info->file);
1711               if (status != MagickFalse)
1712                 blob=FileToBlob(unique,~0UL,length,exception);
1713             }
1714           (void) RelinquishUniqueFileResource(unique);
1715         }
1716     }
1717   blob_info=DestroyImageInfo(blob_info);
1718   return(blob);
1719 }
1720 \f
1721 /*
1722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1723 %                                                                             %
1724 %                                                                             %
1725 %                                                                             %
1726 +  I m a g e T o C u s t o m S t r e a m                                      %
1727 %                                                                             %
1728 %                                                                             %
1729 %                                                                             %
1730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731 %
1732 %  ImageToCustomStream() is the equivalent of WriteImage(), but writes the
1733 %  formatted "file" to the custom stream rather than to an actual file.
1734 %
1735 %  The format of the ImageToCustomStream method is:
1736 %
1737 %      void ImageToCustomStream(const ImageInfo *image_info,Image *image,
1738 %        ExceptionInfo *exception)
1739 %
1740 %  A description of each parameter follows:
1741 %
1742 %    o image_info: the image info.
1743 %
1744 %    o image: the image.
1745 %
1746 %    o exception: return any errors or warnings in this structure.
1747 %
1748 */
1749 MagickExport void ImageToCustomStream(const ImageInfo *image_info,Image *image,
1750   ExceptionInfo *exception)
1751 {
1752   const MagickInfo
1753     *magick_info;
1754
1755   ImageInfo
1756     *blob_info;
1757
1758   MagickBooleanType
1759     status;
1760
1761   assert(image_info != (const ImageInfo *) NULL);
1762   assert(image_info->signature == MagickCoreSignature);
1763   if (image_info->debug != MagickFalse)
1764     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1765       image_info->filename);
1766   assert(image != (Image *) NULL);
1767   assert(image->signature == MagickCoreSignature);
1768   assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
1769   assert(image_info->custom_stream->signature == MagickCoreSignature);
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       if (image->blob->custom_stream->reader != (CustomStreamHandler) NULL)
3370         count=image->blob->custom_stream->reader(q,length,
3371           image->blob->custom_stream->data);
3372       break;
3373     }
3374   }
3375   return(count);
3376 }
3377 \f
3378 /*
3379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3380 %                                                                             %
3381 %                                                                             %
3382 %                                                                             %
3383 +  R e a d B l o b B y t e                                                    %
3384 %                                                                             %
3385 %                                                                             %
3386 %                                                                             %
3387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3388 %
3389 %  ReadBlobByte() reads a single byte from the image file and returns it.
3390 %
3391 %  The format of the ReadBlobByte method is:
3392 %
3393 %      int ReadBlobByte(Image *image)
3394 %
3395 %  A description of each parameter follows.
3396 %
3397 %    o image: the image.
3398 %
3399 */
3400 MagickExport int ReadBlobByte(Image *image)
3401 {
3402   register const unsigned char
3403     *p;
3404
3405   ssize_t
3406     count;
3407
3408   unsigned char
3409     buffer[1];
3410
3411   assert(image != (Image *) NULL);
3412   assert(image->signature == MagickCoreSignature);
3413   p=(const unsigned char *) ReadBlobStream(image,1,buffer,&count);
3414   if (count != 1)
3415     return(EOF);
3416   return((int) (*p));
3417 }
3418 \f
3419 /*
3420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3421 %                                                                             %
3422 %                                                                             %
3423 %                                                                             %
3424 +  R e a d B l o b D o u b l e                                                %
3425 %                                                                             %
3426 %                                                                             %
3427 %                                                                             %
3428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3429 %
3430 %  ReadBlobDouble() reads a double value as a 64-bit quantity in the byte-order
3431 %  specified by the endian member of the image structure.
3432 %
3433 %  The format of the ReadBlobDouble method is:
3434 %
3435 %      double ReadBlobDouble(Image *image)
3436 %
3437 %  A description of each parameter follows.
3438 %
3439 %    o image: the image.
3440 %
3441 */
3442 MagickExport double ReadBlobDouble(Image *image)
3443 {
3444   union
3445   {
3446     MagickSizeType
3447       unsigned_value;
3448
3449     double
3450       double_value;
3451   } quantum;
3452
3453   quantum.double_value=0.0;
3454   quantum.unsigned_value=ReadBlobLongLong(image);
3455   return(quantum.double_value);
3456 }
3457 \f
3458 /*
3459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3460 %                                                                             %
3461 %                                                                             %
3462 %                                                                             %
3463 +  R e a d B l o b F l o a t                                                  %
3464 %                                                                             %
3465 %                                                                             %
3466 %                                                                             %
3467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3468 %
3469 %  ReadBlobFloat() reads a float value as a 32-bit quantity in the byte-order
3470 %  specified by the endian member of the image structure.
3471 %
3472 %  The format of the ReadBlobFloat method is:
3473 %
3474 %      float ReadBlobFloat(Image *image)
3475 %
3476 %  A description of each parameter follows.
3477 %
3478 %    o image: the image.
3479 %
3480 */
3481 MagickExport float ReadBlobFloat(Image *image)
3482 {
3483   union
3484   {
3485     unsigned int
3486       unsigned_value;
3487
3488     float
3489       float_value;
3490   } quantum;
3491
3492   quantum.float_value=0.0;
3493   quantum.unsigned_value=ReadBlobLong(image);
3494   return(quantum.float_value);
3495 }
3496 \f
3497 /*
3498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3499 %                                                                             %
3500 %                                                                             %
3501 %                                                                             %
3502 +  R e a d B l o b L o n g                                                    %
3503 %                                                                             %
3504 %                                                                             %
3505 %                                                                             %
3506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507 %
3508 %  ReadBlobLong() reads a unsigned int value as a 32-bit quantity in the
3509 %  byte-order specified by the endian member of the image structure.
3510 %
3511 %  The format of the ReadBlobLong method is:
3512 %
3513 %      unsigned int ReadBlobLong(Image *image)
3514 %
3515 %  A description of each parameter follows.
3516 %
3517 %    o image: the image.
3518 %
3519 */
3520 MagickExport unsigned int ReadBlobLong(Image *image)
3521 {
3522   register const unsigned char
3523     *p;
3524
3525   ssize_t
3526     count;
3527
3528   unsigned char
3529     buffer[4];
3530
3531   unsigned int
3532     value;
3533
3534   assert(image != (Image *) NULL);
3535   assert(image->signature == MagickCoreSignature);
3536   *buffer='\0';
3537   p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
3538   if (count != 4)
3539     return(0UL);
3540   if (image->endian == LSBEndian)
3541     {
3542       value=(unsigned int) (*p++);
3543       value|=(unsigned int) (*p++) << 8;
3544       value|=(unsigned int) (*p++) << 16;
3545       value|=(unsigned int) (*p++) << 24;
3546       return(value & 0xffffffff);
3547     }
3548   value=(unsigned int) (*p++) << 24;
3549   value|=(unsigned int) (*p++) << 16;
3550   value|=(unsigned int) (*p++) << 8;
3551   value|=(unsigned int) (*p++);
3552   return(value & 0xffffffff);
3553 }
3554 \f
3555 /*
3556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3557 %                                                                             %
3558 %                                                                             %
3559 %                                                                             %
3560 +  R e a d B l o b L o n g L o n g                                            %
3561 %                                                                             %
3562 %                                                                             %
3563 %                                                                             %
3564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565 %
3566 %  ReadBlobLongLong() reads a long long value as a 64-bit quantity in the
3567 %  byte-order specified by the endian member of the image structure.
3568 %
3569 %  The format of the ReadBlobLongLong method is:
3570 %
3571 %      MagickSizeType ReadBlobLongLong(Image *image)
3572 %
3573 %  A description of each parameter follows.
3574 %
3575 %    o image: the image.
3576 %
3577 */
3578 MagickExport MagickSizeType ReadBlobLongLong(Image *image)
3579 {
3580   MagickSizeType
3581     value;
3582
3583   register const unsigned char
3584     *p;
3585
3586   ssize_t
3587     count;
3588
3589   unsigned char
3590     buffer[8];
3591
3592   assert(image != (Image *) NULL);
3593   assert(image->signature == MagickCoreSignature);
3594   *buffer='\0';
3595   p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
3596   if (count != 8)
3597     return(MagickULLConstant(0));
3598   if (image->endian == LSBEndian)
3599     {
3600       value=(MagickSizeType) (*p++);
3601       value|=(MagickSizeType) (*p++) << 8;
3602       value|=(MagickSizeType) (*p++) << 16;
3603       value|=(MagickSizeType) (*p++) << 24;
3604       value|=(MagickSizeType) (*p++) << 32;
3605       value|=(MagickSizeType) (*p++) << 40;
3606       value|=(MagickSizeType) (*p++) << 48;
3607       value|=(MagickSizeType) (*p++) << 56;
3608       return(value & MagickULLConstant(0xffffffffffffffff));
3609     }
3610   value=(MagickSizeType) (*p++) << 56;
3611   value|=(MagickSizeType) (*p++) << 48;
3612   value|=(MagickSizeType) (*p++) << 40;
3613   value|=(MagickSizeType) (*p++) << 32;
3614   value|=(MagickSizeType) (*p++) << 24;
3615   value|=(MagickSizeType) (*p++) << 16;
3616   value|=(MagickSizeType) (*p++) << 8;
3617   value|=(MagickSizeType) (*p++);
3618   return(value & MagickULLConstant(0xffffffffffffffff));
3619 }
3620 \f
3621 /*
3622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3623 %                                                                             %
3624 %                                                                             %
3625 %                                                                             %
3626 +  R e a d B l o b S h o r t                                                  %
3627 %                                                                             %
3628 %                                                                             %
3629 %                                                                             %
3630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3631 %
3632 %  ReadBlobShort() reads a short value as a 16-bit quantity in the byte-order
3633 %  specified by the endian member of the image structure.
3634 %
3635 %  The format of the ReadBlobShort method is:
3636 %
3637 %      unsigned short ReadBlobShort(Image *image)
3638 %
3639 %  A description of each parameter follows.
3640 %
3641 %    o image: the image.
3642 %
3643 */
3644 MagickExport unsigned short ReadBlobShort(Image *image)
3645 {
3646   register const unsigned char
3647     *p;
3648
3649   register unsigned short
3650     value;
3651
3652   ssize_t
3653     count;
3654
3655   unsigned char
3656     buffer[2];
3657
3658   assert(image != (Image *) NULL);
3659   assert(image->signature == MagickCoreSignature);
3660   *buffer='\0';
3661   p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
3662   if (count != 2)
3663     return((unsigned short) 0U);
3664   if (image->endian == LSBEndian)
3665     {
3666       value=(unsigned short) (*p++);
3667       value|=(unsigned short) (*p++) << 8;
3668       return(value);
3669     }
3670   value=(unsigned short) (*p++) << 8;
3671   value|=(unsigned short) (*p++);
3672   return(value);
3673 }
3674 \f
3675 /*
3676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3677 %                                                                             %
3678 %                                                                             %
3679 %                                                                             %
3680 +  R e a d B l o b L S B L o n g                                              %
3681 %                                                                             %
3682 %                                                                             %
3683 %                                                                             %
3684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3685 %
3686 %  ReadBlobLSBLong() reads a unsigned int value as a 32-bit quantity in
3687 %  least-significant byte first order.
3688 %
3689 %  The format of the ReadBlobLSBLong method is:
3690 %
3691 %      unsigned int ReadBlobLSBLong(Image *image)
3692 %
3693 %  A description of each parameter follows.
3694 %
3695 %    o image: the image.
3696 %
3697 */
3698 MagickExport unsigned int ReadBlobLSBLong(Image *image)
3699 {
3700   register const unsigned char
3701     *p;
3702
3703   register unsigned int
3704     value;
3705
3706   ssize_t
3707     count;
3708
3709   unsigned char
3710     buffer[4];
3711
3712   assert(image != (Image *) NULL);
3713   assert(image->signature == MagickCoreSignature);
3714   *buffer='\0';
3715   p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
3716   if (count != 4)
3717     return(0U);
3718   value=(unsigned int) (*p++);
3719   value|=(unsigned int) (*p++) << 8;
3720   value|=(unsigned int) (*p++) << 16;
3721   value|=(unsigned int) (*p++) << 24;
3722   return(value & 0xffffffff);
3723 }
3724 \f
3725 /*
3726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727 %                                                                             %
3728 %                                                                             %
3729 %                                                                             %
3730 +  R e a d B l o b L S B S i g n e d L o n g                                  %
3731 %                                                                             %
3732 %                                                                             %
3733 %                                                                             %
3734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3735 %
3736 %  ReadBlobLSBSignedLong() reads a signed int value as a 32-bit quantity in
3737 %  least-significant byte first order.
3738 %
3739 %  The format of the ReadBlobLSBSignedLong method is:
3740 %
3741 %      signed int ReadBlobLSBSignedLong(Image *image)
3742 %
3743 %  A description of each parameter follows.
3744 %
3745 %    o image: the image.
3746 %
3747 */
3748 MagickExport signed int ReadBlobLSBSignedLong(Image *image)
3749 {
3750   union
3751   {
3752     unsigned int
3753       unsigned_value;
3754
3755     signed int
3756       signed_value;
3757   } quantum;
3758
3759   quantum.unsigned_value=ReadBlobLSBLong(image);
3760   return(quantum.signed_value);
3761 }
3762 \f
3763 /*
3764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765 %                                                                             %
3766 %                                                                             %
3767 %                                                                             %
3768 +  R e a d B l o b L S B S h o r t                                            %
3769 %                                                                             %
3770 %                                                                             %
3771 %                                                                             %
3772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773 %
3774 %  ReadBlobLSBShort() reads a short value as a 16-bit quantity in
3775 %  least-significant byte first order.
3776 %
3777 %  The format of the ReadBlobLSBShort method is:
3778 %
3779 %      unsigned short ReadBlobLSBShort(Image *image)
3780 %
3781 %  A description of each parameter follows.
3782 %
3783 %    o image: the image.
3784 %
3785 */
3786 MagickExport unsigned short ReadBlobLSBShort(Image *image)
3787 {
3788   register const unsigned char
3789     *p;
3790
3791   register unsigned short
3792     value;
3793
3794   ssize_t
3795     count;
3796
3797   unsigned char
3798     buffer[2];
3799
3800   assert(image != (Image *) NULL);
3801   assert(image->signature == MagickCoreSignature);
3802   *buffer='\0';
3803   p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
3804   if (count != 2)
3805     return((unsigned short) 0U);
3806   value=(unsigned int) (*p++);
3807   value|=(unsigned int) (*p++) << 8;
3808   return(value & 0xffff);
3809 }
3810 \f
3811 /*
3812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3813 %                                                                             %
3814 %                                                                             %
3815 %                                                                             %
3816 +  R e a d B l o b L S B S i g n e d S h o r t                                %
3817 %                                                                             %
3818 %                                                                             %
3819 %                                                                             %
3820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3821 %
3822 %  ReadBlobLSBSignedShort() reads a signed short value as a 16-bit quantity in
3823 %  least-significant byte-order.
3824 %
3825 %  The format of the ReadBlobLSBSignedShort method is:
3826 %
3827 %      signed short ReadBlobLSBSignedShort(Image *image)
3828 %
3829 %  A description of each parameter follows.
3830 %
3831 %    o image: the image.
3832 %
3833 */
3834 MagickExport signed short ReadBlobLSBSignedShort(Image *image)
3835 {
3836   union
3837   {
3838     unsigned short
3839       unsigned_value;
3840
3841     signed short
3842       signed_value;
3843   } quantum;
3844
3845   quantum.unsigned_value=ReadBlobLSBShort(image);
3846   return(quantum.signed_value);
3847 }
3848 \f
3849 /*
3850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3851 %                                                                             %
3852 %                                                                             %
3853 %                                                                             %
3854 +  R e a d B l o b M S B L o n g                                              %
3855 %                                                                             %
3856 %                                                                             %
3857 %                                                                             %
3858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3859 %
3860 %  ReadBlobMSBLong() reads a unsigned int value as a 32-bit quantity in
3861 %  most-significant byte first order.
3862 %
3863 %  The format of the ReadBlobMSBLong method is:
3864 %
3865 %      unsigned int ReadBlobMSBLong(Image *image)
3866 %
3867 %  A description of each parameter follows.
3868 %
3869 %    o image: the image.
3870 %
3871 */
3872 MagickExport unsigned int ReadBlobMSBLong(Image *image)
3873 {
3874   register const unsigned char
3875     *p;
3876
3877   register unsigned int
3878     value;
3879
3880   ssize_t
3881     count;
3882
3883   unsigned char
3884     buffer[4];
3885
3886   assert(image != (Image *) NULL);
3887   assert(image->signature == MagickCoreSignature);
3888   *buffer='\0';
3889   p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
3890   if (count != 4)
3891     return(0UL);
3892   value=(unsigned int) (*p++) << 24;
3893   value|=(unsigned int) (*p++) << 16;
3894   value|=(unsigned int) (*p++) << 8;
3895   value|=(unsigned int) (*p++);
3896   return(value);
3897 }
3898 \f
3899 /*
3900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3901 %                                                                             %
3902 %                                                                             %
3903 %                                                                             %
3904 +  R e a d B l o b M S B L o n g L o n g                                      %
3905 %                                                                             %
3906 %                                                                             %
3907 %                                                                             %
3908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3909 %
3910 %  ReadBlobMSBLongLong() reads a unsigned long long value as a 64-bit quantity
3911 %  in most-significant byte first order.
3912 %
3913 %  The format of the ReadBlobMSBLongLong method is:
3914 %
3915 %      unsigned int ReadBlobMSBLongLong(Image *image)
3916 %
3917 %  A description of each parameter follows.
3918 %
3919 %    o image: the image.
3920 %
3921 */
3922 MagickExport MagickSizeType ReadBlobMSBLongLong(Image *image)
3923 {
3924   register const unsigned char
3925     *p;
3926
3927   register MagickSizeType
3928     value;
3929
3930   ssize_t
3931     count;
3932
3933   unsigned char
3934     buffer[8];
3935
3936   assert(image != (Image *) NULL);
3937   assert(image->signature == MagickCoreSignature);
3938   *buffer='\0';
3939   p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
3940   if (count != 8)
3941     return(MagickULLConstant(0));
3942   value=(MagickSizeType) (*p++) << 56;
3943   value|=(MagickSizeType) (*p++) << 48;
3944   value|=(MagickSizeType) (*p++) << 40;
3945   value|=(MagickSizeType) (*p++) << 32;
3946   value|=(MagickSizeType) (*p++) << 24;
3947   value|=(MagickSizeType) (*p++) << 16;
3948   value|=(MagickSizeType) (*p++) << 8;
3949   value|=(MagickSizeType) (*p++);
3950   return(value & MagickULLConstant(0xffffffffffffffff));
3951 }
3952 \f
3953 /*
3954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3955 %                                                                             %
3956 %                                                                             %
3957 %                                                                             %
3958 +  R e a d B l o b M S B S h o r t                                            %
3959 %                                                                             %
3960 %                                                                             %
3961 %                                                                             %
3962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3963 %
3964 %  ReadBlobMSBShort() reads a short value as a 16-bit quantity in
3965 %  most-significant byte first order.
3966 %
3967 %  The format of the ReadBlobMSBShort method is:
3968 %
3969 %      unsigned short ReadBlobMSBShort(Image *image)
3970 %
3971 %  A description of each parameter follows.
3972 %
3973 %    o image: the image.
3974 %
3975 */
3976 MagickExport unsigned short ReadBlobMSBShort(Image *image)
3977 {
3978   register const unsigned char
3979     *p;
3980
3981   register unsigned short
3982     value;
3983
3984   ssize_t
3985     count;
3986
3987   unsigned char
3988     buffer[2];
3989
3990   assert(image != (Image *) NULL);
3991   assert(image->signature == MagickCoreSignature);
3992   *buffer='\0';
3993   p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
3994   if (count != 2)
3995     return((unsigned short) 0U);
3996   value=(unsigned short) (*p++) << 8;
3997   value|=(unsigned short) (*p++);
3998   return(value & 0xffff);
3999 }
4000 \f
4001 /*
4002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4003 %                                                                             %
4004 %                                                                             %
4005 %                                                                             %
4006 +  R e a d B l o b M S B S i g n e d L o n g                                  %
4007 %                                                                             %
4008 %                                                                             %
4009 %                                                                             %
4010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4011 %
4012 %  ReadBlobMSBSignedLong() reads a signed int value as a 32-bit quantity in
4013 %  most-significant byte-order.
4014 %
4015 %  The format of the ReadBlobMSBSignedLong method is:
4016 %
4017 %      signed int ReadBlobMSBSignedLong(Image *image)
4018 %
4019 %  A description of each parameter follows.
4020 %
4021 %    o image: the image.
4022 %
4023 */
4024 MagickExport signed int ReadBlobMSBSignedLong(Image *image)
4025 {
4026   union
4027   {
4028     unsigned int
4029       unsigned_value;
4030
4031     signed int
4032       signed_value;
4033   } quantum;
4034
4035   quantum.unsigned_value=ReadBlobMSBLong(image);
4036   return(quantum.signed_value);
4037 }
4038 \f
4039 /*
4040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4041 %                                                                             %
4042 %                                                                             %
4043 %                                                                             %
4044 +  R e a d B l o b M S B S i g n e d S h o r t                                %
4045 %                                                                             %
4046 %                                                                             %
4047 %                                                                             %
4048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4049 %
4050 %  ReadBlobMSBSignedShort() reads a signed short value as a 16-bit quantity in
4051 %  most-significant byte-order.
4052 %
4053 %  The format of the ReadBlobMSBSignedShort method is:
4054 %
4055 %      signed short ReadBlobMSBSignedShort(Image *image)
4056 %
4057 %  A description of each parameter follows.
4058 %
4059 %    o image: the image.
4060 %
4061 */
4062 MagickExport signed short ReadBlobMSBSignedShort(Image *image)
4063 {
4064   union
4065   {
4066     unsigned short
4067       unsigned_value;
4068
4069     signed short
4070       signed_value;
4071   } quantum;
4072
4073   quantum.unsigned_value=ReadBlobMSBShort(image);
4074   return(quantum.signed_value);
4075 }
4076 \f
4077 /*
4078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4079 %                                                                             %
4080 %                                                                             %
4081 %                                                                             %
4082 +  R e a d B l o b S i g n e d L o n g                                        %
4083 %                                                                             %
4084 %                                                                             %
4085 %                                                                             %
4086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087 %
4088 %  ReadBlobSignedLong() reads a signed int value as a 32-bit quantity in the
4089 %  byte-order specified by the endian member of the image structure.
4090 %
4091 %  The format of the ReadBlobSignedLong method is:
4092 %
4093 %      signed int ReadBlobSignedLong(Image *image)
4094 %
4095 %  A description of each parameter follows.
4096 %
4097 %    o image: the image.
4098 %
4099 */
4100 MagickExport signed int ReadBlobSignedLong(Image *image)
4101 {
4102   union
4103   {
4104     unsigned int
4105       unsigned_value;
4106
4107     signed int
4108       signed_value;
4109   } quantum;
4110
4111   quantum.unsigned_value=ReadBlobLong(image);
4112   return(quantum.signed_value);
4113 }
4114 \f
4115 /*
4116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4117 %                                                                             %
4118 %                                                                             %
4119 %                                                                             %
4120 +  R e a d B l o b S i g n e d S h o r t                                      %
4121 %                                                                             %
4122 %                                                                             %
4123 %                                                                             %
4124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4125 %
4126 %  ReadBlobSignedShort() reads a signed short value as a 16-bit quantity in the
4127 %  byte-order specified by the endian member of the image structure.
4128 %
4129 %  The format of the ReadBlobSignedShort method is:
4130 %
4131 %      signed short ReadBlobSignedShort(Image *image)
4132 %
4133 %  A description of each parameter follows.
4134 %
4135 %    o image: the image.
4136 %
4137 */
4138 MagickExport signed short ReadBlobSignedShort(Image *image)
4139 {
4140   union
4141   {
4142     unsigned short
4143       unsigned_value;
4144
4145     signed short
4146       signed_value;
4147   } quantum;
4148
4149   quantum.unsigned_value=ReadBlobShort(image);
4150   return(quantum.signed_value);
4151 }
4152 \f
4153 /*
4154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4155 %                                                                             %
4156 %                                                                             %
4157 %                                                                             %
4158 +  R e a d B l o b S t r e a m                                                %
4159 %                                                                             %
4160 %                                                                             %
4161 %                                                                             %
4162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4163 %
4164 %  ReadBlobStream() reads data from the blob or image file and returns it.  It
4165 %  returns a pointer to the data buffer you supply or to the image memory
4166 %  buffer if its supported (zero-copy). If length is zero, ReadBlobStream()
4167 %  returns a count of zero and has no other results. If length is greater than
4168 %  SSIZE_MAX, the result is unspecified.
4169 %
4170 %  The format of the ReadBlobStream method is:
4171 %
4172 %      const void *ReadBlobStream(Image *image,const size_t length,void *data,
4173 %        ssize_t *count)
4174 %
4175 %  A description of each parameter follows:
4176 %
4177 %    o image: the image.
4178 %
4179 %    o length:  Specifies an integer representing the number of bytes to read
4180 %      from the file.
4181 %
4182 %    o count: returns the number of bytes read.
4183 %
4184 %    o data:  Specifies an area to place the information requested from the
4185 %      file.
4186 %
4187 */
4188 MagickExport const void *ReadBlobStream(Image *image,const size_t length,
4189   void *data,ssize_t *count)
4190 {
4191   assert(image != (Image *) NULL);
4192   assert(image->signature == MagickCoreSignature);
4193   assert(image->blob != (BlobInfo *) NULL);
4194   assert(image->blob->type != UndefinedStream);
4195   assert(count != (ssize_t *) NULL);
4196   if (image->blob->type != BlobStream)
4197     {
4198       assert(data != NULL);
4199       *count=ReadBlob(image,length,(unsigned char *) data);
4200       return(data);
4201     }
4202   if (image->blob->offset >= (MagickOffsetType) image->blob->length)
4203     {
4204       *count=0;
4205       image->blob->eof=MagickTrue;
4206       return(data);
4207     }
4208   data=image->blob->data+image->blob->offset;
4209   *count=(ssize_t) MagickMin(length,image->blob->length-image->blob->offset);
4210   image->blob->offset+=(*count);
4211   if (*count != (ssize_t) length)
4212     image->blob->eof=MagickTrue;
4213   return(data);
4214 }
4215 \f
4216 /*
4217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4218 %                                                                             %
4219 %                                                                             %
4220 %                                                                             %
4221 +   R e a d B l o b S t r i n g                                               %
4222 %                                                                             %
4223 %                                                                             %
4224 %                                                                             %
4225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4226 %
4227 %  ReadBlobString() reads characters from a blob or file until a newline
4228 %  character is read or an end-of-file condition is encountered.
4229 %
4230 %  The format of the ReadBlobString method is:
4231 %
4232 %      char *ReadBlobString(Image *image,char *string)
4233 %
4234 %  A description of each parameter follows:
4235 %
4236 %    o image: the image.
4237 %
4238 %    o string: the address of a character buffer.
4239 %
4240 */
4241 MagickExport char *ReadBlobString(Image *image,char *string)
4242 {
4243   register const unsigned char
4244     *p;
4245
4246   register ssize_t
4247     i;
4248
4249   ssize_t
4250     count;
4251
4252   unsigned char
4253     buffer[1];
4254
4255   assert(image != (Image *) NULL);
4256   assert(image->signature == MagickCoreSignature);
4257   for (i=0; i < (MagickPathExtent-1L); i++)
4258   {
4259     p=(const unsigned char *) ReadBlobStream(image,1,buffer,&count);
4260     if (count != 1)
4261       {
4262         if (i == 0)
4263           return((char *) NULL);
4264         break;
4265       }
4266     string[i]=(char) (*p);
4267     if ((string[i] == '\r') || (string[i] == '\n'))
4268       break;
4269   }
4270   if (string[i] == '\r')
4271     (void) ReadBlobStream(image,1,buffer,&count);
4272   string[i]='\0';
4273   return(string);
4274 }
4275 \f
4276 /*
4277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4278 %                                                                             %
4279 %                                                                             %
4280 %                                                                             %
4281 +   R e f e r e n c e B l o b                                                 %
4282 %                                                                             %
4283 %                                                                             %
4284 %                                                                             %
4285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4286 %
4287 %  ReferenceBlob() increments the reference count associated with the pixel
4288 %  blob returning a pointer to the blob.
4289 %
4290 %  The format of the ReferenceBlob method is:
4291 %
4292 %      BlobInfo ReferenceBlob(BlobInfo *blob_info)
4293 %
4294 %  A description of each parameter follows:
4295 %
4296 %    o blob_info: the blob_info.
4297 %
4298 */
4299 MagickExport BlobInfo *ReferenceBlob(BlobInfo *blob)
4300 {
4301   assert(blob != (BlobInfo *) NULL);
4302   assert(blob->signature == MagickCoreSignature);
4303   if (blob->debug != MagickFalse)
4304     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4305   LockSemaphoreInfo(blob->semaphore);
4306   blob->reference_count++;
4307   UnlockSemaphoreInfo(blob->semaphore);
4308   return(blob);
4309 }
4310 \f
4311 /*
4312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4313 %                                                                             %
4314 %                                                                             %
4315 %                                                                             %
4316 +  S e e k B l o b                                                            %
4317 %                                                                             %
4318 %                                                                             %
4319 %                                                                             %
4320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4321 %
4322 %  SeekBlob() sets the offset in bytes from the beginning of a blob or file
4323 %  and returns the resulting offset.
4324 %
4325 %  The format of the SeekBlob method is:
4326 %
4327 %      MagickOffsetType SeekBlob(Image *image,const MagickOffsetType offset,
4328 %        const int whence)
4329 %
4330 %  A description of each parameter follows:
4331 %
4332 %    o image: the image.
4333 %
4334 %    o offset:  Specifies an integer representing the offset in bytes.
4335 %
4336 %    o whence:  Specifies an integer representing how the offset is
4337 %      treated relative to the beginning of the blob as follows:
4338 %
4339 %        SEEK_SET  Set position equal to offset bytes.
4340 %        SEEK_CUR  Set position to current location plus offset.
4341 %        SEEK_END  Set position to EOF plus offset.
4342 %
4343 */
4344 MagickExport MagickOffsetType SeekBlob(Image *image,
4345   const MagickOffsetType offset,const int whence)
4346 {
4347   assert(image != (Image *) NULL);
4348   assert(image->signature == MagickCoreSignature);
4349   if (image->debug != MagickFalse)
4350     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4351   assert(image->blob != (BlobInfo *) NULL);
4352   assert(image->blob->type != UndefinedStream);
4353   switch (image->blob->type)
4354   {
4355     case UndefinedStream:
4356       break;
4357     case StandardStream:
4358     case PipeStream:
4359       return(-1);
4360     case FileStream:
4361     {
4362       if ((offset < 0) && (whence == SEEK_SET))
4363         return(-1);
4364       if (fseek(image->blob->file_info.file,offset,whence) < 0)
4365         return(-1);
4366       image->blob->offset=TellBlob(image);
4367       break;
4368     }
4369     case ZipStream:
4370     {
4371 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4372       if (gzseek(image->blob->file_info.gzfile,(off_t) offset,whence) < 0)
4373         return(-1);
4374 #endif
4375       image->blob->offset=TellBlob(image);
4376       break;
4377     }
4378     case BZipStream:
4379       return(-1);
4380     case FifoStream:
4381       return(-1);
4382     case BlobStream:
4383     {
4384       switch (whence)
4385       {
4386         case SEEK_SET:
4387         default:
4388         {
4389           if (offset < 0)
4390             return(-1);
4391           image->blob->offset=offset;
4392           break;
4393         }
4394         case SEEK_CUR:
4395         {
4396           if ((image->blob->offset+offset) < 0)
4397             return(-1);
4398           image->blob->offset+=offset;
4399           break;
4400         }
4401         case SEEK_END:
4402         {
4403           if (((MagickOffsetType) image->blob->length+offset) < 0)
4404             return(-1);
4405           image->blob->offset=image->blob->length+offset;
4406           break;
4407         }
4408       }
4409       if (image->blob->offset < (MagickOffsetType)
4410           ((off_t) image->blob->length))
4411         {
4412           image->blob->eof=MagickFalse;
4413           break;
4414         }
4415       if (image->blob->offset < (MagickOffsetType)
4416           ((off_t) image->blob->extent))
4417         break;
4418       if (image->blob->mapped != MagickFalse)
4419         {
4420           image->blob->eof=MagickTrue;
4421           return(-1);
4422         }
4423       image->blob->extent=(size_t) (image->blob->offset+image->blob->quantum);
4424       image->blob->quantum<<=1;
4425       image->blob->data=(unsigned char *) ResizeQuantumMemory(image->blob->data,
4426         image->blob->extent+1,sizeof(*image->blob->data));
4427       (void) SyncBlob(image);
4428       if (image->blob->data == NULL)
4429         {
4430           (void) DetachBlob(image->blob);
4431           return(-1);
4432         }
4433       break;
4434     }
4435     case CustomStream:
4436     {
4437       if (image->blob->custom_stream->seeker == (CustomStreamSeeker) NULL)
4438         return(-1);
4439       image->blob->offset=image->blob->custom_stream->seeker(offset,whence,
4440         image->blob->custom_stream->data);
4441       break;
4442     }
4443   }
4444   return(image->blob->offset);
4445 }
4446 \f
4447 /*
4448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4449 %                                                                             %
4450 %                                                                             %
4451 %                                                                             %
4452 +   S e t B l o b E x e m p t                                                 %
4453 %                                                                             %
4454 %                                                                             %
4455 %                                                                             %
4456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4457 %
4458 %  SetBlobExempt() sets the blob exempt status.
4459 %
4460 %  The format of the SetBlobExempt method is:
4461 %
4462 %      MagickBooleanType SetBlobExempt(const Image *image,
4463 %        const MagickBooleanType exempt)
4464 %
4465 %  A description of each parameter follows:
4466 %
4467 %    o image: the image.
4468 %
4469 %    o exempt: Set to true if this blob is exempt from being closed.
4470 %
4471 */
4472 MagickExport void SetBlobExempt(Image *image,const MagickBooleanType exempt)
4473 {
4474   assert(image != (const Image *) NULL);
4475   assert(image->signature == MagickCoreSignature);
4476   if (image->debug != MagickFalse)
4477     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4478   image->blob->exempt=exempt;
4479 }
4480 \f
4481 /*
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4483 %                                                                             %
4484 %                                                                             %
4485 %                                                                             %
4486 +  S e t B l o b E x t e n t                                                  %
4487 %                                                                             %
4488 %                                                                             %
4489 %                                                                             %
4490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4491 %
4492 %  SetBlobExtent() ensures enough space is allocated for the blob.  If the
4493 %  method is successful, subsequent writes to bytes in the specified range are
4494 %  guaranteed not to fail.
4495 %
4496 %  The format of the SetBlobExtent method is:
4497 %
4498 %      MagickBooleanType SetBlobExtent(Image *image,const MagickSizeType extent)
4499 %
4500 %  A description of each parameter follows:
4501 %
4502 %    o image: the image.
4503 %
4504 %    o extent:  the blob maximum extent.
4505 %
4506 */
4507 MagickExport MagickBooleanType SetBlobExtent(Image *image,
4508   const MagickSizeType extent)
4509 {
4510   assert(image != (Image *) NULL);
4511   assert(image->signature == MagickCoreSignature);
4512   if (image->debug != MagickFalse)
4513     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4514   assert(image->blob != (BlobInfo *) NULL);
4515   assert(image->blob->type != UndefinedStream);
4516   switch (image->blob->type)
4517   {
4518     case UndefinedStream:
4519       break;
4520     case StandardStream:
4521       return(MagickFalse);
4522     case FileStream:
4523     {
4524       MagickOffsetType
4525         offset;
4526
4527       ssize_t
4528         count;
4529
4530       if (extent != (MagickSizeType) ((off_t) extent))
4531         return(MagickFalse);
4532       offset=SeekBlob(image,0,SEEK_END);
4533       if (offset < 0)
4534         return(MagickFalse);
4535       if ((MagickSizeType) offset >= extent)
4536         break;
4537       offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
4538       if (offset < 0)
4539         break;
4540       count=(ssize_t) fwrite((const unsigned char *) "",1,1,
4541         image->blob->file_info.file);
4542 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
4543       if (image->blob->synchronize != MagickFalse)
4544         {
4545           int
4546             file;
4547
4548           file=fileno(image->blob->file_info.file);
4549           if ((file == -1) || (offset < 0))
4550             return(MagickFalse);
4551           (void) posix_fallocate(file,offset,extent-offset);
4552         }
4553 #endif
4554       offset=SeekBlob(image,offset,SEEK_SET);
4555       if (count != 1)
4556         return(MagickFalse);
4557       break;
4558     }
4559     case PipeStream:
4560     case ZipStream:
4561       return(MagickFalse);
4562     case BZipStream:
4563       return(MagickFalse);
4564     case FifoStream:
4565       return(MagickFalse);
4566     case BlobStream:
4567     {
4568       if (extent != (MagickSizeType) ((size_t) extent))
4569         return(MagickFalse);
4570       if (image->blob->mapped != MagickFalse)
4571         {
4572           MagickOffsetType
4573             offset;
4574
4575           ssize_t
4576             count;
4577
4578           (void) UnmapBlob(image->blob->data,image->blob->length);
4579           RelinquishMagickResource(MapResource,image->blob->length);
4580           if (extent != (MagickSizeType) ((off_t) extent))
4581             return(MagickFalse);
4582           offset=SeekBlob(image,0,SEEK_END);
4583           if (offset < 0)
4584             return(MagickFalse);
4585           if ((MagickSizeType) offset >= extent)
4586             break;
4587           offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
4588           count=(ssize_t) fwrite((const unsigned char *) "",1,1,
4589             image->blob->file_info.file);
4590 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
4591           if (image->blob->synchronize != MagickFalse)
4592             {
4593               int
4594                 file;
4595
4596               file=fileno(image->blob->file_info.file);
4597               if ((file == -1) || (offset < 0))
4598                 return(MagickFalse);
4599               (void) posix_fallocate(file,offset,extent-offset);
4600             }
4601 #endif
4602           offset=SeekBlob(image,offset,SEEK_SET);
4603           if (count != 1)
4604             return(MagickFalse);
4605           (void) AcquireMagickResource(MapResource,extent);
4606           image->blob->data=(unsigned char*) MapBlob(fileno(
4607             image->blob->file_info.file),WriteMode,0,(size_t) extent);
4608           image->blob->extent=(size_t) extent;
4609           image->blob->length=(size_t) extent;
4610           (void) SyncBlob(image);
4611           break;
4612         }
4613       image->blob->extent=(size_t) extent;
4614       image->blob->data=(unsigned char *) ResizeQuantumMemory(image->blob->data,
4615         image->blob->extent+1,sizeof(*image->blob->data));
4616       (void) SyncBlob(image);
4617       if (image->blob->data == (unsigned char *) NULL)
4618         {
4619           (void) DetachBlob(image->blob);
4620           return(MagickFalse);
4621         }
4622       break;
4623     }
4624     case CustomStream:
4625       break;
4626   }
4627   return(MagickTrue);
4628 }
4629 \f
4630 /*
4631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4632 %                                                                             %
4633 %                                                                             %
4634 %                                                                             %
4635 +  S e t C u s t o m S t r e a m D a t a                                      %
4636 %                                                                             %
4637 %                                                                             %
4638 %                                                                             %
4639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4640 %
4641 %  SetCustomStreamData() sets the stream info data member.
4642 %
4643 %  The format of the SetCustomStreamData method is:
4644 %
4645 %      void SetCustomStreamData(CustomStreamInfo *custom_stream,void *)
4646 %
4647 %  A description of each parameter follows:
4648 %
4649 %    o custom_stream: your custom stream.
4650 %
4651 %    o void: your data.
4652 %
4653 */
4654 MagickExport void SetCustomStreamData(CustomStreamInfo *custom_stream,
4655   void *data)
4656 {
4657   assert(custom_stream != (CustomStreamInfo *) NULL);
4658   assert(custom_stream->signature == MagickCoreSignature);
4659   custom_stream->data=data;
4660 }
4661 \f
4662 /*
4663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4664 %                                                                             %
4665 %                                                                             %
4666 %                                                                             %
4667 +  S e t C u s t o m S t r e a m R e a d e r                                  %
4668 %                                                                             %
4669 %                                                                             %
4670 %                                                                             %
4671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4672 %
4673 %  SetCustomStreamReader() sets the stream info reader member.
4674 %
4675 %  The format of the SetCustomStreamReader method is:
4676 %
4677 %      void SetCustomStreamReader(CustomStreamInfo *custom_stream,
4678 %        CustomStreamHandler reader)
4679 %
4680 %  A description of each parameter follows:
4681 %
4682 %    o custom_stream: your custom stream.
4683 %
4684 %    o reader: your custom stream reader.
4685 %
4686 */
4687 MagickExport void SetCustomStreamReader(CustomStreamInfo *custom_stream,
4688   CustomStreamHandler reader)
4689 {
4690   assert(custom_stream != (CustomStreamInfo *) NULL);
4691   assert(custom_stream->signature == MagickCoreSignature);
4692   custom_stream->reader=reader;
4693 }
4694 \f
4695 /*
4696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4697 %                                                                             %
4698 %                                                                             %
4699 %                                                                             %
4700 +  S e t C u s t o m S t r e a m S e e k e r                                  %
4701 %                                                                             %
4702 %                                                                             %
4703 %                                                                             %
4704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705 %
4706 %  SetCustomStreamSeeker() sets the stream info seeker member.
4707 %
4708 %  The format of the SetCustomStreamReader method is:
4709 %
4710 %      void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
4711 %        CustomStreamSeeker seeker)
4712 %
4713 %  A description of each parameter follows:
4714 %
4715 %    o custom_stream: your custom stream.
4716 %
4717 %    o seeker: your custom stream seeker.
4718 %
4719 */
4720 MagickExport void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
4721   CustomStreamSeeker seeker)
4722 {
4723   assert(custom_stream != (CustomStreamInfo *) NULL);
4724   assert(custom_stream->signature == MagickCoreSignature);
4725   custom_stream->seeker=seeker;
4726 }
4727 \f
4728 /*
4729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4730 %                                                                             %
4731 %                                                                             %
4732 %                                                                             %
4733 +  S e t C u s t o m S t r e a m T e l l e r                                  %
4734 %                                                                             %
4735 %                                                                             %
4736 %                                                                             %
4737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4738 %
4739 %  SetCustomStreamTeller() sets the stream info teller member.
4740 %
4741 %  The format of the SetCustomStreamTeller method is:
4742 %
4743 %      void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
4744 %        CustomStreamTeller *teller)
4745 %
4746 %  A description of each parameter follows:
4747 %
4748 %    o custom_stream: your custom stream.
4749 %
4750 %    o teller: your custom stream teller.
4751 %
4752 */
4753 MagickExport void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
4754   CustomStreamTeller teller)
4755 {
4756   assert(custom_stream != (CustomStreamInfo *) NULL);
4757   assert(custom_stream->signature == MagickCoreSignature);
4758   custom_stream->teller=teller;
4759 }
4760 \f
4761 /*
4762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4763 %                                                                             %
4764 %                                                                             %
4765 %                                                                             %
4766 +  S e t C u s t o m S t r e a m W r i t e r                                  %
4767 %                                                                             %
4768 %                                                                             %
4769 %                                                                             %
4770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4771 %
4772 %  SetCustomStreamWriter() sets the stream info writer member.
4773 %
4774 %  The format of the SetCustomStreamWriter method is:
4775 %
4776 %      void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
4777 %        CustomStreamHandler *writer)
4778 %
4779 %  A description of each parameter follows:
4780 %
4781 %    o custom_stream: your custom stream.
4782 %
4783 %    o writer: your custom stream writer.
4784 %
4785 */
4786 MagickExport void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
4787   CustomStreamHandler writer)
4788 {
4789   assert(custom_stream != (CustomStreamInfo *) NULL);
4790   assert(custom_stream->signature == MagickCoreSignature);
4791   custom_stream->writer=writer;
4792 }
4793 \f
4794 /*
4795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4796 %                                                                             %
4797 %                                                                             %
4798 %                                                                             %
4799 +  S y n c B l o b                                                            %
4800 %                                                                             %
4801 %                                                                             %
4802 %                                                                             %
4803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4804 %
4805 %  SyncBlob() flushes the datastream if it is a file or synchronizes the data
4806 %  attributes if it is an blob.
4807 %
4808 %  The format of the SyncBlob method is:
4809 %
4810 %      int SyncBlob(Image *image)
4811 %
4812 %  A description of each parameter follows:
4813 %
4814 %    o image: the image.
4815 %
4816 */
4817 static int SyncBlob(Image *image)
4818 {
4819   int
4820     status;
4821
4822   assert(image != (Image *) NULL);
4823   assert(image->signature == MagickCoreSignature);
4824   if (image->debug != MagickFalse)
4825     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4826   assert(image->blob != (BlobInfo *) NULL);
4827   assert(image->blob->type != UndefinedStream);
4828   status=0;
4829   switch (image->blob->type)
4830   {
4831     case UndefinedStream:
4832     case StandardStream:
4833       break;
4834     case FileStream:
4835     case PipeStream:
4836     {
4837       status=fflush(image->blob->file_info.file);
4838       break;
4839     }
4840     case ZipStream:
4841     {
4842 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4843       status=gzflush(image->blob->file_info.gzfile,Z_SYNC_FLUSH);
4844 #endif
4845       break;
4846     }
4847     case BZipStream:
4848     {
4849 #if defined(MAGICKCORE_BZLIB_DELEGATE)
4850       status=BZ2_bzflush(image->blob->file_info.bzfile);
4851 #endif
4852       break;
4853     }
4854     case FifoStream:
4855       break;
4856     case BlobStream:
4857       break;
4858     case CustomStream:
4859       break;
4860   }
4861   return(status);
4862 }
4863 \f
4864 /*
4865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866 %                                                                             %
4867 %                                                                             %
4868 %                                                                             %
4869 +  T e l l B l o b                                                            %
4870 %                                                                             %
4871 %                                                                             %
4872 %                                                                             %
4873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4874 %
4875 %  TellBlob() obtains the current value of the blob or file position.
4876 %
4877 %  The format of the TellBlob method is:
4878 %
4879 %      MagickOffsetType TellBlob(const Image *image)
4880 %
4881 %  A description of each parameter follows:
4882 %
4883 %    o image: the image.
4884 %
4885 */
4886 MagickExport MagickOffsetType TellBlob(const Image *image)
4887 {
4888   MagickOffsetType
4889     offset;
4890
4891   assert(image != (Image *) NULL);
4892   assert(image->signature == MagickCoreSignature);
4893   if (image->debug != MagickFalse)
4894     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4895   assert(image->blob != (BlobInfo *) NULL);
4896   assert(image->blob->type != UndefinedStream);
4897   offset=(-1);
4898   switch (image->blob->type)
4899   {
4900     case UndefinedStream:
4901     case StandardStream:
4902       break;
4903     case FileStream:
4904     {
4905       offset=ftell(image->blob->file_info.file);
4906       break;
4907     }
4908     case PipeStream:
4909       break;
4910     case ZipStream:
4911     {
4912 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4913       offset=(MagickOffsetType) gztell(image->blob->file_info.gzfile);
4914 #endif
4915       break;
4916     }
4917     case BZipStream:
4918       break;
4919     case FifoStream:
4920       break;
4921     case BlobStream:
4922     {
4923       offset=image->blob->offset;
4924       break;
4925     }
4926     case CustomStream:
4927     {
4928       if (image->blob->custom_stream->teller != (CustomStreamTeller) NULL)
4929         offset=image->blob->custom_stream->teller(image->blob->custom_stream->data);
4930       break;
4931     }
4932   }
4933   return(offset);
4934 }
4935 \f
4936 /*
4937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4938 %                                                                             %
4939 %                                                                             %
4940 %                                                                             %
4941 +  U n m a p B l o b                                                          %
4942 %                                                                             %
4943 %                                                                             %
4944 %                                                                             %
4945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4946 %
4947 %  UnmapBlob() deallocates the binary large object previously allocated with
4948 %  the MapBlob method.
4949 %
4950 %  The format of the UnmapBlob method is:
4951 %
4952 %       MagickBooleanType UnmapBlob(void *map,const size_t length)
4953 %
4954 %  A description of each parameter follows:
4955 %
4956 %    o map: the address  of the binary large object.
4957 %
4958 %    o length: the length of the binary large object.
4959 %
4960 */
4961 MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
4962 {
4963 #if defined(MAGICKCORE_HAVE_MMAP)
4964   int
4965     status;
4966
4967   status=munmap(map,length);
4968   return(status == -1 ? MagickFalse : MagickTrue);
4969 #else
4970   (void) map;
4971   (void) length;
4972   return(MagickFalse);
4973 #endif
4974 }
4975 \f
4976 /*
4977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4978 %                                                                             %
4979 %                                                                             %
4980 %                                                                             %
4981 %   C u s t o m S t r e a m T o I m a g e                                     %
4982 %                                                                             %
4983 %                                                                             %
4984 %                                                                             %
4985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4986 %
4987 %  CustomStreamToImage() is the equivalent of ReadImage(), but reads the
4988 %  formatted "file" from the suplied method rather than to an actual file.
4989 %
4990 %  The format of the CustomStreamToImage method is:
4991 %
4992 %      Image *CustomStreamToImage(const ImageInfo *image_info,
4993 %         ExceptionInfo *exception)
4994 %
4995 %  A description of each parameter follows:
4996 %
4997 %    o image_info: the image info.
4998 %
4999 %    o exception: return any errors or warnings in this structure.
5000 %
5001 */
5002 MagickExport Image *CustomStreamToImage(const ImageInfo *image_info,
5003   ExceptionInfo *exception)
5004 {
5005   const MagickInfo
5006     *magick_info;
5007
5008   Image
5009     *image;
5010
5011   ImageInfo
5012     *blob_info;
5013
5014   assert(image_info != (ImageInfo *) NULL);
5015   assert(image_info->signature == MagickCoreSignature);
5016   if (image_info->debug != MagickFalse)
5017     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5018       image_info->filename);
5019   assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
5020   assert(image_info->custom_stream->signature == MagickCoreSignature);
5021   assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
5022   assert(exception != (ExceptionInfo *) NULL);
5023   blob_info=CloneImageInfo(image_info);
5024   if (*blob_info->magick == '\0')
5025     (void) SetImageInfo(blob_info,0,exception);
5026   magick_info=GetMagickInfo(blob_info->magick,exception);
5027   if (magick_info == (const MagickInfo *) NULL)
5028     {
5029       (void) ThrowMagickException(exception,GetMagickModule(),
5030         MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
5031         blob_info->magick);
5032       blob_info=DestroyImageInfo(blob_info);
5033       return((Image *) NULL);
5034     }
5035   image=(Image *) NULL;
5036   if ((GetMagickBlobSupport(magick_info) != MagickFalse) ||
5037       (blob_info->custom_stream == (CustomStreamInfo *) NULL))
5038     {
5039       /*
5040         Native blob support for this image format or SetImageInfo changed the
5041         blob to a file.
5042       */
5043       image=ReadImage(blob_info,exception);
5044       if (image != (Image *) NULL)
5045         (void) CloseBlob(image);
5046     }
5047   else
5048     {
5049       char
5050         unique[MagickPathExtent];
5051
5052       int
5053         file;
5054
5055       ImageInfo
5056         *clone_info;
5057
5058       unsigned char
5059         *blob;
5060
5061       /*
5062         Write data to file on disk.
5063       */
5064       blob_info->custom_stream=(CustomStreamInfo *) NULL;
5065       blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
5066         sizeof(*blob));
5067       if (blob == (unsigned char *) NULL)
5068         {
5069           ThrowFileException(exception,BlobError,"UnableToReadBlob",
5070             image_info->filename);
5071           blob_info=DestroyImageInfo(blob_info);
5072           return((Image *) NULL);
5073         }
5074       file=AcquireUniqueFileResource(unique);
5075       if (file == -1)
5076         {
5077           ThrowFileException(exception,BlobError,"UnableToReadBlob",
5078             image_info->filename);
5079           blob=(unsigned char *) RelinquishMagickMemory(blob);
5080           blob_info=DestroyImageInfo(blob_info);
5081           return((Image *) NULL);
5082         }
5083       clone_info=CloneImageInfo(blob_info);
5084       blob_info->file=fdopen(file,"wb+");
5085       if (blob_info->file != (FILE *) NULL)
5086         {
5087           ssize_t
5088             count;
5089
5090           count=(ssize_t) MagickMaxBufferExtent;
5091           while (count == (ssize_t) MagickMaxBufferExtent)
5092           {
5093             count=image_info->custom_stream->reader(blob,MagickMaxBufferExtent,
5094               image_info->custom_stream->data);
5095             count=(ssize_t) write(file,(const char *) blob,count);
5096           }
5097           (void) fclose(blob_info->file);
5098           (void) FormatLocaleString(clone_info->filename,MagickPathExtent,
5099             "%s:%s",blob_info->magick,unique);
5100           image=ReadImage(clone_info,exception);
5101           if (image != (Image *) NULL)
5102             {
5103               Image
5104                 *images;
5105
5106               /*
5107                 Restore original filenames and image format.
5108               */
5109               for (images=GetFirstImageInList(image); images != (Image *) NULL; )
5110               {
5111                 (void) CopyMagickString(images->filename,image_info->filename,
5112                   MagickPathExtent);
5113                 (void) CopyMagickString(images->magick_filename,
5114                   image_info->filename,MagickPathExtent);
5115                 (void) CopyMagickString(images->magick,magick_info->name,
5116                   MagickPathExtent);
5117                 (void) CloseBlob(images);
5118                 images=GetNextImageInList(images);
5119               }
5120             }
5121         }
5122       clone_info=DestroyImageInfo(clone_info);
5123       blob=(unsigned char *) RelinquishMagickMemory(blob);
5124       (void) RelinquishUniqueFileResource(unique);
5125     }
5126   blob_info=DestroyImageInfo(blob_info);
5127   return(image);
5128 }
5129 \f
5130 /*
5131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5132 %                                                                             %
5133 %                                                                             %
5134 %                                                                             %
5135 +  W r i t e B l o b                                                          %
5136 %                                                                             %
5137 %                                                                             %
5138 %                                                                             %
5139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5140 %
5141 %  WriteBlob() writes data to a blob or image file.  It returns the number of
5142 %  bytes written.
5143 %
5144 %  The format of the WriteBlob method is:
5145 %
5146 %      ssize_t WriteBlob(Image *image,const size_t length,const void *data)
5147 %
5148 %  A description of each parameter follows:
5149 %
5150 %    o image: the image.
5151 %
5152 %    o length:  Specifies an integer representing the number of bytes to
5153 %      write to the file.
5154 %
5155 %    o data:  The address of the data to write to the blob or file.
5156 %
5157 */
5158 MagickExport ssize_t WriteBlob(Image *image,const size_t length,
5159   const void *data)
5160 {
5161   int
5162     c;
5163
5164   register const unsigned char
5165     *p;
5166
5167   ssize_t
5168     count;
5169
5170   assert(image != (Image *) NULL);
5171   assert(image->signature == MagickCoreSignature);
5172   assert(image->blob != (BlobInfo *) NULL);
5173   assert(image->blob->type != UndefinedStream);
5174   if (length == 0)
5175     return(0);
5176   assert(data != (const void *) NULL);
5177   count=0;
5178   p=(const unsigned char *) data;
5179   switch (image->blob->type)
5180   {
5181     case UndefinedStream:
5182       break;
5183     case StandardStream:
5184     case FileStream:
5185     case PipeStream:
5186     {
5187       switch (length)
5188       {
5189         default:
5190         {
5191           count=(ssize_t) fwrite((const char *) data,1,length,
5192             image->blob->file_info.file);
5193           break;
5194         }
5195         case 4:
5196         {
5197           c=putc((int) *p++,image->blob->file_info.file);
5198           if (c == EOF)
5199             break;
5200           count++;
5201         }
5202         case 3:
5203         {
5204           c=putc((int) *p++,image->blob->file_info.file);
5205           if (c == EOF)
5206             break;
5207           count++;
5208         }
5209         case 2:
5210         {
5211           c=putc((int) *p++,image->blob->file_info.file);
5212           if (c == EOF)
5213             break;
5214           count++;
5215         }
5216         case 1:
5217         {
5218           c=putc((int) *p++,image->blob->file_info.file);
5219           if (c == EOF)
5220             break;
5221           count++;
5222         }
5223         case 0:
5224           break;
5225       }
5226       break;
5227     }
5228     case ZipStream:
5229     {
5230 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5231       switch (length)
5232       {
5233         default:
5234         {
5235           count=(ssize_t) gzwrite(image->blob->file_info.gzfile,(void *) data,
5236             (unsigned int) length);
5237           break;
5238         }
5239         case 4:
5240         {
5241           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5242           if (c == EOF)
5243             break;
5244           count++;
5245         }
5246         case 3:
5247         {
5248           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5249           if (c == EOF)
5250             break;
5251           count++;
5252         }
5253         case 2:
5254         {
5255           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5256           if (c == EOF)
5257             break;
5258           count++;
5259         }
5260         case 1:
5261         {
5262           c=gzputc(image->blob->file_info.gzfile,(int) *p++);
5263           if (c == EOF)
5264             break;
5265           count++;
5266         }
5267         case 0:
5268           break;
5269       }
5270 #endif
5271       break;
5272     }
5273     case BZipStream:
5274     {
5275 #if defined(MAGICKCORE_BZLIB_DELEGATE)
5276       count=(ssize_t) BZ2_bzwrite(image->blob->file_info.bzfile,(void *) data,
5277         (int) length);
5278 #endif
5279       break;
5280     }
5281     case FifoStream:
5282     {
5283       count=(ssize_t) image->blob->stream(image,data,length);
5284       break;
5285     }
5286     case BlobStream:
5287     {
5288       register unsigned char
5289         *q;
5290
5291       if ((image->blob->offset+(MagickOffsetType) length) >=
5292           (MagickOffsetType) image->blob->extent)
5293         {
5294           if (image->blob->mapped != MagickFalse)
5295             return(0);
5296           image->blob->extent+=length+image->blob->quantum;
5297           image->blob->quantum<<=1;
5298           image->blob->data=(unsigned char *) ResizeQuantumMemory(
5299             image->blob->data,image->blob->extent+1,sizeof(*image->blob->data));
5300           (void) SyncBlob(image);
5301           if (image->blob->data == (unsigned char *) NULL)
5302             {
5303               (void) DetachBlob(image->blob);
5304               return(0);
5305             }
5306         }
5307       q=image->blob->data+image->blob->offset;
5308       (void) memcpy(q,p,length);
5309       image->blob->offset+=length;
5310       if (image->blob->offset >= (MagickOffsetType) image->blob->length)
5311         image->blob->length=(size_t) image->blob->offset;
5312       count=(ssize_t) length;
5313       break;
5314     }
5315     case CustomStream:
5316     {
5317       if (image->blob->custom_stream->writer != (CustomStreamHandler) NULL)
5318         count=image->blob->custom_stream->writer((const unsigned char *) data,
5319           length,image->blob->custom_stream->data);
5320       break;
5321     }
5322   }
5323   return(count);
5324 }
5325 \f
5326 /*
5327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5328 %                                                                             %
5329 %                                                                             %
5330 %                                                                             %
5331 +  W r i t e B l o b B y t e                                                  %
5332 %                                                                             %
5333 %                                                                             %
5334 %                                                                             %
5335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5336 %
5337 %  WriteBlobByte() write an integer to a blob.  It returns the number of bytes
5338 %  written (either 0 or 1);
5339 %
5340 %  The format of the WriteBlobByte method is:
5341 %
5342 %      ssize_t WriteBlobByte(Image *image,const unsigned char value)
5343 %
5344 %  A description of each parameter follows.
5345 %
5346 %    o image: the image.
5347 %
5348 %    o value: Specifies the value to write.
5349 %
5350 */
5351 MagickExport ssize_t WriteBlobByte(Image *image,const unsigned char value)
5352 {
5353   assert(image != (Image *) NULL);
5354   assert(image->signature == MagickCoreSignature);
5355   return(WriteBlobStream(image,1,&value));
5356 }
5357 \f
5358 /*
5359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5360 %                                                                             %
5361 %                                                                             %
5362 %                                                                             %
5363 +  W r i t e B l o b F l o a t                                                %
5364 %                                                                             %
5365 %                                                                             %
5366 %                                                                             %
5367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5368 %
5369 %  WriteBlobFloat() writes a float value as a 32-bit quantity in the byte-order
5370 %  specified by the endian member of the image structure.
5371 %
5372 %  The format of the WriteBlobFloat method is:
5373 %
5374 %      ssize_t WriteBlobFloat(Image *image,const float value)
5375 %
5376 %  A description of each parameter follows.
5377 %
5378 %    o image: the image.
5379 %
5380 %    o value: Specifies the value to write.
5381 %
5382 */
5383 MagickExport ssize_t WriteBlobFloat(Image *image,const float value)
5384 {
5385   union
5386   {
5387     unsigned int
5388       unsigned_value;
5389
5390     float
5391       float_value;
5392   } quantum;
5393
5394   quantum.unsigned_value=0U;
5395   quantum.float_value=value;
5396   return(WriteBlobLong(image,quantum.unsigned_value));
5397 }
5398 \f
5399 /*
5400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5401 %                                                                             %
5402 %                                                                             %
5403 %                                                                             %
5404 +  W r i t e B l o b L o n g                                                  %
5405 %                                                                             %
5406 %                                                                             %
5407 %                                                                             %
5408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5409 %
5410 %  WriteBlobLong() writes a unsigned int value as a 32-bit quantity in the
5411 %  byte-order specified by the endian member of the image structure.
5412 %
5413 %  The format of the WriteBlobLong method is:
5414 %
5415 %      ssize_t WriteBlobLong(Image *image,const unsigned int value)
5416 %
5417 %  A description of each parameter follows.
5418 %
5419 %    o image: the image.
5420 %
5421 %    o value: Specifies the value to write.
5422 %
5423 */
5424 MagickExport ssize_t WriteBlobLong(Image *image,const unsigned int value)
5425 {
5426   unsigned char
5427     buffer[4];
5428
5429   assert(image != (Image *) NULL);
5430   assert(image->signature == MagickCoreSignature);
5431   if (image->endian == LSBEndian)
5432     {
5433       buffer[0]=(unsigned char) value;
5434       buffer[1]=(unsigned char) (value >> 8);
5435       buffer[2]=(unsigned char) (value >> 16);
5436       buffer[3]=(unsigned char) (value >> 24);
5437       return(WriteBlobStream(image,4,buffer));
5438     }
5439   buffer[0]=(unsigned char) (value >> 24);
5440   buffer[1]=(unsigned char) (value >> 16);
5441   buffer[2]=(unsigned char) (value >> 8);
5442   buffer[3]=(unsigned char) value;
5443   return(WriteBlobStream(image,4,buffer));
5444 }
5445 \f
5446 /*
5447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5448 %                                                                             %
5449 %                                                                             %
5450 %                                                                             %
5451 +   W r i t e B l o b S h o r t                                               %
5452 %                                                                             %
5453 %                                                                             %
5454 %                                                                             %
5455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5456 %
5457 %  WriteBlobShort() writes a short value as a 16-bit quantity in the
5458 %  byte-order specified by the endian member of the image structure.
5459 %
5460 %  The format of the WriteBlobShort method is:
5461 %
5462 %      ssize_t WriteBlobShort(Image *image,const unsigned short value)
5463 %
5464 %  A description of each parameter follows.
5465 %
5466 %    o image: the image.
5467 %
5468 %    o value:  Specifies the value to write.
5469 %
5470 */
5471 MagickExport ssize_t WriteBlobShort(Image *image,const unsigned short value)
5472 {
5473   unsigned char
5474     buffer[2];
5475
5476   assert(image != (Image *) NULL);
5477   assert(image->signature == MagickCoreSignature);
5478   if (image->endian == LSBEndian)
5479     {
5480       buffer[0]=(unsigned char) value;
5481       buffer[1]=(unsigned char) (value >> 8);
5482       return(WriteBlobStream(image,2,buffer));
5483     }
5484   buffer[0]=(unsigned char) (value >> 8);
5485   buffer[1]=(unsigned char) value;
5486   return(WriteBlobStream(image,2,buffer));
5487 }
5488 \f
5489 /*
5490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5491 %                                                                             %
5492 %                                                                             %
5493 %                                                                             %
5494 +  W r i t e B l o b L S B L o n g                                            %
5495 %                                                                             %
5496 %                                                                             %
5497 %                                                                             %
5498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5499 %
5500 %  WriteBlobLSBLong() writes a unsigned int value as a 32-bit quantity in
5501 %  least-significant byte first order.
5502 %
5503 %  The format of the WriteBlobLSBLong method is:
5504 %
5505 %      ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
5506 %
5507 %  A description of each parameter follows.
5508 %
5509 %    o image: the image.
5510 %
5511 %    o value: Specifies the value to write.
5512 %
5513 */
5514 MagickExport ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
5515 {
5516   unsigned char
5517     buffer[4];
5518
5519   assert(image != (Image *) NULL);
5520   assert(image->signature == MagickCoreSignature);
5521   buffer[0]=(unsigned char) value;
5522   buffer[1]=(unsigned char) (value >> 8);
5523   buffer[2]=(unsigned char) (value >> 16);
5524   buffer[3]=(unsigned char) (value >> 24);
5525   return(WriteBlobStream(image,4,buffer));
5526 }
5527 \f
5528 /*
5529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5530 %                                                                             %
5531 %                                                                             %
5532 %                                                                             %
5533 +   W r i t e B l o b L S B S h o r t                                         %
5534 %                                                                             %
5535 %                                                                             %
5536 %                                                                             %
5537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5538 %
5539 %  WriteBlobLSBShort() writes a unsigned short value as a 16-bit quantity in
5540 %  least-significant byte first order.
5541 %
5542 %  The format of the WriteBlobLSBShort method is:
5543 %
5544 %      ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
5545 %
5546 %  A description of each parameter follows.
5547 %
5548 %    o image: the image.
5549 %
5550 %    o value:  Specifies the value to write.
5551 %
5552 */
5553 MagickExport ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
5554 {
5555   unsigned char
5556     buffer[2];
5557
5558   assert(image != (Image *) NULL);
5559   assert(image->signature == MagickCoreSignature);
5560   buffer[0]=(unsigned char) value;
5561   buffer[1]=(unsigned char) (value >> 8);
5562   return(WriteBlobStream(image,2,buffer));
5563 }
5564 \f
5565 /*
5566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5567 %                                                                             %
5568 %                                                                             %
5569 %                                                                             %
5570 +  W r i t e B l o b L S B S i g n e d L o n g                                %
5571 %                                                                             %
5572 %                                                                             %
5573 %                                                                             %
5574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5575 %
5576 %  WriteBlobLSBSignedLong() writes a signed value as a 32-bit quantity in
5577 %  least-significant byte first order.
5578 %
5579 %  The format of the WriteBlobLSBSignedLong method is:
5580 %
5581 %      ssize_t WriteBlobLSBSignedLong(Image *image,const signed int value)
5582 %
5583 %  A description of each parameter follows.
5584 %
5585 %    o image: the image.
5586 %
5587 %    o value: Specifies the value to write.
5588 %
5589 */
5590 MagickExport ssize_t WriteBlobLSBSignedLong(Image *image,const signed int value)
5591 {
5592   union
5593   {
5594     unsigned int
5595       unsigned_value;
5596
5597     signed int
5598       signed_value;
5599   } quantum;
5600
5601   unsigned char
5602     buffer[4];
5603
5604   assert(image != (Image *) NULL);
5605   assert(image->signature == MagickCoreSignature);
5606   quantum.signed_value=value;
5607   buffer[0]=(unsigned char) quantum.unsigned_value;
5608   buffer[1]=(unsigned char) (quantum.unsigned_value >> 8);
5609   buffer[2]=(unsigned char) (quantum.unsigned_value >> 16);
5610   buffer[3]=(unsigned char) (quantum.unsigned_value >> 24);
5611   return(WriteBlobStream(image,4,buffer));
5612 }
5613 \f
5614 /*
5615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5616 %                                                                             %
5617 %                                                                             %
5618 %                                                                             %
5619 +   W r i t e B l o b L S B S i g n e d S h o r t                             %
5620 %                                                                             %
5621 %                                                                             %
5622 %                                                                             %
5623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5624 %
5625 %  WriteBlobLSBSignedShort() writes a signed short value as a 16-bit quantity
5626 %  in least-significant byte first order.
5627 %
5628 %  The format of the WriteBlobLSBSignedShort method is:
5629 %
5630 %      ssize_t WriteBlobLSBSignedShort(Image *image,const signed short value)
5631 %
5632 %  A description of each parameter follows.
5633 %
5634 %    o image: the image.
5635 %
5636 %    o value:  Specifies the value to write.
5637 %
5638 */
5639 MagickExport ssize_t WriteBlobLSBSignedShort(Image *image,
5640   const signed short value)
5641 {
5642   union
5643   {
5644     unsigned short
5645       unsigned_value;
5646
5647     signed short
5648       signed_value;
5649   } quantum;
5650
5651   unsigned char
5652     buffer[2];
5653
5654   assert(image != (Image *) NULL);
5655   assert(image->signature == MagickCoreSignature);
5656   quantum.signed_value=value;
5657   buffer[0]=(unsigned char) quantum.unsigned_value;
5658   buffer[1]=(unsigned char) (quantum.unsigned_value >> 8);
5659   return(WriteBlobStream(image,2,buffer));
5660 }
5661 \f
5662 /*
5663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5664 %                                                                             %
5665 %                                                                             %
5666 %                                                                             %
5667 +  W r i t e B l o b M S B L o n g                                            %
5668 %                                                                             %
5669 %                                                                             %
5670 %                                                                             %
5671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5672 %
5673 %  WriteBlobMSBLong() writes a unsigned int value as a 32-bit quantity in
5674 %  most-significant byte first order.
5675 %
5676 %  The format of the WriteBlobMSBLong method is:
5677 %
5678 %      ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
5679 %
5680 %  A description of each parameter follows.
5681 %
5682 %    o value:  Specifies the value to write.
5683 %
5684 %    o image: the image.
5685 %
5686 */
5687 MagickExport ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
5688 {
5689   unsigned char
5690     buffer[4];
5691
5692   assert(image != (Image *) NULL);
5693   assert(image->signature == MagickCoreSignature);
5694   buffer[0]=(unsigned char) (value >> 24);
5695   buffer[1]=(unsigned char) (value >> 16);
5696   buffer[2]=(unsigned char) (value >> 8);
5697   buffer[3]=(unsigned char) value;
5698   return(WriteBlobStream(image,4,buffer));
5699 }
5700 \f
5701 /*
5702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5703 %                                                                             %
5704 %                                                                             %
5705 %                                                                             %
5706 +  W r i t e B l o b M S B L o n g L o n g                                    %
5707 %                                                                             %
5708 %                                                                             %
5709 %                                                                             %
5710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5711 %
5712 %  WriteBlobMSBLongLong() writes a long long value as a 64-bit quantity in
5713 %  most-significant byte first order.
5714 %
5715 %  The format of the WriteBlobMSBLongLong method is:
5716 %
5717 %      ssize_t WriteBlobMSBLongLong(Image *image,const MagickSizeType value)
5718 %
5719 %  A description of each parameter follows.
5720 %
5721 %    o value:  Specifies the value to write.
5722 %
5723 %    o image: the image.
5724 %
5725 */
5726 MagickExport ssize_t WriteBlobMSBLongLong(Image *image,
5727   const MagickSizeType value)
5728 {
5729   unsigned char
5730     buffer[8];
5731
5732   assert(image != (Image *) NULL);
5733   assert(image->signature == MagickCoreSignature);
5734   buffer[0]=(unsigned char) (value >> 56);
5735   buffer[1]=(unsigned char) (value >> 48);
5736   buffer[2]=(unsigned char) (value >> 40);
5737   buffer[3]=(unsigned char) (value >> 32);
5738   buffer[4]=(unsigned char) (value >> 24);
5739   buffer[5]=(unsigned char) (value >> 16);
5740   buffer[6]=(unsigned char) (value >> 8);
5741   buffer[7]=(unsigned char) value;
5742   return(WriteBlobStream(image,8,buffer));
5743 }
5744 \f
5745 /*
5746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5747 %                                                                             %
5748 %                                                                             %
5749 %                                                                             %
5750 +  W r i t e B l o b M S B S i g n e d L o n g                                %
5751 %                                                                             %
5752 %                                                                             %
5753 %                                                                             %
5754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5755 %
5756 %  WriteBlobMSBSignedLong() writes a signed value as a 32-bit quantity in
5757 %  most-significant byte first order.
5758 %
5759 %  The format of the WriteBlobMSBSignedLong method is:
5760 %
5761 %      ssize_t WriteBlobMSBSignedLong(Image *image,const signed int value)
5762 %
5763 %  A description of each parameter follows.
5764 %
5765 %    o image: the image.
5766 %
5767 %    o value: Specifies the value to write.
5768 %
5769 */
5770 MagickExport ssize_t WriteBlobMSBSignedLong(Image *image,const signed int value)
5771 {
5772   union
5773   {
5774     unsigned int
5775       unsigned_value;
5776
5777     signed int
5778       signed_value;
5779   } quantum;
5780
5781   unsigned char
5782     buffer[4];
5783
5784   assert(image != (Image *) NULL);
5785   assert(image->signature == MagickCoreSignature);
5786   quantum.signed_value=value;
5787   buffer[0]=(unsigned char) (quantum.unsigned_value >> 24);
5788   buffer[1]=(unsigned char) (quantum.unsigned_value >> 16);
5789   buffer[2]=(unsigned char) (quantum.unsigned_value >> 8);
5790   buffer[3]=(unsigned char) quantum.unsigned_value;
5791   return(WriteBlobStream(image,4,buffer));
5792 }
5793 \f
5794 /*
5795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5796 %                                                                             %
5797 %                                                                             %
5798 %                                                                             %
5799 +   W r i t e B l o b M S B S i g n e d S h o r t                             %
5800 %                                                                             %
5801 %                                                                             %
5802 %                                                                             %
5803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5804 %
5805 %  WriteBlobMSBSignedShort() writes a signed short value as a 16-bit quantity
5806 %  in most-significant byte first order.
5807 %
5808 %  The format of the WriteBlobMSBSignedShort method is:
5809 %
5810 %      ssize_t WriteBlobMSBSignedShort(Image *image,const signed short value)
5811 %
5812 %  A description of each parameter follows.
5813 %
5814 %    o image: the image.
5815 %
5816 %    o value:  Specifies the value to write.
5817 %
5818 */
5819 MagickExport ssize_t WriteBlobMSBSignedShort(Image *image,
5820   const signed short value)
5821 {
5822   union
5823   {
5824     unsigned short
5825       unsigned_value;
5826
5827     signed short
5828       signed_value;
5829   } quantum;
5830
5831   unsigned char
5832     buffer[2];
5833
5834   assert(image != (Image *) NULL);
5835   assert(image->signature == MagickCoreSignature);
5836   quantum.signed_value=value;
5837   buffer[0]=(unsigned char) (quantum.unsigned_value >> 8);
5838   buffer[1]=(unsigned char) quantum.unsigned_value;
5839   return(WriteBlobStream(image,2,buffer));
5840 }
5841 \f
5842 /*
5843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5844 %                                                                             %
5845 %                                                                             %
5846 %                                                                             %
5847 +  W r i t e B l o b M S B S h o r t                                          %
5848 %                                                                             %
5849 %                                                                             %
5850 %                                                                             %
5851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5852 %
5853 %  WriteBlobMSBShort() writes a unsigned short value as a 16-bit quantity in
5854 %  most-significant byte first order.
5855 %
5856 %  The format of the WriteBlobMSBShort method is:
5857 %
5858 %      ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
5859 %
5860 %  A description of each parameter follows.
5861 %
5862 %   o  value:  Specifies the value to write.
5863 %
5864 %   o  file:  Specifies the file to write the data to.
5865 %
5866 */
5867 MagickExport ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
5868 {
5869   unsigned char
5870     buffer[2];
5871
5872   assert(image != (Image *) NULL);
5873   assert(image->signature == MagickCoreSignature);
5874   buffer[0]=(unsigned char) (value >> 8);
5875   buffer[1]=(unsigned char) value;
5876   return(WriteBlobStream(image,2,buffer));
5877 }
5878 \f
5879 /*
5880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5881 %                                                                             %
5882 %                                                                             %
5883 %                                                                             %
5884 +  W r i t e B l o b S t r i n g                                              %
5885 %                                                                             %
5886 %                                                                             %
5887 %                                                                             %
5888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5889 %
5890 %  WriteBlobString() write a string to a blob.  It returns the number of
5891 %  characters written.
5892 %
5893 %  The format of the WriteBlobString method is:
5894 %
5895 %      ssize_t WriteBlobString(Image *image,const char *string)
5896 %
5897 %  A description of each parameter follows.
5898 %
5899 %    o image: the image.
5900 %
5901 %    o string: Specifies the string to write.
5902 %
5903 */
5904 MagickExport ssize_t WriteBlobString(Image *image,const char *string)
5905 {
5906   assert(image != (Image *) NULL);
5907   assert(image->signature == MagickCoreSignature);
5908   assert(string != (const char *) NULL);
5909   return(WriteBlobStream(image,strlen(string),(const unsigned char *) string));
5910 }