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