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