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