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