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