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://www.imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 
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;
1385  status=GetPathAttributes(filename,&attributes);
1386  if ((status == MagickFalse) || (S_ISDIR(attributes.st_mode) != 0))
1387  {
1388  ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1389  return(NULL);
1390  }
1391  file=fileno(stdin);
1392  if (LocaleCompare(filename,"-") != 0)
1393  file=open_utf8(filename,O_RDONLY | O_BINARY,0);
1394  if (file == -1)
1395  {
1396  ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
1397  return(NULL);
1398  }
1399  offset=(MagickOffsetType) lseek(file,0,SEEK_END);
1400  count=0;
1401  if ((file == fileno(stdin)) || (offset < 0) ||
1402  (offset != (MagickOffsetType) ((ssize_t) offset)))
1403  {
1404  size_t
1405  quantum;
1406 
1407  struct stat
1408  file_stats;
1409 
1410  /*
1411  Stream is not seekable.
1412  */
1413  offset=(MagickOffsetType) lseek(file,0,SEEK_SET);
1414  quantum=(size_t) MagickMaxBufferExtent;
1415  if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1416  quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1417  blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
1418  for (i=0; blob != (unsigned char *) NULL; i+=count)
1419  {
1420  count=read(file,blob+i,quantum);
1421  if (count <= 0)
1422  {
1423  count=0;
1424  if (errno != EINTR)
1425  break;
1426  }
1427  if (~((size_t) i) < (quantum+1))
1428  {
1429  blob=(unsigned char *) RelinquishMagickMemory(blob);
1430  break;
1431  }
1432  blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
1433  sizeof(*blob));
1434  if ((size_t) (i+count) >= extent)
1435  break;
1436  }
1437  if (LocaleCompare(filename,"-") != 0)
1438  file=close(file);
1439  if (blob == (unsigned char *) NULL)
1440  {
1441  (void) ThrowMagickException(exception,GetMagickModule(),
1442  ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1443  return(NULL);
1444  }
1445  if (file == -1)
1446  {
1447  blob=(unsigned char *) RelinquishMagickMemory(blob);
1448  ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1449  return(NULL);
1450  }
1451  *length=(size_t) MagickMin(i+count,extent);
1452  blob[*length]='\0';
1453  return(blob);
1454  }
1455  *length=(size_t) MagickMin(offset,(MagickOffsetType)
1456  MagickMin(extent,SSIZE_MAX));
1457  blob=(unsigned char *) NULL;
1458  if (~(*length) >= (MagickPathExtent-1))
1459  blob=(unsigned char *) AcquireQuantumMemory(*length+MagickPathExtent,
1460  sizeof(*blob));
1461  if (blob == (unsigned char *) NULL)
1462  {
1463  file=close(file);
1464  (void) ThrowMagickException(exception,GetMagickModule(),
1465  ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1466  return(NULL);
1467  }
1468  map=MapBlob(file,ReadMode,0,*length);
1469  if (map != (unsigned char *) NULL)
1470  {
1471  (void) memcpy(blob,map,*length);
1472  (void) UnmapBlob(map,*length);
1473  }
1474  else
1475  {
1476  (void) lseek(file,0,SEEK_SET);
1477  for (i=0; i < *length; i+=count)
1478  {
1479  count=read(file,blob+i,(size_t) MagickMin(*length-i,SSIZE_MAX));
1480  if (count <= 0)
1481  {
1482  count=0;
1483  if (errno != EINTR)
1484  break;
1485  }
1486  }
1487  if (i < *length)
1488  {
1489  file=close(file)-1;
1490  blob=(unsigned char *) RelinquishMagickMemory(blob);
1491  ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1492  return(NULL);
1493  }
1494  }
1495  blob[*length]='\0';
1496  if (LocaleCompare(filename,"-") != 0)
1497  file=close(file);
1498  if (file == -1)
1499  {
1500  blob=(unsigned char *) RelinquishMagickMemory(blob);
1501  ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
1502  }
1503  return(blob);
1504 }
1505 
1506 /*
1507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1508 % %
1509 % %
1510 % %
1511 % F i l e T o I m a g e %
1512 % %
1513 % %
1514 % %
1515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1516 %
1517 % FileToImage() write the contents of a file to an image.
1518 %
1519 % The format of the FileToImage method is:
1520 %
1521 % MagickBooleanType FileToImage(Image *,const char *filename)
1522 %
1523 % A description of each parameter follows:
1524 %
1525 % o image: the image.
1526 %
1527 % o filename: the filename.
1528 %
1529 */
1530 
1531 static inline ssize_t WriteBlobStream(Image *image,const size_t length,
1532  const void *data)
1533 {
1534  BlobInfo
1535  *magick_restrict blob_info;
1536 
1538  extent;
1539 
1540  register unsigned char
1541  *q;
1542 
1543  assert(image->blob != (BlobInfo *) NULL);
1544  assert(image->blob->type != UndefinedStream);
1545  assert(data != NULL);
1546  blob_info=image->blob;
1547  if (blob_info->type != BlobStream)
1548  return(WriteBlob(image,length,(const unsigned char *) data));
1549  extent=(MagickSizeType) (blob_info->offset+(MagickOffsetType) length);
1550  if (extent >= blob_info->extent)
1551  {
1552  extent=blob_info->extent+blob_info->quantum+length;
1553  blob_info->quantum<<=1;
1554  if (SetBlobExtent(image,extent) == MagickFalse)
1555  return(0);
1556  }
1557  q=blob_info->data+blob_info->offset;
1558  (void) memcpy(q,data,length);
1559  blob_info->offset+=length;
1560  if (blob_info->offset >= (MagickOffsetType) blob_info->length)
1561  blob_info->length=(size_t) blob_info->offset;
1562  return((ssize_t) length);
1563 }
1564 
1565 MagickExport MagickBooleanType FileToImage(Image *image,const char *filename,
1566  ExceptionInfo *exception)
1567 {
1568  int
1569  file;
1570 
1571  size_t
1572  length,
1573  quantum;
1574 
1575  ssize_t
1576  count;
1577 
1578  struct stat
1579  file_stats;
1580 
1581  unsigned char
1582  *blob;
1583 
1584  assert(image != (const Image *) NULL);
1585  assert(image->signature == MagickCoreSignature);
1586  assert(filename != (const char *) NULL);
1587  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1588  file=fileno(stdin);
1589  if (LocaleCompare(filename,"-") != 0)
1590  file=open_utf8(filename,O_RDONLY | O_BINARY,0);
1591  if (file == -1)
1592  {
1593  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
1594  return(MagickFalse);
1595  }
1596  quantum=(size_t) MagickMaxBufferExtent;
1597  if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
1598  quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
1599  blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
1600  if (blob == (unsigned char *) NULL)
1601  {
1602  file=close(file);
1603  ThrowFileException(exception,ResourceLimitError,"MemoryAllocationFailed",
1604  filename);
1605  return(MagickFalse);
1606  }
1607  for ( ; ; )
1608  {
1609  count=read(file,blob,quantum);
1610  if (count <= 0)
1611  {
1612  count=0;
1613  if (errno != EINTR)
1614  break;
1615  }
1616  length=(size_t) count;
1617  count=WriteBlobStream(image,length,blob);
1618  if (count != (ssize_t) length)
1619  {
1620  ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1621  break;
1622  }
1623  }
1624  file=close(file);
1625  if (file == -1)
1626  ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1627  blob=(unsigned char *) RelinquishMagickMemory(blob);
1628  return(MagickTrue);
1629 }
1630 
1631 /*
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 % %
1634 % %
1635 % %
1636 + G e t B l o b E r r o r %
1637 % %
1638 % %
1639 % %
1640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 %
1642 % GetBlobError() returns MagickTrue if the blob associated with the specified
1643 % image encountered an error.
1644 %
1645 % The format of the GetBlobError method is:
1646 %
1647 % MagickBooleanType GetBlobError(const Image *image)
1648 %
1649 % A description of each parameter follows:
1650 %
1651 % o image: the image.
1652 %
1653 */
1655 {
1656  assert(image != (const Image *) NULL);
1657  assert(image->signature == MagickCoreSignature);
1658  if (image->debug != MagickFalse)
1659  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1660  return(image->blob->status);
1661 }
1662 
1663 /*
1664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1665 % %
1666 % %
1667 % %
1668 + G e t B l o b F i l e H a n d l e %
1669 % %
1670 % %
1671 % %
1672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673 %
1674 % GetBlobFileHandle() returns the file handle associated with the image blob.
1675 %
1676 % The format of the GetBlobFile method is:
1677 %
1678 % FILE *GetBlobFileHandle(const Image *image)
1679 %
1680 % A description of each parameter follows:
1681 %
1682 % o image: the image.
1683 %
1684 */
1686 {
1687  assert(image != (const Image *) NULL);
1688  assert(image->signature == MagickCoreSignature);
1689  return(image->blob->file_info.file);
1690 }
1691 
1692 /*
1693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1694 % %
1695 % %
1696 % %
1697 + G e t B l o b I n f o %
1698 % %
1699 % %
1700 % %
1701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1702 %
1703 % GetBlobInfo() initializes the BlobInfo structure.
1704 %
1705 % The format of the GetBlobInfo method is:
1706 %
1707 % void GetBlobInfo(BlobInfo *blob_info)
1708 %
1709 % A description of each parameter follows:
1710 %
1711 % o blob_info: Specifies a pointer to a BlobInfo structure.
1712 %
1713 */
1715 {
1716  assert(blob_info != (BlobInfo *) NULL);
1717  (void) memset(blob_info,0,sizeof(*blob_info));
1718  blob_info->type=UndefinedStream;
1719  blob_info->quantum=(size_t) MagickMaxBlobExtent;
1720  blob_info->properties.st_mtime=time((time_t *) NULL);
1721  blob_info->properties.st_ctime=time((time_t *) NULL);
1722  blob_info->debug=IsEventLogging();
1723  blob_info->reference_count=1;
1724  blob_info->semaphore=AcquireSemaphoreInfo();
1725  blob_info->signature=MagickCoreSignature;
1726 }
1727 
1728 /*
1729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1730 % %
1731 % %
1732 % %
1733 % G e t B l o b P r o p e r t i e s %
1734 % %
1735 % %
1736 % %
1737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738 %
1739 % GetBlobProperties() returns information about an image blob.
1740 %
1741 % The format of the GetBlobProperties method is:
1742 %
1743 % const struct stat *GetBlobProperties(const Image *image)
1744 %
1745 % A description of each parameter follows:
1746 %
1747 % o image: the image.
1748 %
1749 */
1750 MagickExport const struct stat *GetBlobProperties(const Image *image)
1751 {
1752  assert(image != (Image *) NULL);
1753  assert(image->signature == MagickCoreSignature);
1754  if (image->debug != MagickFalse)
1755  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1756  return(&image->blob->properties);
1757 }
1758 
1759 /*
1760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761 % %
1762 % %
1763 % %
1764 + G e t B l o b S i z e %
1765 % %
1766 % %
1767 % %
1768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769 %
1770 % GetBlobSize() returns the current length of the image file or blob; zero is
1771 % returned if the size cannot be determined.
1772 %
1773 % The format of the GetBlobSize method is:
1774 %
1775 % MagickSizeType GetBlobSize(const Image *image)
1776 %
1777 % A description of each parameter follows:
1778 %
1779 % o image: the image.
1780 %
1781 */
1783 {
1784  BlobInfo
1785  *magick_restrict blob_info;
1786 
1788  extent;
1789 
1790  assert(image != (Image *) NULL);
1791  assert(image->signature == MagickCoreSignature);
1792  if (image->debug != MagickFalse)
1793  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1794  assert(image->blob != (BlobInfo *) NULL);
1795  blob_info=image->blob;
1796  extent=0;
1797  switch (blob_info->type)
1798  {
1799  case UndefinedStream:
1800  case StandardStream:
1801  {
1802  extent=blob_info->size;
1803  break;
1804  }
1805  case FileStream:
1806  {
1807  if (fstat(fileno(blob_info->file_info.file),&blob_info->properties) == 0)
1808  extent=(MagickSizeType) blob_info->properties.st_size;
1809  break;
1810  }
1811  case PipeStream:
1812  {
1813  extent=blob_info->size;
1814  break;
1815  }
1816  case ZipStream:
1817  case BZipStream:
1818  {
1820  status;
1821 
1822  status=GetPathAttributes(image->filename,&blob_info->properties);
1823  if (status != MagickFalse)
1824  extent=(MagickSizeType) blob_info->properties.st_size;
1825  break;
1826  }
1827  case FifoStream:
1828  break;
1829  case BlobStream:
1830  {
1831  extent=(MagickSizeType) blob_info->length;
1832  break;
1833  }
1834  case CustomStream:
1835  {
1836  if ((blob_info->custom_stream->teller != (CustomStreamTeller) NULL) &&
1837  (blob_info->custom_stream->seeker != (CustomStreamSeeker) NULL))
1838  {
1840  offset;
1841 
1842  offset=blob_info->custom_stream->teller(
1843  blob_info->custom_stream->data);
1844  extent=(MagickSizeType) blob_info->custom_stream->seeker(0,SEEK_END,
1845  blob_info->custom_stream->data);
1846  (void) blob_info->custom_stream->seeker(offset,SEEK_SET,
1847  blob_info->custom_stream->data);
1848  }
1849  break;
1850  }
1851  }
1852  return(extent);
1853 }
1854 
1855 /*
1856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1857 % %
1858 % %
1859 % %
1860 + G e t B l o b S t r e a m D a t a %
1861 % %
1862 % %
1863 % %
1864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865 %
1866 % GetBlobStreamData() returns the stream data for the image.
1867 %
1868 % The format of the GetBlobStreamData method is:
1869 %
1870 % void *GetBlobStreamData(const Image *image)
1871 %
1872 % A description of each parameter follows:
1873 %
1874 % o image: the image.
1875 %
1876 */
1878 {
1879  assert(image != (const Image *) NULL);
1880  assert(image->signature == MagickCoreSignature);
1881  return(image->blob->data);
1882 }
1883 
1884 /*
1885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1886 % %
1887 % %
1888 % %
1889 + G e t B l o b S t r e a m H a n d l e r %
1890 % %
1891 % %
1892 % %
1893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1894 %
1895 % GetBlobStreamHandler() returns the stream handler for the image.
1896 %
1897 % The format of the GetBlobStreamHandler method is:
1898 %
1899 % StreamHandler GetBlobStreamHandler(const Image *image)
1900 %
1901 % A description of each parameter follows:
1902 %
1903 % o image: the image.
1904 %
1905 */
1907 {
1908  assert(image != (const Image *) NULL);
1909  assert(image->signature == MagickCoreSignature);
1910  if (image->debug != MagickFalse)
1911  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1912  return(image->blob->stream);
1913 }
1914 
1915 /*
1916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1917 % %
1918 % %
1919 % %
1920 % I m a g e T o B l o b %
1921 % %
1922 % %
1923 % %
1924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1925 %
1926 % ImageToBlob() implements direct to memory image formats. It returns the
1927 % image as a formatted blob and its length. The magick member of the Image
1928 % structure determines the format of the returned blob (GIF, JPEG, PNG,
1929 % etc.). This method is the equivalent of WriteImage(), but writes the
1930 % formatted "file" to a memory buffer rather than to an actual file.
1931 %
1932 % The format of the ImageToBlob method is:
1933 %
1934 % void *ImageToBlob(const ImageInfo *image_info,Image *image,
1935 % size_t *length,ExceptionInfo *exception)
1936 %
1937 % A description of each parameter follows:
1938 %
1939 % o image_info: the image info.
1940 %
1941 % o image: the image.
1942 %
1943 % o length: return the actual length of the blob.
1944 %
1945 % o exception: return any errors or warnings in this structure.
1946 %
1947 */
1948 MagickExport void *ImageToBlob(const ImageInfo *image_info,
1949  Image *image,size_t *length,ExceptionInfo *exception)
1950 {
1951  const MagickInfo
1952  *magick_info;
1953 
1954  ImageInfo
1955  *blob_info;
1956 
1958  status;
1959 
1960  void
1961  *blob;
1962 
1963  assert(image_info != (const ImageInfo *) NULL);
1964  assert(image_info->signature == MagickCoreSignature);
1965  if (image_info->debug != MagickFalse)
1967  image_info->filename);
1968  assert(image != (Image *) NULL);
1969  assert(image->signature == MagickCoreSignature);
1970  assert(exception != (ExceptionInfo *) NULL);
1971  *length=0;
1972  blob=(unsigned char *) NULL;
1973  blob_info=CloneImageInfo(image_info);
1974  blob_info->adjoin=MagickFalse;
1975  (void) SetImageInfo(blob_info,1,exception);
1976  if (*blob_info->magick != '\0')
1977  (void) CopyMagickString(image->magick,blob_info->magick,MagickPathExtent);
1978  magick_info=GetMagickInfo(image->magick,exception);
1979  if (magick_info == (const MagickInfo *) NULL)
1980  {
1981  (void) ThrowMagickException(exception,GetMagickModule(),
1982  MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
1983  image->magick);
1984  blob_info=DestroyImageInfo(blob_info);
1985  return(blob);
1986  }
1987  (void) CopyMagickString(blob_info->magick,image->magick,MagickPathExtent);
1988  if (GetMagickBlobSupport(magick_info) != MagickFalse)
1989  {
1990  /*
1991  Native blob support for this image format.
1992  */
1993  blob_info->length=0;
1995  sizeof(unsigned char));
1996  if (blob_info->blob == NULL)
1997  (void) ThrowMagickException(exception,GetMagickModule(),
1998  ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1999  else
2000  {
2001  (void) CloseBlob(image);
2002  image->blob->exempt=MagickTrue;
2003  *image->filename='\0';
2004  status=WriteImage(blob_info,image,exception);
2005  *length=image->blob->length;
2006  blob=DetachBlob(image->blob);
2007  if (blob == (void *) NULL)
2008  blob_info->blob=RelinquishMagickMemory(blob_info->blob);
2009  else if (status == MagickFalse)
2010  blob=RelinquishMagickMemory(blob);
2011  else
2012  blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
2013  }
2014  }
2015  else
2016  {
2017  char
2018  unique[MagickPathExtent];
2019 
2020  int
2021  file;
2022 
2023  /*
2024  Write file to disk in blob image format.
2025  */
2026  file=AcquireUniqueFileResource(unique);
2027  if (file == -1)
2028  {
2029  ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2030  image_info->filename);
2031  }
2032  else
2033  {
2034  blob_info->file=fdopen(file,"wb");
2035  if (blob_info->file != (FILE *) NULL)
2036  {
2038  "%s:%s",image->magick,unique);
2039  status=WriteImage(blob_info,image,exception);
2040  (void) CloseBlob(image);
2041  (void) fclose(blob_info->file);
2042  if (status != MagickFalse)
2043  blob=FileToBlob(unique,~0UL,length,exception);
2044  }
2045  (void) RelinquishUniqueFileResource(unique);
2046  }
2047  }
2048  blob_info=DestroyImageInfo(blob_info);
2049  return(blob);
2050 }
2051 
2052 /*
2053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054 % %
2055 % %
2056 % %
2057 + I m a g e T o C u s t o m S t r e a m %
2058 % %
2059 % %
2060 % %
2061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2062 %
2063 % ImageToCustomStream() is the equivalent of WriteImage(), but writes the
2064 % formatted "file" to the custom stream rather than to an actual file.
2065 %
2066 % The format of the ImageToCustomStream method is:
2067 %
2068 % void ImageToCustomStream(const ImageInfo *image_info,Image *image,
2069 % ExceptionInfo *exception)
2070 %
2071 % A description of each parameter follows:
2072 %
2073 % o image_info: the image info.
2074 %
2075 % o image: the image.
2076 %
2077 % o exception: return any errors or warnings in this structure.
2078 %
2079 */
2080 MagickExport void ImageToCustomStream(const ImageInfo *image_info,Image *image,
2081  ExceptionInfo *exception)
2082 {
2083  const MagickInfo
2084  *magick_info;
2085 
2086  ImageInfo
2087  *clone_info;
2088 
2090  blob_support,
2091  status;
2092 
2093  assert(image_info != (const ImageInfo *) NULL);
2094  assert(image_info->signature == MagickCoreSignature);
2095  if (image_info->debug != MagickFalse)
2097  image_info->filename);
2098  assert(image != (Image *) NULL);
2099  assert(image->signature == MagickCoreSignature);
2100  assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
2101  assert(image_info->custom_stream->signature == MagickCoreSignature);
2102  assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
2103  assert(exception != (ExceptionInfo *) NULL);
2104  clone_info=CloneImageInfo(image_info);
2105  clone_info->adjoin=MagickFalse;
2106  (void) SetImageInfo(clone_info,1,exception);
2107  if (*clone_info->magick != '\0')
2108  (void) CopyMagickString(image->magick,clone_info->magick,MagickPathExtent);
2109  magick_info=GetMagickInfo(image->magick,exception);
2110  if (magick_info == (const MagickInfo *) NULL)
2111  {
2112  (void) ThrowMagickException(exception,GetMagickModule(),
2113  MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
2114  image->magick);
2115  clone_info=DestroyImageInfo(clone_info);
2116  return;
2117  }
2118  (void) CopyMagickString(clone_info->magick,image->magick,MagickPathExtent);
2119  blob_support=GetMagickBlobSupport(magick_info);
2120  if ((blob_support != MagickFalse) &&
2121  (GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
2122  {
2123  if ((clone_info->custom_stream->seeker == (CustomStreamSeeker) NULL) ||
2124  (clone_info->custom_stream->teller == (CustomStreamTeller) NULL))
2125  blob_support=MagickFalse;
2126  }
2127  if (blob_support != MagickFalse)
2128  {
2129  /*
2130  Native blob support for this image format.
2131  */
2132  (void) CloseBlob(image);
2133  *image->filename='\0';
2134  (void) WriteImage(clone_info,image,exception);
2135  (void) CloseBlob(image);
2136  }
2137  else
2138  {
2139  char
2140  unique[MagickPathExtent];
2141 
2142  int
2143  file;
2144 
2145  unsigned char
2146  *blob;
2147 
2148  /*
2149  Write file to disk in blob image format.
2150  */
2151  clone_info->custom_stream=(CustomStreamInfo *) NULL;
2152  blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
2153  sizeof(*blob));
2154  if (blob == (unsigned char *) NULL)
2155  {
2156  ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2157  image_info->filename);
2158  clone_info=DestroyImageInfo(clone_info);
2159  return;
2160  }
2161  file=AcquireUniqueFileResource(unique);
2162  if (file == -1)
2163  {
2164  ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2165  image_info->filename);
2166  blob=(unsigned char *) RelinquishMagickMemory(blob);
2167  clone_info=DestroyImageInfo(clone_info);
2168  return;
2169  }
2170  clone_info->file=fdopen(file,"wb+");
2171  if (clone_info->file != (FILE *) NULL)
2172  {
2173  ssize_t
2174  count;
2175 
2177  "%s:%s",image->magick,unique);
2178  status=WriteImage(clone_info,image,exception);
2179  (void) CloseBlob(image);
2180  if (status != MagickFalse)
2181  {
2182  (void) fseek(clone_info->file,0,SEEK_SET);
2183  count=(ssize_t) MagickMaxBufferExtent;
2184  while (count == (ssize_t) MagickMaxBufferExtent)
2185  {
2186  count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
2187  clone_info->file);
2188  (void) image_info->custom_stream->writer(blob,(size_t) count,
2189  image_info->custom_stream->data);
2190  }
2191  }
2192  (void) fclose(clone_info->file);
2193  }
2194  blob=(unsigned char *) RelinquishMagickMemory(blob);
2195  (void) RelinquishUniqueFileResource(unique);
2196  }
2197  clone_info=DestroyImageInfo(clone_info);
2198 }
2199 
2200 /*
2201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202 % %
2203 % %
2204 % %
2205 % I m a g e T o F i l e %
2206 % %
2207 % %
2208 % %
2209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2210 %
2211 % ImageToFile() writes an image to a file. It returns MagickFalse if an error
2212 % occurs otherwise MagickTrue.
2213 %
2214 % The format of the ImageToFile method is:
2215 %
2216 % MagickBooleanType ImageToFile(Image *image,char *filename,
2217 % ExceptionInfo *exception)
2218 %
2219 % A description of each parameter follows:
2220 %
2221 % o image: the image.
2222 %
2223 % o filename: Write the image to this file.
2224 %
2225 % o exception: return any errors or warnings in this structure.
2226 %
2227 */
2229  ExceptionInfo *exception)
2230 {
2231  int
2232  file;
2233 
2234  register const unsigned char
2235  *p;
2236 
2237  register size_t
2238  i;
2239 
2240  size_t
2241  length,
2242  quantum;
2243 
2244  ssize_t
2245  count;
2246 
2247  struct stat
2248  file_stats;
2249 
2250  unsigned char
2251  *buffer;
2252 
2253  assert(image != (Image *) NULL);
2254  assert(image->signature == MagickCoreSignature);
2255  assert(image->blob != (BlobInfo *) NULL);
2256  assert(image->blob->type != UndefinedStream);
2257  if (image->debug != MagickFalse)
2258  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
2259  assert(filename != (const char *) NULL);
2260  if (*filename == '\0')
2261  file=AcquireUniqueFileResource(filename);
2262  else
2263  if (LocaleCompare(filename,"-") == 0)
2264  file=fileno(stdout);
2265  else
2266  file=open_utf8(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
2267  if (file == -1)
2268  {
2269  ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
2270  return(MagickFalse);
2271  }
2272  quantum=(size_t) MagickMaxBufferExtent;
2273  if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
2274  quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
2275  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
2276  if (buffer == (unsigned char *) NULL)
2277  {
2278  file=close(file)-1;
2279  (void) ThrowMagickException(exception,GetMagickModule(),
2280  ResourceLimitError,"MemoryAllocationError","`%s'",filename);
2281  return(MagickFalse);
2282  }
2283  length=0;
2284  p=(const unsigned char *) ReadBlobStream(image,quantum,buffer,&count);
2285  for (i=0; count > 0; )
2286  {
2287  length=(size_t) count;
2288  for (i=0; i < length; i+=count)
2289  {
2290  count=write(file,p+i,(size_t) (length-i));
2291  if (count <= 0)
2292  {
2293  count=0;
2294  if (errno != EINTR)
2295  break;
2296  }
2297  }
2298  if (i < length)
2299  break;
2300  p=(const unsigned char *) ReadBlobStream(image,quantum,buffer,&count);
2301  }
2302  if (LocaleCompare(filename,"-") != 0)
2303  file=close(file);
2304  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2305  if ((file == -1) || (i < length))
2306  {
2307  if (file != -1)
2308  file=close(file);
2309  ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
2310  return(MagickFalse);
2311  }
2312  return(MagickTrue);
2313 }
2314 
2315 /*
2316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2317 % %
2318 % %
2319 % %
2320 % I m a g e s T o B l o b %
2321 % %
2322 % %
2323 % %
2324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2325 %
2326 % ImagesToBlob() implements direct to memory image formats. It returns the
2327 % image sequence as a blob and its length. The magick member of the ImageInfo
2328 % structure determines the format of the returned blob (GIF, JPEG, PNG, etc.)
2329 %
2330 % Note, some image formats do not permit multiple images to the same image
2331 % stream (e.g. JPEG). in this instance, just the first image of the
2332 % sequence is returned as a blob.
2333 %
2334 % The format of the ImagesToBlob method is:
2335 %
2336 % void *ImagesToBlob(const ImageInfo *image_info,Image *images,
2337 % size_t *length,ExceptionInfo *exception)
2338 %
2339 % A description of each parameter follows:
2340 %
2341 % o image_info: the image info.
2342 %
2343 % o images: the image list.
2344 %
2345 % o length: return the actual length of the blob.
2346 %
2347 % o exception: return any errors or warnings in this structure.
2348 %
2349 */
2350 MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images,
2351  size_t *length,ExceptionInfo *exception)
2352 {
2353  const MagickInfo
2354  *magick_info;
2355 
2356  ImageInfo
2357  *clone_info;
2358 
2360  status;
2361 
2362  void
2363  *blob;
2364 
2365  assert(image_info != (const ImageInfo *) NULL);
2366  assert(image_info->signature == MagickCoreSignature);
2367  if (image_info->debug != MagickFalse)
2369  image_info->filename);
2370  assert(images != (Image *) NULL);
2371  assert(images->signature == MagickCoreSignature);
2372  assert(exception != (ExceptionInfo *) NULL);
2373  *length=0;
2374  blob=(unsigned char *) NULL;
2375  clone_info=CloneImageInfo(image_info);
2376  (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(images),
2377  exception);
2378  if (*clone_info->magick != '\0')
2379  (void) CopyMagickString(images->magick,clone_info->magick,MagickPathExtent);
2380  magick_info=GetMagickInfo(images->magick,exception);
2381  if (magick_info == (const MagickInfo *) NULL)
2382  {
2383  (void) ThrowMagickException(exception,GetMagickModule(),
2384  MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
2385  images->magick);
2386  clone_info=DestroyImageInfo(clone_info);
2387  return(blob);
2388  }
2389  if (GetMagickAdjoin(magick_info) == MagickFalse)
2390  {
2391  clone_info=DestroyImageInfo(clone_info);
2392  return(ImageToBlob(image_info,images,length,exception));
2393  }
2394  (void) CopyMagickString(clone_info->magick,images->magick,MagickPathExtent);
2395  if (GetMagickBlobSupport(magick_info) != MagickFalse)
2396  {
2397  /*
2398  Native blob support for this images format.
2399  */
2400  clone_info->length=0;
2401  clone_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
2402  sizeof(unsigned char));
2403  if (clone_info->blob == (void *) NULL)
2404  (void) ThrowMagickException(exception,GetMagickModule(),
2405  ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
2406  else
2407  {
2408  (void) CloseBlob(images);
2409  images->blob->exempt=MagickTrue;
2410  *images->filename='\0';
2411  status=WriteImages(clone_info,images,images->filename,exception);
2412  *length=images->blob->length;
2413  blob=DetachBlob(images->blob);
2414  if (blob == (void *) NULL)
2415  clone_info->blob=RelinquishMagickMemory(clone_info->blob);
2416  else if (status == MagickFalse)
2417  blob=RelinquishMagickMemory(blob);
2418  else
2419  blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
2420  }
2421  }
2422  else
2423  {
2424  char
2425  filename[MagickPathExtent],
2426  unique[MagickPathExtent];
2427 
2428  int
2429  file;
2430 
2431  /*
2432  Write file to disk in blob images format.
2433  */
2434  file=AcquireUniqueFileResource(unique);
2435  if (file == -1)
2436  {
2437  ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",
2438  image_info->filename);
2439  }
2440  else
2441  {
2442  clone_info->file=fdopen(file,"wb");
2443  if (clone_info->file != (FILE *) NULL)
2444  {
2445  (void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
2446  images->magick,unique);
2447  status=WriteImages(clone_info,images,filename,exception);
2448  (void) CloseBlob(images);
2449  (void) fclose(clone_info->file);
2450  if (status != MagickFalse)
2451  blob=FileToBlob(unique,~0UL,length,exception);
2452  }
2453  (void) RelinquishUniqueFileResource(unique);
2454  }
2455  }
2456  clone_info=DestroyImageInfo(clone_info);
2457  return(blob);
2458 }
2459 
2460 /*
2461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462 % %
2463 % %
2464 % %
2465 + I m a g e s T o C u s t o m B l o b %
2466 % %
2467 % %
2468 % %
2469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470 %
2471 % ImagesToCustomStream() is the equivalent of WriteImages(), but writes the
2472 % formatted "file" to the custom stream rather than to an actual file.
2473 %
2474 % The format of the ImageToCustomStream method is:
2475 %
2476 % void ImagesToCustomStream(const ImageInfo *image_info,Image *images,
2477 % ExceptionInfo *exception)
2478 %
2479 % A description of each parameter follows:
2480 %
2481 % o image_info: the image info.
2482 %
2483 % o images: the image list.
2484 %
2485 % o exception: return any errors or warnings in this structure.
2486 %
2487 */
2489  Image *images,ExceptionInfo *exception)
2490 {
2491  const MagickInfo
2492  *magick_info;
2493 
2494  ImageInfo
2495  *clone_info;
2496 
2498  blob_support,
2499  status;
2500 
2501  assert(image_info != (const ImageInfo *) NULL);
2502  assert(image_info->signature == MagickCoreSignature);
2503  if (image_info->debug != MagickFalse)
2505  image_info->filename);
2506  assert(images != (Image *) NULL);
2507  assert(images->signature == MagickCoreSignature);
2508  assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
2509  assert(image_info->custom_stream->signature == MagickCoreSignature);
2510  assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
2511  assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
2512  assert(exception != (ExceptionInfo *) NULL);
2513  clone_info=CloneImageInfo(image_info);
2514  (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(images),
2515  exception);
2516  if (*clone_info->magick != '\0')
2517  (void) CopyMagickString(images->magick,clone_info->magick,MagickPathExtent);
2518  magick_info=GetMagickInfo(images->magick,exception);
2519  if (magick_info == (const MagickInfo *) NULL)
2520  {
2521  (void) ThrowMagickException(exception,GetMagickModule(),
2522  MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
2523  images->magick);
2524  clone_info=DestroyImageInfo(clone_info);
2525  return;
2526  }
2527  (void) CopyMagickString(clone_info->magick,images->magick,MagickPathExtent);
2528  blob_support=GetMagickBlobSupport(magick_info);
2529  if ((blob_support != MagickFalse) &&
2530  (GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
2531  {
2532  if ((clone_info->custom_stream->seeker == (CustomStreamSeeker) NULL) ||
2533  (clone_info->custom_stream->teller == (CustomStreamTeller) NULL))
2534  blob_support=MagickFalse;
2535  }
2536  if (blob_support != MagickFalse)
2537  {
2538  /*
2539  Native blob support for this image format.
2540  */
2541  (void) CloseBlob(images);
2542  *images->filename='\0';
2543  (void) WriteImages(clone_info,images,images->filename,exception);
2544  (void) CloseBlob(images);
2545  }
2546  else
2547  {
2548  char
2549  filename[MagickPathExtent],
2550  unique[MagickPathExtent];
2551 
2552  int
2553  file;
2554 
2555  unsigned char
2556  *blob;
2557 
2558  /*
2559  Write file to disk in blob image format.
2560  */
2561  clone_info->custom_stream=(CustomStreamInfo *) NULL;
2562  blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
2563  sizeof(*blob));
2564  if (blob == (unsigned char *) NULL)
2565  {
2566  ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2567  image_info->filename);
2568  clone_info=DestroyImageInfo(clone_info);
2569  return;
2570  }
2571  file=AcquireUniqueFileResource(unique);
2572  if (file == -1)
2573  {
2574  ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2575  image_info->filename);
2576  blob=(unsigned char *) RelinquishMagickMemory(blob);
2577  clone_info=DestroyImageInfo(clone_info);
2578  return;
2579  }
2580  clone_info->file=fdopen(file,"wb+");
2581  if (clone_info->file != (FILE *) NULL)
2582  {
2583  ssize_t
2584  count;
2585 
2586  (void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
2587  images->magick,unique);
2588  status=WriteImages(clone_info,images,filename,exception);
2589  (void) CloseBlob(images);
2590  if (status != MagickFalse)
2591  {
2592  (void) fseek(clone_info->file,0,SEEK_SET);
2593  count=(ssize_t) MagickMaxBufferExtent;
2594  while (count == (ssize_t) MagickMaxBufferExtent)
2595  {
2596  count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
2597  clone_info->file);
2598  (void) image_info->custom_stream->writer(blob,(size_t) count,
2599  image_info->custom_stream->data);
2600  }
2601  }
2602  (void) fclose(clone_info->file);
2603  }
2604  blob=(unsigned char *) RelinquishMagickMemory(blob);
2605  (void) RelinquishUniqueFileResource(unique);
2606  }
2607  clone_info=DestroyImageInfo(clone_info);
2608 }
2609 
2610 /*
2611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2612 % %
2613 % %
2614 % %
2615 % I n j e c t I m a g e B l o b %
2616 % %
2617 % %
2618 % %
2619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620 %
2621 % InjectImageBlob() injects the image with a copy of itself in the specified
2622 % format (e.g. inject JPEG into a PDF image).
2623 %
2624 % The format of the InjectImageBlob method is:
2625 %
2626 % MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
2627 % Image *image,Image *inject_image,const char *format,
2628 % ExceptionInfo *exception)
2629 %
2630 % A description of each parameter follows:
2631 %
2632 % o image_info: the image info..
2633 %
2634 % o image: the image.
2635 %
2636 % o inject_image: inject into the image stream.
2637 %
2638 % o format: the image format.
2639 %
2640 % o exception: return any errors or warnings in this structure.
2641 %
2642 */
2644  Image *image,Image *inject_image,const char *format,ExceptionInfo *exception)
2645 {
2646  char
2647  filename[MagickPathExtent];
2648 
2649  FILE
2650  *unique_file;
2651 
2652  Image
2653  *byte_image;
2654 
2655  ImageInfo
2656  *write_info;
2657 
2658  int
2659  file;
2660 
2662  status;
2663 
2664  register ssize_t
2665  i;
2666 
2667  size_t
2668  quantum;
2669 
2670  ssize_t
2671  count;
2672 
2673  struct stat
2674  file_stats;
2675 
2676  unsigned char
2677  *buffer;
2678 
2679  /*
2680  Write inject image to a temporary file.
2681  */
2682  assert(image_info != (ImageInfo *) NULL);
2683  assert(image_info->signature == MagickCoreSignature);
2684  assert(image != (Image *) NULL);
2685  assert(image->signature == MagickCoreSignature);
2686  if (image->debug != MagickFalse)
2687  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2688  assert(inject_image != (Image *) NULL);
2689  assert(inject_image->signature == MagickCoreSignature);
2690  assert(exception != (ExceptionInfo *) NULL);
2691  unique_file=(FILE *) NULL;
2692  file=AcquireUniqueFileResource(filename);
2693  if (file != -1)
2694  unique_file=fdopen(file,"wb");
2695  if ((file == -1) || (unique_file == (FILE *) NULL))
2696  {
2697  (void) CopyMagickString(image->filename,filename,MagickPathExtent);
2698  ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2699  image->filename);
2700  return(MagickFalse);
2701  }
2702  byte_image=CloneImage(inject_image,0,0,MagickFalse,exception);
2703  if (byte_image == (Image *) NULL)
2704  {
2705  (void) fclose(unique_file);
2706  (void) RelinquishUniqueFileResource(filename);
2707  return(MagickFalse);
2708  }
2709  (void) FormatLocaleString(byte_image->filename,MagickPathExtent,"%s:%s",
2710  format,filename);
2711  DestroyBlob(byte_image);
2712  byte_image->blob=CloneBlobInfo((BlobInfo *) NULL);
2713  write_info=CloneImageInfo(image_info);
2714  SetImageInfoFile(write_info,unique_file);
2715  status=WriteImage(write_info,byte_image,exception);
2716  write_info=DestroyImageInfo(write_info);
2717  byte_image=DestroyImage(byte_image);
2718  (void) fclose(unique_file);
2719  if (status == MagickFalse)
2720  {
2721  (void) RelinquishUniqueFileResource(filename);
2722  return(MagickFalse);
2723  }
2724  /*
2725  Inject into image stream.
2726  */
2727  file=open_utf8(filename,O_RDONLY | O_BINARY,0);
2728  if (file == -1)
2729  {
2730  (void) RelinquishUniqueFileResource(filename);
2731  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
2732  image_info->filename);
2733  return(MagickFalse);
2734  }
2735  quantum=(size_t) MagickMaxBufferExtent;
2736  if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
2737  quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
2738  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
2739  if (buffer == (unsigned char *) NULL)
2740  {
2741  (void) RelinquishUniqueFileResource(filename);
2742  file=close(file);
2743  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2744  image->filename);
2745  }
2746  for (i=0; ; i+=count)
2747  {
2748  count=read(file,buffer,quantum);
2749  if (count <= 0)
2750  {
2751  count=0;
2752  if (errno != EINTR)
2753  break;
2754  }
2755  status=WriteBlobStream(image,(size_t) count,buffer) == count ? MagickTrue :
2756  MagickFalse;
2757  }
2758  file=close(file);
2759  if (file == -1)
2760  ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",filename);
2761  (void) RelinquishUniqueFileResource(filename);
2762  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2763  return(status);
2764 }
2765 
2766 /*
2767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768 % %
2769 % %
2770 % %
2771 % I s B l o b E x e m p t %
2772 % %
2773 % %
2774 % %
2775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776 %
2777 % IsBlobExempt() returns true if the blob is exempt.
2778 %
2779 % The format of the IsBlobExempt method is:
2780 %
2781 % MagickBooleanType IsBlobExempt(const Image *image)
2782 %
2783 % A description of each parameter follows:
2784 %
2785 % o image: the image.
2786 %
2787 */
2789 {
2790  assert(image != (const Image *) NULL);
2791  assert(image->signature == MagickCoreSignature);
2792  if (image->debug != MagickFalse)
2793  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2794  return(image->blob->exempt);
2795 }
2796 
2797 /*
2798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2799 % %
2800 % %
2801 % %
2802 % I s B l o b S e e k a b l e %
2803 % %
2804 % %
2805 % %
2806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2807 %
2808 % IsBlobSeekable() returns true if the blob is seekable.
2809 %
2810 % The format of the IsBlobSeekable method is:
2811 %
2812 % MagickBooleanType IsBlobSeekable(const Image *image)
2813 %
2814 % A description of each parameter follows:
2815 %
2816 % o image: the image.
2817 %
2818 */
2820 {
2821  BlobInfo
2822  *magick_restrict blob_info;
2823 
2824  assert(image != (const Image *) NULL);
2825  assert(image->signature == MagickCoreSignature);
2826  if (image->debug != MagickFalse)
2827  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2828  blob_info=image->blob;
2829  switch (blob_info->type)
2830  {
2831  case BlobStream:
2832  return(MagickTrue);
2833  case FileStream:
2834  {
2835  int
2836  status;
2837 
2838  if (blob_info->file_info.file == (FILE *) NULL)
2839  return(MagickFalse);
2840  status=fseek(blob_info->file_info.file,0,SEEK_CUR);
2841  return(status == -1 ? MagickFalse : MagickTrue);
2842  }
2843  case ZipStream:
2844  {
2845 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2846  int
2847  status;
2848 
2849  if (blob_info->file_info.gzfile == (gzFile) NULL)
2850  return(MagickFalse);
2851  status=gzseek(blob_info->file_info.gzfile,0,SEEK_CUR);
2852  return(status == -1 ? MagickFalse : MagickTrue);
2853 #else
2854  break;
2855 #endif
2856  }
2857  case UndefinedStream:
2858  case BZipStream:
2859  case FifoStream:
2860  case PipeStream:
2861  case StandardStream:
2862  break;
2863  case CustomStream:
2864  {
2865  if ((blob_info->custom_stream->seeker != (CustomStreamSeeker) NULL) &&
2866  (blob_info->custom_stream->teller != (CustomStreamTeller) NULL))
2867  return(MagickTrue);
2868  break;
2869  }
2870  default:
2871  break;
2872  }
2873  return(MagickFalse);
2874 }
2875 
2876 /*
2877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878 % %
2879 % %
2880 % %
2881 % I s B l o b T e m p o r a r y %
2882 % %
2883 % %
2884 % %
2885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886 %
2887 % IsBlobTemporary() returns true if the blob is temporary.
2888 %
2889 % The format of the IsBlobTemporary method is:
2890 %
2891 % MagickBooleanType IsBlobTemporary(const Image *image)
2892 %
2893 % A description of each parameter follows:
2894 %
2895 % o image: the image.
2896 %
2897 */
2899 {
2900  assert(image != (const Image *) NULL);
2901  assert(image->signature == MagickCoreSignature);
2902  if (image->debug != MagickFalse)
2903  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2904  return(image->blob->temporary);
2905 }
2906 
2907 /*
2908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2909 % %
2910 % %
2911 % %
2912 + M a p B l o b %
2913 % %
2914 % %
2915 % %
2916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2917 %
2918 % MapBlob() creates a mapping from a file to a binary large object.
2919 %
2920 % The format of the MapBlob method is:
2921 %
2922 % void *MapBlob(int file,const MapMode mode,const MagickOffsetType offset,
2923 % const size_t length)
2924 %
2925 % A description of each parameter follows:
2926 %
2927 % o file: map this file descriptor.
2928 %
2929 % o mode: ReadMode, WriteMode, or IOMode.
2930 %
2931 % o offset: starting at this offset within the file.
2932 %
2933 % o length: the length of the mapping is returned in this pointer.
2934 %
2935 */
2936 MagickExport void *MapBlob(int file,const MapMode mode,
2937  const MagickOffsetType offset,const size_t length)
2938 {
2939 #if defined(MAGICKCORE_HAVE_MMAP)
2940  int
2941  flags,
2942  protection;
2943 
2944  void
2945  *map;
2946 
2947  /*
2948  Map file.
2949  */
2950  flags=0;
2951  if (file == -1)
2952 #if defined(MAP_ANONYMOUS)
2953  flags|=MAP_ANONYMOUS;
2954 #else
2955  return(NULL);
2956 #endif
2957  switch (mode)
2958  {
2959  case ReadMode:
2960  default:
2961  {
2962  protection=PROT_READ;
2963  flags|=MAP_PRIVATE;
2964  break;
2965  }
2966  case WriteMode:
2967  {
2968  protection=PROT_WRITE;
2969  flags|=MAP_SHARED;
2970  break;
2971  }
2972  case IOMode:
2973  {
2974  protection=PROT_READ | PROT_WRITE;
2975  flags|=MAP_SHARED;
2976  break;
2977  }
2978  }
2979 #if !defined(MAGICKCORE_HAVE_HUGEPAGES) || !defined(MAP_HUGETLB)
2980  map=mmap((char *) NULL,length,protection,flags,file,(off_t) offset);
2981 #else
2982  map=mmap((char *) NULL,length,protection,flags | MAP_HUGETLB,file,(off_t)
2983  offset);
2984  if (map == MAP_FAILED)
2985  map=mmap((char *) NULL,length,protection,flags,file,(off_t) offset);
2986 #endif
2987  if (map == MAP_FAILED)
2988  return(NULL);
2989  return(map);
2990 #else
2991  (void) file;
2992  (void) mode;
2993  (void) offset;
2994  (void) length;
2995  return(NULL);
2996 #endif
2997 }
2998 
2999 /*
3000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001 % %
3002 % %
3003 % %
3004 + M S B O r d e r L o n g %
3005 % %
3006 % %
3007 % %
3008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3009 %
3010 % MSBOrderLong() converts a least-significant byte first buffer of integers to
3011 % most-significant byte first.
3012 %
3013 % The format of the MSBOrderLong method is:
3014 %
3015 % void MSBOrderLong(unsigned char *buffer,const size_t length)
3016 %
3017 % A description of each parameter follows.
3018 %
3019 % o buffer: Specifies a pointer to a buffer of integers.
3020 %
3021 % o length: Specifies the length of the buffer.
3022 %
3023 */
3024 MagickExport void MSBOrderLong(unsigned char *buffer,const size_t length)
3025 {
3026  int
3027  c;
3028 
3029  register unsigned char
3030  *p,
3031  *q;
3032 
3033  assert(buffer != (unsigned char *) NULL);
3034  q=buffer+length;
3035  while (buffer < q)
3036  {
3037  p=buffer+3;
3038  c=(int) (*p);
3039  *p=(*buffer);
3040  *buffer++=(unsigned char) c;
3041  p=buffer+1;
3042  c=(int) (*p);
3043  *p=(*buffer);
3044  *buffer++=(unsigned char) c;
3045  buffer+=2;
3046  }
3047 }
3048 
3049 /*
3050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3051 % %
3052 % %
3053 % %
3054 + M S B O r d e r S h o r t %
3055 % %
3056 % %
3057 % %
3058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3059 %
3060 % MSBOrderShort() converts a least-significant byte first buffer of integers
3061 % to most-significant byte first.
3062 %
3063 % The format of the MSBOrderShort method is:
3064 %
3065 % void MSBOrderShort(unsigned char *p,const size_t length)
3066 %
3067 % A description of each parameter follows.
3068 %
3069 % o p: Specifies a pointer to a buffer of integers.
3070 %
3071 % o length: Specifies the length of the buffer.
3072 %
3073 */
3074 MagickExport void MSBOrderShort(unsigned char *p,const size_t length)
3075 {
3076  int
3077  c;
3078 
3079  register unsigned char
3080  *q;
3081 
3082  assert(p != (unsigned char *) NULL);
3083  q=p+length;
3084  while (p < q)
3085  {
3086  c=(int) (*p);
3087  *p=(*(p+1));
3088  p++;
3089  *p++=(unsigned char) c;
3090  }
3091 }
3092 
3093 /*
3094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3095 % %
3096 % %
3097 % %
3098 + O p e n B l o b %
3099 % %
3100 % %
3101 % %
3102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3103 %
3104 % OpenBlob() opens a file associated with the image. A file name of '-' sets
3105 % the file to stdin for type 'r' and stdout for type 'w'. If the filename
3106 % suffix is '.gz' or '.Z', the image is decompressed for type 'r' and
3107 % compressed for type 'w'. If the filename prefix is '|', it is piped to or
3108 % from a system command.
3109 %
3110 % The format of the OpenBlob method is:
3111 %
3112 % MagickBooleanType OpenBlob(const ImageInfo *image_info,Image *image,
3113 % const BlobMode mode,ExceptionInfo *exception)
3114 %
3115 % A description of each parameter follows:
3116 %
3117 % o image_info: the image info.
3118 %
3119 % o image: the image.
3120 %
3121 % o mode: the mode for opening the file.
3122 %
3123 */
3124 
3125 static inline MagickBooleanType SetStreamBuffering(const ImageInfo *image_info,
3126  Image *image)
3127 {
3128  const char
3129  *option;
3130 
3131  int
3132  status;
3133 
3134  size_t
3135  size;
3136 
3137  size=16384;
3138  option=GetImageOption(image_info,"stream:buffer-size");
3139  if (option != (const char *) NULL)
3140  size=StringToUnsignedLong(option);
3141  status=setvbuf(image->blob->file_info.file,(char *) NULL,size == 0 ?
3142  _IONBF : _IOFBF,size);
3143  return(status == 0 ? MagickTrue : MagickFalse);
3144 }
3145 
3147  Image *image,const BlobMode mode,ExceptionInfo *exception)
3148 {
3149  BlobInfo
3150  *magick_restrict blob_info;
3151 
3152  char
3153  extension[MagickPathExtent],
3154  filename[MagickPathExtent];
3155 
3156  const char
3157  *type;
3158 
3160  status;
3161 
3162  PolicyRights
3163  rights;
3164 
3165  assert(image_info != (ImageInfo *) NULL);
3166  assert(image_info->signature == MagickCoreSignature);
3167  if (image_info->debug != MagickFalse)
3169  image_info->filename);
3170  assert(image != (Image *) NULL);
3171  assert(image->signature == MagickCoreSignature);
3172  blob_info=image->blob;
3173  if (image_info->blob != (void *) NULL)
3174  {
3175  if (image_info->stream != (StreamHandler) NULL)
3176  blob_info->stream=(StreamHandler) image_info->stream;
3177  AttachBlob(blob_info,image_info->blob,image_info->length);
3178  return(MagickTrue);
3179  }
3180  if ((image_info->custom_stream != (CustomStreamInfo *) NULL) &&
3181  (*image->filename == '\0'))
3182  {
3183  blob_info->type=CustomStream;
3184  blob_info->custom_stream=image_info->custom_stream;
3185  return(MagickTrue);
3186  }
3187  (void) DetachBlob(blob_info);
3188  blob_info->mode=mode;
3189  switch (mode)
3190  {
3191  default: type="r"; break;
3192  case ReadBlobMode: type="r"; break;
3193  case ReadBinaryBlobMode: type="rb"; break;
3194  case WriteBlobMode: type="w"; break;
3195  case WriteBinaryBlobMode: type="w+b"; break;
3196  case AppendBlobMode: type="a"; break;
3197  case AppendBinaryBlobMode: type="a+b"; break;
3198  }
3199  if (*type != 'r')
3200  blob_info->synchronize=image_info->synchronize;
3201  if (image_info->stream != (StreamHandler) NULL)
3202  {
3203  blob_info->stream=image_info->stream;
3204  if (*type == 'w')
3205  {
3206  blob_info->type=FifoStream;
3207  return(MagickTrue);
3208  }
3209  }
3210  /*
3211  Open image file.
3212  */
3213  *filename='\0';
3214  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
3215  rights=ReadPolicyRights;
3216  if (*type == 'w')
3217  rights=WritePolicyRights;
3218  if (IsRightsAuthorized(PathPolicyDomain,rights,filename) == MagickFalse)
3219  {
3220  errno=EPERM;
3222  "NotAuthorized","`%s'",filename);
3223  return(MagickFalse);
3224  }
3225  if ((LocaleCompare(filename,"-") == 0) ||
3226  ((*filename == '\0') && (image_info->file == (FILE *) NULL)))
3227  {
3228  blob_info->file_info.file=(*type == 'r') ? stdin : stdout;
3229 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
3230  if (strchr(type,'b') != (char *) NULL)
3231  setmode(fileno(blob_info->file_info.file),_O_BINARY);
3232 #endif
3233  blob_info->type=StandardStream;
3234  blob_info->exempt=MagickTrue;
3235  return(SetStreamBuffering(image_info,image));
3236  }
3237  if ((LocaleNCompare(filename,"fd:",3) == 0) &&
3238  (IsGeometry(filename+3) != MagickFalse))
3239  {
3240  char
3241  fileMode[MagickPathExtent];
3242 
3243  *fileMode =(*type);
3244  fileMode[1]='\0';
3245  blob_info->file_info.file=fdopen(StringToLong(filename+3),fileMode);
3246  if (blob_info->file_info.file == (FILE *) NULL)
3247  {
3248  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3249  return(MagickFalse);
3250  }
3251 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
3252  if (strchr(type,'b') != (char *) NULL)
3253  setmode(fileno(blob_info->file_info.file),_O_BINARY);
3254 #endif
3255  blob_info->type=FileStream;
3256  blob_info->exempt=MagickTrue;
3257  return(SetStreamBuffering(image_info,image));
3258  }
3259 #if defined(MAGICKCORE_HAVE_POPEN) && defined(MAGICKCORE_PIPES_SUPPORT)
3260  if (*filename == '|')
3261  {
3262  char
3263  fileMode[MagickPathExtent],
3264  *sanitize_command;
3265 
3266  /*
3267  Pipe image to or from a system command.
3268  */
3269 #if defined(SIGPIPE)
3270  if (*type == 'w')
3271  (void) signal(SIGPIPE,SIG_IGN);
3272 #endif
3273  *fileMode =(*type);
3274  fileMode[1]='\0';
3275  sanitize_command=SanitizeString(filename+1);
3276  blob_info->file_info.file=(FILE *) popen_utf8(sanitize_command,fileMode);
3277  sanitize_command=DestroyString(sanitize_command);
3278  if (blob_info->file_info.file == (FILE *) NULL)
3279  {
3280  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3281  return(MagickFalse);
3282  }
3283  blob_info->type=PipeStream;
3284  blob_info->exempt=MagickTrue;
3285  return(SetStreamBuffering(image_info,image));
3286  }
3287 #endif
3288  status=GetPathAttributes(filename,&blob_info->properties);
3289 #if defined(S_ISFIFO)
3290  if ((status != MagickFalse) && S_ISFIFO(blob_info->properties.st_mode))
3291  {
3292  blob_info->file_info.file=(FILE *) fopen_utf8(filename,type);
3293  if (blob_info->file_info.file == (FILE *) NULL)
3294  {
3295  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3296  return(MagickFalse);
3297  }
3298  blob_info->type=FileStream;
3299  blob_info->exempt=MagickTrue;
3300  return(SetStreamBuffering(image_info,image));
3301  }
3302 #endif
3303  GetPathComponent(image->filename,ExtensionPath,extension);
3304  if (*type == 'w')
3305  {
3306  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
3307  if ((image_info->adjoin == MagickFalse) ||
3308  (strchr(filename,'%') != (char *) NULL))
3309  {
3310  /*
3311  Form filename for multi-part images.
3312  */
3313  (void) InterpretImageFilename(image_info,image,image->filename,(int)
3314  image->scene,filename,exception);
3315  if ((LocaleCompare(filename,image->filename) == 0) &&
3316  ((GetPreviousImageInList(image) != (Image *) NULL) ||
3317  (GetNextImageInList(image) != (Image *) NULL)))
3318  {
3319  char
3320  path[MagickPathExtent];
3321 
3322  GetPathComponent(image->filename,RootPath,path);
3323  if (*extension == '\0')
3324  (void) FormatLocaleString(filename,MagickPathExtent,"%s-%.20g",
3325  path,(double) image->scene);
3326  else
3327  (void) FormatLocaleString(filename,MagickPathExtent,
3328  "%s-%.20g.%s",path,(double) image->scene,extension);
3329  }
3330  (void) CopyMagickString(image->filename,filename,MagickPathExtent);
3331 #if defined(macintosh)
3332  SetApplicationType(filename,image_info->magick,'8BIM');
3333 #endif
3334  }
3335  }
3336  if (image_info->file != (FILE *) NULL)
3337  {
3338  blob_info->file_info.file=image_info->file;
3339  blob_info->type=FileStream;
3340  blob_info->exempt=MagickTrue;
3341  }
3342  else
3343  if (*type == 'r')
3344  {
3345  blob_info->file_info.file=(FILE *) fopen_utf8(filename,type);
3346  if (blob_info->file_info.file != (FILE *) NULL)
3347  {
3348  size_t
3349  count;
3350 
3351  unsigned char
3352  magick[3];
3353 
3354  blob_info->type=FileStream;
3355  (void) SetStreamBuffering(image_info,image);
3356  (void) memset(magick,0,sizeof(magick));
3357  count=fread(magick,1,sizeof(magick),blob_info->file_info.file);
3358  (void) fseek(blob_info->file_info.file,-((off_t) count),SEEK_CUR);
3359 #if defined(MAGICKCORE_POSIX_SUPPORT)
3360  (void) fflush(blob_info->file_info.file);
3361 #endif
3363  " read %.20g magic header bytes",(double) count);
3364 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3365  if (((int) magick[0] == 0x1F) && ((int) magick[1] == 0x8B) &&
3366  ((int) magick[2] == 0x08))
3367  {
3368  if (blob_info->file_info.file != (FILE *) NULL)
3369  (void) fclose(blob_info->file_info.file);
3370  blob_info->file_info.file=(FILE *) NULL;
3371  blob_info->file_info.gzfile=gzopen(filename,"rb");
3372  if (blob_info->file_info.gzfile != (gzFile) NULL)
3373  blob_info->type=ZipStream;
3374  }
3375 #endif
3376 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3377  if (strncmp((char *) magick,"BZh",3) == 0)
3378  {
3379  if (blob_info->file_info.file != (FILE *) NULL)
3380  (void) fclose(blob_info->file_info.file);
3381  blob_info->file_info.file=(FILE *) NULL;
3382  blob_info->file_info.bzfile=BZ2_bzopen(filename,"r");
3383  if (blob_info->file_info.bzfile != (BZFILE *) NULL)
3384  blob_info->type=BZipStream;
3385  }
3386 #endif
3387  if (blob_info->type == FileStream)
3388  {
3389  const MagickInfo
3390  *magick_info;
3391 
3393  *sans_exception;
3394 
3395  size_t
3396  length;
3397 
3398  sans_exception=AcquireExceptionInfo();
3399  magick_info=GetMagickInfo(image_info->magick,sans_exception);
3400  sans_exception=DestroyExceptionInfo(sans_exception);
3401  length=(size_t) blob_info->properties.st_size;
3402  if ((magick_info != (const MagickInfo *) NULL) &&
3403  (GetMagickBlobSupport(magick_info) != MagickFalse) &&
3404  (length > MagickMaxBufferExtent) &&
3406  {
3407  void
3408  *blob;
3409 
3410  blob=MapBlob(fileno(blob_info->file_info.file),ReadMode,0,
3411  length);
3412  if (blob == (void *) NULL)
3414  else
3415  {
3416  /*
3417  Format supports blobs-- use memory-mapped I/O.
3418  */
3419  if (image_info->file != (FILE *) NULL)
3420  blob_info->exempt=MagickFalse;
3421  else
3422  {
3423  (void) fclose(blob_info->file_info.file);
3424  blob_info->file_info.file=(FILE *) NULL;
3425  }
3426  AttachBlob(blob_info,blob,length);
3427  blob_info->mapped=MagickTrue;
3428  }
3429  }
3430  }
3431  }
3432  }
3433  else
3434 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3435  if ((LocaleCompare(extension,"Z") == 0) ||
3436  (LocaleCompare(extension,"gz") == 0) ||
3437  (LocaleCompare(extension,"wmz") == 0) ||
3438  (LocaleCompare(extension,"svgz") == 0))
3439  {
3440  blob_info->file_info.gzfile=gzopen(filename,"wb");
3441  if (blob_info->file_info.gzfile != (gzFile) NULL)
3442  blob_info->type=ZipStream;
3443  }
3444  else
3445 #endif
3446 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3447  if (LocaleCompare(extension,"bz2") == 0)
3448  {
3449  blob_info->file_info.bzfile=BZ2_bzopen(filename,"w");
3450  if (blob_info->file_info.bzfile != (BZFILE *) NULL)
3451  blob_info->type=BZipStream;
3452  }
3453  else
3454 #endif
3455  {
3456  blob_info->file_info.file=(FILE *) fopen_utf8(filename,type);
3457  if (blob_info->file_info.file != (FILE *) NULL)
3458  {
3459  blob_info->type=FileStream;
3460  (void) SetStreamBuffering(image_info,image);
3461  }
3462  }
3463  blob_info->status=MagickFalse;
3464  if (blob_info->type != UndefinedStream)
3465  blob_info->size=GetBlobSize(image);
3466  else
3467  {
3468  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3469  return(MagickFalse);
3470  }
3471  return(MagickTrue);
3472 }
3473 
3474 /*
3475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3476 % %
3477 % %
3478 % %
3479 + P i n g B l o b %
3480 % %
3481 % %
3482 % %
3483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3484 %
3485 % PingBlob() returns all the attributes of an image or image sequence except
3486 % for the pixels. It is much faster and consumes far less memory than
3487 % BlobToImage(). On failure, a NULL image is returned and exception
3488 % describes the reason for the failure.
3489 %
3490 % The format of the PingBlob method is:
3491 %
3492 % Image *PingBlob(const ImageInfo *image_info,const void *blob,
3493 % const size_t length,ExceptionInfo *exception)
3494 %
3495 % A description of each parameter follows:
3496 %
3497 % o image_info: the image info.
3498 %
3499 % o blob: the address of a character stream in one of the image formats
3500 % understood by ImageMagick.
3501 %
3502 % o length: This size_t integer reflects the length in bytes of the blob.
3503 %
3504 % o exception: return any errors or warnings in this structure.
3505 %
3506 */
3507 
3508 #if defined(__cplusplus) || defined(c_plusplus)
3509 extern "C" {
3510 #endif
3511 
3512 static size_t PingStream(const Image *magick_unused(image),
3513  const void *magick_unused(pixels),const size_t columns)
3514 {
3515  magick_unreferenced(image);
3516  magick_unreferenced(pixels);
3517  return(columns);
3518 }
3519 
3520 #if defined(__cplusplus) || defined(c_plusplus)
3521 }
3522 #endif
3523 
3524 MagickExport Image *PingBlob(const ImageInfo *image_info,const void *blob,
3525  const size_t length,ExceptionInfo *exception)
3526 {
3527  const MagickInfo
3528  *magick_info;
3529 
3530  Image
3531  *image;
3532 
3533  ImageInfo
3534  *clone_info,
3535  *ping_info;
3536 
3538  status;
3539 
3540  assert(image_info != (ImageInfo *) NULL);
3541  assert(image_info->signature == MagickCoreSignature);
3542  if (image_info->debug != MagickFalse)
3544  image_info->filename);
3545  assert(exception != (ExceptionInfo *) NULL);
3546  if ((blob == (const void *) NULL) || (length == 0))
3547  {
3548  (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
3549  "ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
3550  return((Image *) NULL);
3551  }
3552  ping_info=CloneImageInfo(image_info);
3553  ping_info->blob=(void *) blob;
3554  ping_info->length=length;
3555  ping_info->ping=MagickTrue;
3556  if (*ping_info->magick == '\0')
3557  (void) SetImageInfo(ping_info,0,exception);
3558  magick_info=GetMagickInfo(ping_info->magick,exception);
3559  if (magick_info == (const MagickInfo *) NULL)
3560  {
3561  (void) ThrowMagickException(exception,GetMagickModule(),
3562  MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
3563  ping_info->magick);
3564  ping_info=DestroyImageInfo(ping_info);
3565  return((Image *) NULL);
3566  }
3567  if (GetMagickBlobSupport(magick_info) != MagickFalse)
3568  {
3569  char
3570  filename[MagickPathExtent];
3571 
3572  /*
3573  Native blob support for this image format.
3574  */
3575  (void) CopyMagickString(filename,ping_info->filename,MagickPathExtent);
3576  (void) FormatLocaleString(ping_info->filename,MagickPathExtent,"%s:%s",
3577  ping_info->magick,filename);
3578  image=ReadStream(ping_info,&PingStream,exception);
3579  if (image != (Image *) NULL)
3580  (void) DetachBlob(image->blob);
3581  ping_info=DestroyImageInfo(ping_info);
3582  return(image);
3583  }
3584  /*
3585  Write blob to a temporary file on disk.
3586  */
3587  ping_info->blob=(void *) NULL;
3588  ping_info->length=0;
3589  *ping_info->filename='\0';
3590  status=BlobToFile(ping_info->filename,blob,length,exception);
3591  if (status == MagickFalse)
3592  {
3593  (void) RelinquishUniqueFileResource(ping_info->filename);
3594  ping_info=DestroyImageInfo(ping_info);
3595  return((Image *) NULL);
3596  }
3597  clone_info=CloneImageInfo(ping_info);
3598  (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:%s",
3599  ping_info->magick,ping_info->filename);
3600  image=ReadStream(clone_info,&PingStream,exception);
3601  if (image != (Image *) NULL)
3602  {
3603  Image
3604  *images;
3605 
3606  /*
3607  Restore original filenames and image format.
3608  */
3609  for (images=GetFirstImageInList(image); images != (Image *) NULL; )
3610  {
3611  (void) CopyMagickString(images->filename,image_info->filename,
3613  (void) CopyMagickString(images->magick_filename,image_info->filename,
3615  (void) CopyMagickString(images->magick,magick_info->name,
3617  images=GetNextImageInList(images);
3618  }
3619  }
3620  clone_info=DestroyImageInfo(clone_info);
3621  (void) RelinquishUniqueFileResource(ping_info->filename);
3622  ping_info=DestroyImageInfo(ping_info);
3623  return(image);
3624 }
3625 
3626 /*
3627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3628 % %
3629 % %
3630 % %
3631 + R e a d B l o b %
3632 % %
3633 % %
3634 % %
3635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3636 %
3637 % ReadBlob() reads data from the blob or image file and returns it. It
3638 % returns the number of bytes read. If length is zero, ReadBlob() returns
3639 % zero and has no other results. If length is greater than SSIZE_MAX, the
3640 % result is unspecified.
3641 %
3642 % The format of the ReadBlob method is:
3643 %
3644 % ssize_t ReadBlob(Image *image,const size_t length,void *data)
3645 %
3646 % A description of each parameter follows:
3647 %
3648 % o image: the image.
3649 %
3650 % o length: Specifies an integer representing the number of bytes to read
3651 % from the file.
3652 %
3653 % o data: Specifies an area to place the information requested from the
3654 % file.
3655 %
3656 */
3657 MagickExport ssize_t ReadBlob(Image *image,const size_t length,void *data)
3658 {
3659  BlobInfo
3660  *magick_restrict blob_info;
3661 
3662  int
3663  c;
3664 
3665  register unsigned char
3666  *q;
3667 
3668  ssize_t
3669  count;
3670 
3671  assert(image != (Image *) NULL);
3672  assert(image->signature == MagickCoreSignature);
3673  assert(image->blob != (BlobInfo *) NULL);
3674  assert(image->blob->type != UndefinedStream);
3675  if (length == 0)
3676  return(0);
3677  assert(data != (void *) NULL);
3678  blob_info=image->blob;
3679  count=0;
3680  q=(unsigned char *) data;
3681  switch (blob_info->type)
3682  {
3683  case UndefinedStream:
3684  break;
3685  case StandardStream:
3686  case FileStream:
3687  case PipeStream:
3688  {
3689  switch (length)
3690  {
3691  default:
3692  {
3693  count=(ssize_t) fread(q,1,length,blob_info->file_info.file);
3694  break;
3695  }
3696  case 4:
3697  {
3698  c=getc(blob_info->file_info.file);
3699  if (c == EOF)
3700  break;
3701  *q++=(unsigned char) c;
3702  count++;
3703  }
3704  case 3:
3705  {
3706  c=getc(blob_info->file_info.file);
3707  if (c == EOF)
3708  break;
3709  *q++=(unsigned char) c;
3710  count++;
3711  }
3712  case 2:
3713  {
3714  c=getc(blob_info->file_info.file);
3715  if (c == EOF)
3716  break;
3717  *q++=(unsigned char) c;
3718  count++;
3719  }
3720  case 1:
3721  {
3722  c=getc(blob_info->file_info.file);
3723  if (c == EOF)
3724  break;
3725  *q++=(unsigned char) c;
3726  count++;
3727  }
3728  case 0:
3729  break;
3730  }
3731  break;
3732  }
3733  case ZipStream:
3734  {
3735 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3736  switch (length)
3737  {
3738  default:
3739  {
3740  register ssize_t
3741  i;
3742 
3743  for (i=0; i < (ssize_t) length; i+=count)
3744  {
3745  count=(ssize_t) gzread(blob_info->file_info.gzfile,q+i,
3746  (unsigned int) MagickMin(length-i,MagickMaxBufferExtent));
3747  if (count <= 0)
3748  {
3749  count=0;
3750  if (errno != EINTR)
3751  break;
3752  }
3753  }
3754  count=i;
3755  break;
3756  }
3757  case 4:
3758  {
3759  c=gzgetc(blob_info->file_info.gzfile);
3760  if (c == EOF)
3761  break;
3762  *q++=(unsigned char) c;
3763  count++;
3764  }
3765  case 3:
3766  {
3767  c=gzgetc(blob_info->file_info.gzfile);
3768  if (c == EOF)
3769  break;
3770  *q++=(unsigned char) c;
3771  count++;
3772  }
3773  case 2:
3774  {
3775  c=gzgetc(blob_info->file_info.gzfile);
3776  if (c == EOF)
3777  break;
3778  *q++=(unsigned char) c;
3779  count++;
3780  }
3781  case 1:
3782  {
3783  c=gzgetc(blob_info->file_info.gzfile);
3784  if (c == EOF)
3785  break;
3786  *q++=(unsigned char) c;
3787  count++;
3788  }
3789  case 0:
3790  break;
3791  }
3792 #endif
3793  break;
3794  }
3795  case BZipStream:
3796  {
3797 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3798  register ssize_t
3799  i;
3800 
3801  for (i=0; i < (ssize_t) length; i+=count)
3802  {
3803  count=(ssize_t) BZ2_bzread(blob_info->file_info.bzfile,q+i,
3804  (unsigned int) MagickMin(length-i,MagickMaxBufferExtent));
3805  if (count <= 0)
3806  {
3807  count=0;
3808  if (errno != EINTR)
3809  break;
3810  }
3811  }
3812  count=i;
3813 #endif
3814  break;
3815  }
3816  case FifoStream:
3817  break;
3818  case BlobStream:
3819  {
3820  register const unsigned char
3821  *p;
3822 
3823  if (blob_info->offset >= (MagickOffsetType) blob_info->length)
3824  {
3825  blob_info->eof=MagickTrue;
3826  break;
3827  }
3828  p=blob_info->data+blob_info->offset;
3829  count=(ssize_t) MagickMin((MagickOffsetType) length,(MagickOffsetType)
3830  blob_info->length-blob_info->offset);
3831  blob_info->offset+=count;
3832  if (count != (ssize_t) length)
3833  blob_info->eof=MagickTrue;
3834  (void) memcpy(q,p,(size_t) count);
3835  break;
3836  }
3837  case CustomStream:
3838  {
3839  if (blob_info->custom_stream->reader != (CustomStreamHandler) NULL)
3840  count=blob_info->custom_stream->reader(q,length,
3841  blob_info->custom_stream->data);
3842  break;
3843  }
3844  }
3845  return(count);
3846 }
3847 
3848 /*
3849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3850 % %
3851 % %
3852 % %
3853 + R e a d B l o b B y t e %
3854 % %
3855 % %
3856 % %
3857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3858 %
3859 % ReadBlobByte() reads a single byte from the image file and returns it.
3860 %
3861 % The format of the ReadBlobByte method is:
3862 %
3863 % int ReadBlobByte(Image *image)
3864 %
3865 % A description of each parameter follows.
3866 %
3867 % o image: the image.
3868 %
3869 */
3871 {
3872  BlobInfo
3873  *magick_restrict blob_info;
3874 
3875  register const unsigned char
3876  *p;
3877 
3878  unsigned char
3879  buffer[1];
3880 
3881  assert(image != (Image *) NULL);
3882  assert(image->signature == MagickCoreSignature);
3883  assert(image->blob != (BlobInfo *) NULL);
3884  assert(image->blob->type != UndefinedStream);
3885  blob_info=image->blob;
3886  switch (blob_info->type)
3887  {
3888  case StandardStream:
3889  case FileStream:
3890  case PipeStream:
3891  {
3892  int
3893  c;
3894 
3895  p=(const unsigned char *) buffer;
3896  c=getc(blob_info->file_info.file);
3897  if (c == EOF)
3898  return(EOF);
3899  *buffer=(unsigned char) c;
3900  break;
3901  }
3902  default:
3903  {
3904  ssize_t
3905  count;
3906 
3907  p=(const unsigned char *) ReadBlobStream(image,1,buffer,&count);
3908  if (count != 1)
3909  return(EOF);
3910  break;
3911  }
3912  }
3913  return((int) (*p));
3914 }
3915 
3916 /*
3917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3918 % %
3919 % %
3920 % %
3921 + R e a d B l o b D o u b l e %
3922 % %
3923 % %
3924 % %
3925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3926 %
3927 % ReadBlobDouble() reads a double value as a 64-bit quantity in the byte-order
3928 % specified by the endian member of the image structure.
3929 %
3930 % The format of the ReadBlobDouble method is:
3931 %
3932 % double ReadBlobDouble(Image *image)
3933 %
3934 % A description of each parameter follows.
3935 %
3936 % o image: the image.
3937 %
3938 */
3940 {
3941  union
3942  {
3944  unsigned_value;
3945 
3946  double
3947  double_value;
3948  } quantum;
3949 
3950  quantum.double_value=0.0;
3951  quantum.unsigned_value=ReadBlobLongLong(image);
3952  return(quantum.double_value);
3953 }
3954 
3955 /*
3956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3957 % %
3958 % %
3959 % %
3960 + R e a d B l o b F l o a t %
3961 % %
3962 % %
3963 % %
3964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3965 %
3966 % ReadBlobFloat() reads a float value as a 32-bit quantity in the byte-order
3967 % specified by the endian member of the image structure.
3968 %
3969 % The format of the ReadBlobFloat method is:
3970 %
3971 % float ReadBlobFloat(Image *image)
3972 %
3973 % A description of each parameter follows.
3974 %
3975 % o image: the image.
3976 %
3977 */
3979 {
3980  union
3981  {
3982  unsigned int
3983  unsigned_value;
3984 
3985  float
3986  float_value;
3987  } quantum;
3988 
3989  quantum.float_value=0.0;
3990  quantum.unsigned_value=ReadBlobLong(image);
3991  return(quantum.float_value);
3992 }
3993 
3994 /*
3995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3996 % %
3997 % %
3998 % %
3999 + R e a d B l o b L o n g %
4000 % %
4001 % %
4002 % %
4003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4004 %
4005 % ReadBlobLong() reads a unsigned int value as a 32-bit quantity in the
4006 % byte-order specified by the endian member of the image structure.
4007 %
4008 % The format of the ReadBlobLong method is:
4009 %
4010 % unsigned int ReadBlobLong(Image *image)
4011 %
4012 % A description of each parameter follows.
4013 %
4014 % o image: the image.
4015 %
4016 */
4017 MagickExport unsigned int ReadBlobLong(Image *image)
4018 {
4019  register const unsigned char
4020  *p;
4021 
4022  ssize_t
4023  count;
4024 
4025  unsigned char
4026  buffer[4];
4027 
4028  unsigned int
4029  value;
4030 
4031  assert(image != (Image *) NULL);
4032  assert(image->signature == MagickCoreSignature);
4033  *buffer='\0';
4034  p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
4035  if (count != 4)
4036  return(0UL);
4037  if (image->endian == LSBEndian)
4038  {
4039  value=(unsigned int) (*p++);
4040  value|=(unsigned int) (*p++) << 8;
4041  value|=(unsigned int) (*p++) << 16;
4042  value|=(unsigned int) (*p++) << 24;
4043  return(value);
4044  }
4045  value=(unsigned int) (*p++) << 24;
4046  value|=(unsigned int) (*p++) << 16;
4047  value|=(unsigned int) (*p++) << 8;
4048  value|=(unsigned int) (*p++);
4049  return(value);
4050 }
4051 
4052 /*
4053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4054 % %
4055 % %
4056 % %
4057 + R e a d B l o b L o n g L o n g %
4058 % %
4059 % %
4060 % %
4061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4062 %
4063 % ReadBlobLongLong() reads a long long value as a 64-bit quantity in the
4064 % byte-order specified by the endian member of the image structure.
4065 %
4066 % The format of the ReadBlobLongLong method is:
4067 %
4068 % MagickSizeType ReadBlobLongLong(Image *image)
4069 %
4070 % A description of each parameter follows.
4071 %
4072 % o image: the image.
4073 %
4074 */
4076 {
4078  value;
4079 
4080  register const unsigned char
4081  *p;
4082 
4083  ssize_t
4084  count;
4085 
4086  unsigned char
4087  buffer[8];
4088 
4089  assert(image != (Image *) NULL);
4090  assert(image->signature == MagickCoreSignature);
4091  *buffer='\0';
4092  p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
4093  if (count != 8)
4094  return(MagickULLConstant(0));
4095  if (image->endian == LSBEndian)
4096  {
4097  value=(MagickSizeType) (*p++);
4098  value|=(MagickSizeType) (*p++) << 8;
4099  value|=(MagickSizeType) (*p++) << 16;
4100  value|=(MagickSizeType) (*p++) << 24;
4101  value|=(MagickSizeType) (*p++) << 32;
4102  value|=(MagickSizeType) (*p++) << 40;
4103  value|=(MagickSizeType) (*p++) << 48;
4104  value|=(MagickSizeType) (*p++) << 56;
4105  return(value);
4106  }
4107  value=(MagickSizeType) (*p++) << 56;
4108  value|=(MagickSizeType) (*p++) << 48;
4109  value|=(MagickSizeType) (*p++) << 40;
4110  value|=(MagickSizeType) (*p++) << 32;
4111  value|=(MagickSizeType) (*p++) << 24;
4112  value|=(MagickSizeType) (*p++) << 16;
4113  value|=(MagickSizeType) (*p++) << 8;
4114  value|=(MagickSizeType) (*p++);
4115  return(value);
4116 }
4117 
4118 /*
4119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4120 % %
4121 % %
4122 % %
4123 + R e a d B l o b S h o r t %
4124 % %
4125 % %
4126 % %
4127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4128 %
4129 % ReadBlobShort() reads a short value as a 16-bit quantity in the byte-order
4130 % specified by the endian member of the image structure.
4131 %
4132 % The format of the ReadBlobShort method is:
4133 %
4134 % unsigned short ReadBlobShort(Image *image)
4135 %
4136 % A description of each parameter follows.
4137 %
4138 % o image: the image.
4139 %
4140 */
4141 MagickExport unsigned short ReadBlobShort(Image *image)
4142 {
4143  register const unsigned char
4144  *p;
4145 
4146  register unsigned short
4147  value;
4148 
4149  ssize_t
4150  count;
4151 
4152  unsigned char
4153  buffer[2];
4154 
4155  assert(image != (Image *) NULL);
4156  assert(image->signature == MagickCoreSignature);
4157  *buffer='\0';
4158  p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
4159  if (count != 2)
4160  return((unsigned short) 0U);
4161  if (image->endian == LSBEndian)
4162  {
4163  value=(unsigned short) (*p++);
4164  value|=(unsigned short) (*p++) << 8;
4165  return(value);
4166  }
4167  value=(unsigned short) ((unsigned short) (*p++) << 8);
4168  value|=(unsigned short) (*p++);
4169  return(value);
4170 }
4171 
4172 /*
4173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4174 % %
4175 % %
4176 % %
4177 + R e a d B l o b L S B L o n g %
4178 % %
4179 % %
4180 % %
4181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4182 %
4183 % ReadBlobLSBLong() reads a unsigned int value as a 32-bit quantity in
4184 % least-significant byte first order.
4185 %
4186 % The format of the ReadBlobLSBLong method is:
4187 %
4188 % unsigned int ReadBlobLSBLong(Image *image)
4189 %
4190 % A description of each parameter follows.
4191 %
4192 % o image: the image.
4193 %
4194 */
4195 MagickExport unsigned int ReadBlobLSBLong(Image *image)
4196 {
4197  register const unsigned char
4198  *p;
4199 
4200  register unsigned int
4201  value;
4202 
4203  ssize_t
4204  count;
4205 
4206  unsigned char
4207  buffer[4];
4208 
4209  assert(image != (Image *) NULL);
4210  assert(image->signature == MagickCoreSignature);
4211  *buffer='\0';
4212  p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
4213  if (count != 4)
4214  return(0U);
4215  value=(unsigned int) (*p++);
4216  value|=(unsigned int) (*p++) << 8;
4217  value|=(unsigned int) (*p++) << 16;
4218  value|=(unsigned int) (*p++) << 24;
4219  return(value);
4220 }
4221 
4222 /*
4223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4224 % %
4225 % %
4226 % %
4227 + R e a d B l o b L S B S i g n e d L o n g %
4228 % %
4229 % %
4230 % %
4231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4232 %
4233 % ReadBlobLSBSignedLong() reads a signed int value as a 32-bit quantity in
4234 % least-significant byte first order.
4235 %
4236 % The format of the ReadBlobLSBSignedLong method is:
4237 %
4238 % signed int ReadBlobLSBSignedLong(Image *image)
4239 %
4240 % A description of each parameter follows.
4241 %
4242 % o image: the image.
4243 %
4244 */
4246 {
4247  union
4248  {
4249  unsigned int
4250  unsigned_value;
4251 
4252  signed int
4253  signed_value;
4254  } quantum;
4255 
4256  quantum.unsigned_value=ReadBlobLSBLong(image);
4257  return(quantum.signed_value);
4258 }
4259 
4260 /*
4261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4262 % %
4263 % %
4264 % %
4265 + R e a d B l o b L S B S h o r t %
4266 % %
4267 % %
4268 % %
4269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4270 %
4271 % ReadBlobLSBShort() reads a short value as a 16-bit quantity in
4272 % least-significant byte first order.
4273 %
4274 % The format of the ReadBlobLSBShort method is:
4275 %
4276 % unsigned short ReadBlobLSBShort(Image *image)
4277 %
4278 % A description of each parameter follows.
4279 %
4280 % o image: the image.
4281 %
4282 */
4283 MagickExport unsigned short ReadBlobLSBShort(Image *image)
4284 {
4285  register const unsigned char
4286  *p;
4287 
4288  register unsigned short
4289  value;
4290 
4291  ssize_t
4292  count;
4293 
4294  unsigned char
4295  buffer[2];
4296 
4297  assert(image != (Image *) NULL);
4298  assert(image->signature == MagickCoreSignature);
4299  *buffer='\0';
4300  p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
4301  if (count != 2)
4302  return((unsigned short) 0U);
4303  value=(unsigned short) (*p++);
4304  value|=(unsigned short) (*p++) << 8;
4305  return(value);
4306 }
4307 
4308 /*
4309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4310 % %
4311 % %
4312 % %
4313 + R e a d B l o b L S B S i g n e d S h o r t %
4314 % %
4315 % %
4316 % %
4317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4318 %
4319 % ReadBlobLSBSignedShort() reads a signed short value as a 16-bit quantity in
4320 % least-significant byte-order.
4321 %
4322 % The format of the ReadBlobLSBSignedShort method is:
4323 %
4324 % signed short ReadBlobLSBSignedShort(Image *image)
4325 %
4326 % A description of each parameter follows.
4327 %
4328 % o image: the image.
4329 %
4330 */
4332 {
4333  union
4334  {
4335  unsigned short
4336  unsigned_value;
4337 
4338  signed short
4339  signed_value;
4340  } quantum;
4341 
4342  quantum.unsigned_value=ReadBlobLSBShort(image);
4343  return(quantum.signed_value);
4344 }
4345 
4346 /*
4347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348 % %
4349 % %
4350 % %
4351 + R e a d B l o b M S B L o n g %
4352 % %
4353 % %
4354 % %
4355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4356 %
4357 % ReadBlobMSBLong() reads a unsigned int value as a 32-bit quantity in
4358 % most-significant byte first order.
4359 %
4360 % The format of the ReadBlobMSBLong method is:
4361 %
4362 % unsigned int ReadBlobMSBLong(Image *image)
4363 %
4364 % A description of each parameter follows.
4365 %
4366 % o image: the image.
4367 %
4368 */
4369 MagickExport unsigned int ReadBlobMSBLong(Image *image)
4370 {
4371  register const unsigned char
4372  *p;
4373 
4374  register unsigned int
4375  value;
4376 
4377  ssize_t
4378  count;
4379 
4380  unsigned char
4381  buffer[4];
4382 
4383  assert(image != (Image *) NULL);
4384  assert(image->signature == MagickCoreSignature);
4385  *buffer='\0';
4386  p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
4387  if (count != 4)
4388  return(0UL);
4389  value=(unsigned int) (*p++) << 24;
4390  value|=(unsigned int) (*p++) << 16;
4391  value|=(unsigned int) (*p++) << 8;
4392  value|=(unsigned int) (*p++);
4393  return(value);
4394 }
4395 
4396 /*
4397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398 % %
4399 % %
4400 % %
4401 + R e a d B l o b M S B L o n g L o n g %
4402 % %
4403 % %
4404 % %
4405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4406 %
4407 % ReadBlobMSBLongLong() reads a unsigned long long value as a 64-bit quantity
4408 % in most-significant byte first order.
4409 %
4410 % The format of the ReadBlobMSBLongLong method is:
4411 %
4412 % unsigned int ReadBlobMSBLongLong(Image *image)
4413 %
4414 % A description of each parameter follows.
4415 %
4416 % o image: the image.
4417 %
4418 */
4420 {
4421  register const unsigned char
4422  *p;
4423 
4424  register MagickSizeType
4425  value;
4426 
4427  ssize_t
4428  count;
4429 
4430  unsigned char
4431  buffer[8];
4432 
4433  assert(image != (Image *) NULL);
4434  assert(image->signature == MagickCoreSignature);
4435  *buffer='\0';
4436  p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
4437  if (count != 8)
4438  return(MagickULLConstant(0));
4439  value=(MagickSizeType) (*p++) << 56;
4440  value|=(MagickSizeType) (*p++) << 48;
4441  value|=(MagickSizeType) (*p++) << 40;
4442  value|=(MagickSizeType) (*p++) << 32;
4443  value|=(MagickSizeType) (*p++) << 24;
4444  value|=(MagickSizeType) (*p++) << 16;
4445  value|=(MagickSizeType) (*p++) << 8;
4446  value|=(MagickSizeType) (*p++);
4447  return(value);
4448 }
4449 
4450 /*
4451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4452 % %
4453 % %
4454 % %
4455 + R e a d B l o b M S B S h o r t %
4456 % %
4457 % %
4458 % %
4459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4460 %
4461 % ReadBlobMSBShort() reads a short value as a 16-bit quantity in
4462 % most-significant byte first order.
4463 %
4464 % The format of the ReadBlobMSBShort method is:
4465 %
4466 % unsigned short ReadBlobMSBShort(Image *image)
4467 %
4468 % A description of each parameter follows.
4469 %
4470 % o image: the image.
4471 %
4472 */
4473 MagickExport unsigned short ReadBlobMSBShort(Image *image)
4474 {
4475  register const unsigned char
4476  *p;
4477 
4478  register unsigned short
4479  value;
4480 
4481  ssize_t
4482  count;
4483 
4484  unsigned char
4485  buffer[2];
4486 
4487  assert(image != (Image *) NULL);
4488  assert(image->signature == MagickCoreSignature);
4489  *buffer='\0';
4490  p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
4491  if (count != 2)
4492  return((unsigned short) 0U);
4493  value=(unsigned short) ((*p++) << 8);
4494  value|=(unsigned short) (*p++);
4495  return((unsigned short) (value & 0xffff));
4496 }
4497 
4498 /*
4499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4500 % %
4501 % %
4502 % %
4503 + R e a d B l o b M S B S i g n e d L o n g %
4504 % %
4505 % %
4506 % %
4507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4508 %
4509 % ReadBlobMSBSignedLong() reads a signed int value as a 32-bit quantity in
4510 % most-significant byte-order.
4511 %
4512 % The format of the ReadBlobMSBSignedLong method is:
4513 %
4514 % signed int ReadBlobMSBSignedLong(Image *image)
4515 %
4516 % A description of each parameter follows.
4517 %
4518 % o image: the image.
4519 %
4520 */
4522 {
4523  union
4524  {
4525  unsigned int
4526  unsigned_value;
4527 
4528  signed int
4529  signed_value;
4530  } quantum;
4531 
4532  quantum.unsigned_value=ReadBlobMSBLong(image);
4533  return(quantum.signed_value);
4534 }
4535 
4536 /*
4537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4538 % %
4539 % %
4540 % %
4541 + R e a d B l o b M S B S i g n e d S h o r t %
4542 % %
4543 % %
4544 % %
4545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4546 %
4547 % ReadBlobMSBSignedShort() reads a signed short value as a 16-bit quantity in
4548 % most-significant byte-order.
4549 %
4550 % The format of the ReadBlobMSBSignedShort method is:
4551 %
4552 % signed short ReadBlobMSBSignedShort(Image *image)
4553 %
4554 % A description of each parameter follows.
4555 %
4556 % o image: the image.
4557 %
4558 */
4560 {
4561  union
4562  {
4563  unsigned short
4564  unsigned_value;
4565 
4566  signed short
4567  signed_value;
4568  } quantum;
4569 
4570  quantum.unsigned_value=ReadBlobMSBShort(image);
4571  return(quantum.signed_value);
4572 }
4573 
4574 /*
4575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4576 % %
4577 % %
4578 % %
4579 + R e a d B l o b S i g n e d L o n g %
4580 % %
4581 % %
4582 % %
4583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4584 %
4585 % ReadBlobSignedLong() reads a signed int value as a 32-bit quantity in the
4586 % byte-order specified by the endian member of the image structure.
4587 %
4588 % The format of the ReadBlobSignedLong method is:
4589 %
4590 % signed int ReadBlobSignedLong(Image *image)
4591 %
4592 % A description of each parameter follows.
4593 %
4594 % o image: the image.
4595 %
4596 */
4598 {
4599  union
4600  {
4601  unsigned int
4602  unsigned_value;
4603 
4604  signed int
4605  signed_value;
4606  } quantum;
4607 
4608  quantum.unsigned_value=ReadBlobLong(image);
4609  return(quantum.signed_value);
4610 }
4611 
4612 /*
4613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4614 % %
4615 % %
4616 % %
4617 + R e a d B l o b S i g n e d S h o r t %
4618 % %
4619 % %
4620 % %
4621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4622 %
4623 % ReadBlobSignedShort() reads a signed short value as a 16-bit quantity in the
4624 % byte-order specified by the endian member of the image structure.
4625 %
4626 % The format of the ReadBlobSignedShort method is:
4627 %
4628 % signed short ReadBlobSignedShort(Image *image)
4629 %
4630 % A description of each parameter follows.
4631 %
4632 % o image: the image.
4633 %
4634 */
4636 {
4637  union
4638  {
4639  unsigned short
4640  unsigned_value;
4641 
4642  signed short
4643  signed_value;
4644  } quantum;
4645 
4646  quantum.unsigned_value=ReadBlobShort(image);
4647  return(quantum.signed_value);
4648 }
4649 
4650 /*
4651 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4652 % %
4653 % %
4654 % %
4655 + R e a d B l o b S t r e a m %
4656 % %
4657 % %
4658 % %
4659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4660 %
4661 % ReadBlobStream() reads data from the blob or image file and returns it. It
4662 % returns a pointer to the data buffer you supply or to the image memory
4663 % buffer if its supported (zero-copy). If length is zero, ReadBlobStream()
4664 % returns a count of zero and has no other results. If length is greater than
4665 % SSIZE_MAX, the result is unspecified.
4666 %
4667 % The format of the ReadBlobStream method is:
4668 %
4669 % const void *ReadBlobStream(Image *image,const size_t length,void *data,
4670 % ssize_t *count)
4671 %
4672 % A description of each parameter follows:
4673 %
4674 % o image: the image.
4675 %
4676 % o length: Specifies an integer representing the number of bytes to read
4677 % from the file.
4678 %
4679 % o count: returns the number of bytes read.
4680 %
4681 % o data: Specifies an area to place the information requested from the
4682 % file.
4683 %
4684 */
4685 MagickExport const void *ReadBlobStream(Image *image,const size_t length,
4686  void *data,ssize_t *count)
4687 {
4688  BlobInfo
4689  *magick_restrict blob_info;
4690 
4691  assert(image != (Image *) NULL);
4692  assert(image->signature == MagickCoreSignature);
4693  assert(image->blob != (BlobInfo *) NULL);
4694  assert(image->blob->type != UndefinedStream);
4695  assert(count != (ssize_t *) NULL);
4696  blob_info=image->blob;
4697  if (blob_info->type != BlobStream)
4698  {
4699  assert(data != NULL);
4700  *count=ReadBlob(image,length,(unsigned char *) data);
4701  return(data);
4702  }
4703  if (blob_info->offset >= (MagickOffsetType) blob_info->length)
4704  {
4705  *count=0;
4706  blob_info->eof=MagickTrue;
4707  return(data);
4708  }
4709  data=blob_info->data+blob_info->offset;
4710  *count=(ssize_t) MagickMin((MagickOffsetType) length,(MagickOffsetType)
4711  blob_info->length-blob_info->offset);
4712  blob_info->offset+=(*count);
4713  if (*count != (ssize_t) length)
4714  blob_info->eof=MagickTrue;
4715  return(data);
4716 }
4717 
4718 /*
4719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4720 % %
4721 % %
4722 % %
4723 + R e a d B l o b S t r i n g %
4724 % %
4725 % %
4726 % %
4727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728 %
4729 % ReadBlobString() reads characters from a blob or file until a newline
4730 % character is read or an end-of-file condition is encountered.
4731 %
4732 % The format of the ReadBlobString method is:
4733 %
4734 % char *ReadBlobString(Image *image,char *string)
4735 %
4736 % A description of each parameter follows:
4737 %
4738 % o image: the image.
4739 %
4740 % o string: the address of a character buffer.
4741 %
4742 */
4743 MagickExport char *ReadBlobString(Image *image,char *string)
4744 {
4745  int
4746  c;
4747 
4748  register ssize_t
4749  i;
4750 
4751  assert(image != (Image *) NULL);
4752  assert(image->signature == MagickCoreSignature);
4753  for (i=0; i < (MagickPathExtent-1L); i++)
4754  {
4755  c=ReadBlobByte(image);
4756  if (c == EOF)
4757  {
4758  if (i == 0)
4759  return((char *) NULL);
4760  break;
4761  }
4762  string[i]=c;
4763  if (c == '\n')
4764  {
4765  if ((i > 0) && (string[i-1] == '\r'))
4766  i--;
4767  break;
4768  }
4769  }
4770  string[i]='\0';
4771  return(string);
4772 }
4773 
4774 /*
4775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4776 % %
4777 % %
4778 % %
4779 + R e f e r e n c e B l o b %
4780 % %
4781 % %
4782 % %
4783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4784 %
4785 % ReferenceBlob() increments the reference count associated with the pixel
4786 % blob returning a pointer to the blob.
4787 %
4788 % The format of the ReferenceBlob method is:
4789 %
4790 % BlobInfo ReferenceBlob(BlobInfo *blob_info)
4791 %
4792 % A description of each parameter follows:
4793 %
4794 % o blob_info: the blob_info.
4795 %
4796 */
4798 {
4799  assert(blob != (BlobInfo *) NULL);
4800  assert(blob->signature == MagickCoreSignature);
4801  if (blob->debug != MagickFalse)
4802  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4804  blob->reference_count++;
4806  return(blob);
4807 }
4808 
4809 /*
4810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4811 % %
4812 % %
4813 % %
4814 + S e e k B l o b %
4815 % %
4816 % %
4817 % %
4818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4819 %
4820 % SeekBlob() sets the offset in bytes from the beginning of a blob or file
4821 % and returns the resulting offset.
4822 %
4823 % The format of the SeekBlob method is:
4824 %
4825 % MagickOffsetType SeekBlob(Image *image,const MagickOffsetType offset,
4826 % const int whence)
4827 %
4828 % A description of each parameter follows:
4829 %
4830 % o image: the image.
4831 %
4832 % o offset: Specifies an integer representing the offset in bytes.
4833 %
4834 % o whence: Specifies an integer representing how the offset is
4835 % treated relative to the beginning of the blob as follows:
4836 %
4837 % SEEK_SET Set position equal to offset bytes.
4838 % SEEK_CUR Set position to current location plus offset.
4839 % SEEK_END Set position to EOF plus offset.
4840 %
4841 */
4843  const MagickOffsetType offset,const int whence)
4844 {
4845  BlobInfo
4846  *magick_restrict blob_info;
4847 
4848  assert(image != (Image *) NULL);
4849  assert(image->signature == MagickCoreSignature);
4850  if (image->debug != MagickFalse)
4851  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4852  assert(image->blob != (BlobInfo *) NULL);
4853  assert(image->blob->type != UndefinedStream);
4854  blob_info=image->blob;
4855  switch (blob_info->type)
4856  {
4857  case UndefinedStream:
4858  break;
4859  case StandardStream:
4860  case PipeStream:
4861  return(-1);
4862  case FileStream:
4863  {
4864  if ((offset < 0) && (whence == SEEK_SET))
4865  return(-1);
4866  if (fseek(blob_info->file_info.file,offset,whence) < 0)
4867  return(-1);
4868  blob_info->offset=TellBlob(image);
4869  break;
4870  }
4871  case ZipStream:
4872  {
4873 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4874  if (gzseek(blob_info->file_info.gzfile,(off_t) offset,whence) < 0)
4875  return(-1);
4876 #endif
4877  blob_info->offset=TellBlob(image);
4878  break;
4879  }
4880  case BZipStream:
4881  return(-1);
4882  case FifoStream:
4883  return(-1);
4884  case BlobStream:
4885  {
4886  switch (whence)
4887  {
4888  case SEEK_SET:
4889  default:
4890  {
4891  if (offset < 0)
4892  return(-1);
4893  blob_info->offset=offset;
4894  break;
4895  }
4896  case SEEK_CUR:
4897  {
4898  if ((blob_info->offset+offset) < 0)
4899  return(-1);
4900  blob_info->offset+=offset;
4901  break;
4902  }
4903  case SEEK_END:
4904  {
4905  if (((MagickOffsetType) blob_info->length+offset) < 0)
4906  return(-1);
4907  blob_info->offset=blob_info->length+offset;
4908  break;
4909  }
4910  }
4911  if (blob_info->offset < (MagickOffsetType) ((off_t) blob_info->length))
4912  {
4913  blob_info->eof=MagickFalse;
4914  break;
4915  }
4916  if (blob_info->offset >= (MagickOffsetType) ((off_t) blob_info->extent))
4917  return(-1);
4918  break;
4919  }
4920  case CustomStream:
4921  {
4922  if (blob_info->custom_stream->seeker == (CustomStreamSeeker) NULL)
4923  return(-1);
4924  blob_info->offset=blob_info->custom_stream->seeker(offset,whence,
4925  blob_info->custom_stream->data);
4926  break;
4927  }
4928  }
4929  return(blob_info->offset);
4930 }
4931 
4932 /*
4933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4934 % %
4935 % %
4936 % %
4937 + S e t B l o b E x e m p t %
4938 % %
4939 % %
4940 % %
4941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4942 %
4943 % SetBlobExempt() sets the blob exempt status.
4944 %
4945 % The format of the SetBlobExempt method is:
4946 %
4947 % MagickBooleanType SetBlobExempt(const Image *image,
4948 % const MagickBooleanType exempt)
4949 %
4950 % A description of each parameter follows:
4951 %
4952 % o image: the image.
4953 %
4954 % o exempt: Set to true if this blob is exempt from being closed.
4955 %
4956 */
4958 {
4959  assert(image != (const Image *) NULL);
4960  assert(image->signature == MagickCoreSignature);
4961  if (image->debug != MagickFalse)
4962  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4963  image->blob->exempt=exempt;
4964 }
4965 
4966 /*
4967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4968 % %
4969 % %
4970 % %
4971 + S e t B l o b E x t e n t %
4972 % %
4973 % %
4974 % %
4975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4976 %
4977 % SetBlobExtent() ensures enough space is allocated for the blob. If the
4978 % method is successful, subsequent writes to bytes in the specified range are
4979 % guaranteed not to fail.
4980 %
4981 % The format of the SetBlobExtent method is:
4982 %
4983 % MagickBooleanType SetBlobExtent(Image *image,const MagickSizeType extent)
4984 %
4985 % A description of each parameter follows:
4986 %
4987 % o image: the image.
4988 %
4989 % o extent: the blob maximum extent.
4990 %
4991 */
4993  const MagickSizeType extent)
4994 {
4995  BlobInfo
4996  *magick_restrict blob_info;
4997 
4998  assert(image != (Image *) NULL);
4999  assert(image->signature == MagickCoreSignature);
5000  if (image->debug != MagickFalse)
5001  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5002  assert(image->blob != (BlobInfo *) NULL);
5003  assert(image->blob->type != UndefinedStream);
5004  blob_info=image->blob;
5005  switch (blob_info->type)
5006  {
5007  case UndefinedStream:
5008  break;
5009  case StandardStream:
5010  return(MagickFalse);
5011  case FileStream:
5012  {
5014  offset;
5015 
5016  ssize_t
5017  count;
5018 
5019  if (extent != (MagickSizeType) ((off_t) extent))
5020  return(MagickFalse);
5021  offset=SeekBlob(image,0,SEEK_END);
5022  if (offset < 0)
5023  return(MagickFalse);
5024  if ((MagickSizeType) offset >= extent)
5025  break;
5026  offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
5027  if (offset < 0)
5028  break;
5029  count=(ssize_t) fwrite((const unsigned char *) "",1,1,
5030  blob_info->file_info.file);
5031 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
5032  if (blob_info->synchronize != MagickFalse)
5033  {
5034  int
5035  file;
5036 
5037  file=fileno(blob_info->file_info.file);
5038  if ((file == -1) || (offset < 0))
5039  return(MagickFalse);
5040  (void) posix_fallocate(file,offset,extent-offset);
5041  }
5042 #endif
5043  offset=SeekBlob(image,offset,SEEK_SET);
5044  if (count != 1)
5045  return(MagickFalse);
5046  break;
5047  }
5048  case PipeStream:
5049  case ZipStream:
5050  return(MagickFalse);
5051  case BZipStream:
5052  return(MagickFalse);
5053  case FifoStream:
5054  return(MagickFalse);
5055  case BlobStream:
5056  {
5057  if (extent != (MagickSizeType) ((size_t) extent))
5058  return(MagickFalse);
5059  if (blob_info->mapped != MagickFalse)
5060  {
5062  offset;
5063 
5064  ssize_t
5065  count;
5066 
5067  (void) UnmapBlob(blob_info->data,blob_info->length);
5068  RelinquishMagickResource(MapResource,blob_info->length);
5069  if (extent != (MagickSizeType) ((off_t) extent))
5070  return(MagickFalse);
5071  offset=SeekBlob(image,0,SEEK_END);
5072  if (offset < 0)
5073  return(MagickFalse);
5074  if ((MagickSizeType) offset >= extent)
5075  break;
5076  offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
5077  count=(ssize_t) fwrite((const unsigned char *) "",1,1,
5078  blob_info->file_info.file);
5079 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
5080  if (blob_info->synchronize != MagickFalse)
5081  {
5082  int
5083  file;
5084 
5085  file=fileno(blob_info->file_info.file);
5086  if ((file == -1) || (offset < 0))
5087  return(MagickFalse);
5088  (void) posix_fallocate(file,offset,extent-offset);
5089  }
5090 #endif
5091  offset=SeekBlob(image,offset,SEEK_SET);
5092  if (count != 1)
5093  return(MagickFalse);
5094  (void) AcquireMagickResource(MapResource,extent);
5095  blob_info->data=(unsigned char*) MapBlob(fileno(
5096  blob_info->file_info.file),WriteMode,0,(size_t) extent);
5097  blob_info->extent=(size_t) extent;
5098  blob_info->length=(size_t) extent;
5099  (void) SyncBlob(image);
5100  break;
5101  }
5102  blob_info->extent=(size_t) extent;
5103  blob_info->data=(unsigned char *) ResizeQuantumMemory(blob_info->data,
5104  blob_info->extent+1,sizeof(*blob_info->data));
5105  (void) SyncBlob(image);
5106  if (blob_info->data == (unsigned char *) NULL)
5107  {
5108  (void) DetachBlob(blob_info);
5109  return(MagickFalse);
5110  }
5111  break;
5112  }
5113  case CustomStream:
5114  break;
5115  }
5116  return(MagickTrue);
5117 }
5118 
5119 /*
5120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5121 % %
5122 % %
5123 % %
5124 + S e t C u s t o m S t r e a m D a t a %
5125 % %
5126 % %
5127 % %
5128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129 %
5130 % SetCustomStreamData() sets the stream info data member.
5131 %
5132 % The format of the SetCustomStreamData method is:
5133 %
5134 % void SetCustomStreamData(CustomStreamInfo *custom_stream,void *)
5135 %
5136 % A description of each parameter follows:
5137 %
5138 % o custom_stream: the custom stream info.
5139 %
5140 % o data: an object containing information about the custom stream.
5141 %
5142 */
5144  void *data)
5145 {
5146  assert(custom_stream != (CustomStreamInfo *) NULL);
5147  assert(custom_stream->signature == MagickCoreSignature);
5148  custom_stream->data=data;
5149 }
5150 
5151 /*
5152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5153 % %
5154 % %
5155 % %
5156 + S e t C u s t o m S t r e a m R e a d e r %
5157 % %
5158 % %
5159 % %
5160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5161 %
5162 % SetCustomStreamReader() sets the stream info reader member.
5163 %
5164 % The format of the SetCustomStreamReader method is:
5165 %
5166 % void SetCustomStreamReader(CustomStreamInfo *custom_stream,
5167 % CustomStreamHandler reader)
5168 %
5169 % A description of each parameter follows:
5170 %
5171 % o custom_stream: the custom stream info.
5172 %
5173 % o reader: a function to read from the stream.
5174 %
5175 */
5177  CustomStreamHandler reader)
5178 {
5179  assert(custom_stream != (CustomStreamInfo *) NULL);
5180  assert(custom_stream->signature == MagickCoreSignature);
5181  custom_stream->reader=reader;
5182 }
5183 
5184 /*
5185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5186 % %
5187 % %
5188 % %
5189 + S e t C u s t o m S t r e a m S e e k e r %
5190 % %
5191 % %
5192 % %
5193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5194 %
5195 % SetCustomStreamSeeker() sets the stream info seeker member.
5196 %
5197 % The format of the SetCustomStreamReader method is:
5198 %
5199 % void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
5200 % CustomStreamSeeker seeker)
5201 %
5202 % A description of each parameter follows:
5203 %
5204 % o custom_stream: the custom stream info.
5205 %
5206 % o seeker: a function to seek in the custom stream.
5207 %
5208 */
5210  CustomStreamSeeker seeker)
5211 {
5212  assert(custom_stream != (CustomStreamInfo *) NULL);
5213  assert(custom_stream->signature == MagickCoreSignature);
5214  custom_stream->seeker=seeker;
5215 }
5216 
5217 /*
5218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5219 % %
5220 % %
5221 % %
5222 + S e t C u s t o m S t r e a m T e l l e r %
5223 % %
5224 % %
5225 % %
5226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5227 %
5228 % SetCustomStreamTeller() sets the stream info teller member.
5229 %
5230 % The format of the SetCustomStreamTeller method is:
5231 %
5232 % void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
5233 % CustomStreamTeller *teller)
5234 %
5235 % A description of each parameter follows:
5236 %
5237 % o custom_stream: the custom stream info.
5238 %
5239 % o teller: a function to set the position in the stream.
5240 %
5241 */
5243  CustomStreamTeller teller)
5244 {
5245  assert(custom_stream != (CustomStreamInfo *) NULL);
5246  assert(custom_stream->signature == MagickCoreSignature);
5247  custom_stream->teller=teller;
5248 }
5249 
5250 /*
5251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5252 % %
5253 % %
5254 % %
5255 + S e t C u s t o m S t r e a m W r i t e r %
5256 % %
5257 % %
5258 % %
5259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5260 %
5261 % SetCustomStreamWriter() sets the stream info writer member.
5262 %
5263 % The format of the SetCustomStreamWriter method is:
5264 %
5265 % void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
5266 % CustomStreamHandler *writer)
5267 %
5268 % A description of each parameter follows:
5269 %
5270 % o custom_stream: the custom stream info.
5271 %
5272 % o writer: a function to write to the custom stream.
5273 %
5274 */
5276  CustomStreamHandler writer)
5277 {
5278  assert(custom_stream != (CustomStreamInfo *) NULL);
5279  assert(custom_stream->signature == MagickCoreSignature);
5280  custom_stream->writer=writer;
5281 }
5282 
5283 /*
5284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5285 % %
5286 % %
5287 % %
5288 + S y n c B l o b %
5289 % %
5290 % %
5291 % %
5292 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5293 %
5294 % SyncBlob() flushes the datastream if it is a file or synchronizes the data
5295 % attributes if it is an blob.
5296 %
5297 % The format of the SyncBlob method is:
5298 %
5299 % int SyncBlob(Image *image)
5300 %
5301 % A description of each parameter follows:
5302 %
5303 % o image: the image.
5304 %
5305 */
5306 static int SyncBlob(Image *image)
5307 {
5308  BlobInfo
5309  *magick_restrict blob_info;
5310 
5311  int
5312  status;
5313 
5314  assert(image != (Image *) NULL);
5315  assert(image->signature == MagickCoreSignature);
5316  if (image->debug != MagickFalse)
5317  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5318  assert(image->blob != (BlobInfo *) NULL);
5319  assert(image->blob->type != UndefinedStream);
5320  blob_info=image->blob;
5321  status=0;
5322  switch (blob_info->type)
5323  {
5324  case UndefinedStream:
5325  case StandardStream:
5326  break;
5327  case FileStream:
5328  case PipeStream:
5329  {
5330  status=fflush(blob_info->file_info.file);
5331  break;
5332  }
5333  case ZipStream:
5334  {
5335 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5336  status=gzflush(blob_info->file_info.gzfile,Z_SYNC_FLUSH);
5337 #endif
5338  break;
5339  }
5340  case BZipStream:
5341  {
5342 #if defined(MAGICKCORE_BZLIB_DELEGATE)
5343  status=BZ2_bzflush(blob_info->file_info.bzfile);
5344 #endif
5345  break;
5346  }
5347  case FifoStream:
5348  break;
5349  case BlobStream:
5350  break;
5351  case CustomStream:
5352  break;
5353  }
5354  return(status);
5355 }
5356 
5357 /*
5358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5359 % %
5360 % %
5361 % %
5362 + T e l l B l o b %
5363 % %
5364 % %
5365 % %
5366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5367 %
5368 % TellBlob() obtains the current value of the blob or file position.
5369 %
5370 % The format of the TellBlob method is:
5371 %
5372 % MagickOffsetType TellBlob(const Image *image)
5373 %
5374 % A description of each parameter follows:
5375 %
5376 % o image: the image.
5377 %
5378 */
5380 {
5381  BlobInfo
5382  *magick_restrict blob_info;
5383 
5385  offset;
5386 
5387  assert(image != (Image *) NULL);
5388  assert(image->signature == MagickCoreSignature);
5389  if (image->debug != MagickFalse)
5390  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5391  assert(image->blob != (BlobInfo *) NULL);
5392  assert(image->blob->type != UndefinedStream);
5393  blob_info=image->blob;
5394  offset=(-1);
5395  switch (blob_info->type)
5396  {
5397  case UndefinedStream:
5398  case StandardStream:
5399  break;
5400  case FileStream:
5401  {
5402  offset=ftell(blob_info->file_info.file);
5403  break;
5404  }
5405  case PipeStream:
5406  break;
5407  case ZipStream:
5408  {
5409 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5410  offset=(MagickOffsetType) gztell(blob_info->file_info.gzfile);
5411 #endif
5412  break;
5413  }
5414  case BZipStream:
5415  break;
5416  case FifoStream:
5417  break;
5418  case BlobStream:
5419  {
5420  offset=blob_info->offset;
5421  break;
5422  }
5423  case CustomStream:
5424  {
5425  if (blob_info->custom_stream->teller != (CustomStreamTeller) NULL)
5426  offset=blob_info->custom_stream->teller(blob_info->custom_stream->data);
5427  break;
5428  }
5429  }
5430  return(offset);
5431 }
5432 
5433 /*
5434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5435 % %
5436 % %
5437 % %
5438 + U n m a p B l o b %
5439 % %
5440 % %
5441 % %
5442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5443 %
5444 % UnmapBlob() deallocates the binary large object previously allocated with
5445 % the MapBlob method.
5446 %
5447 % The format of the UnmapBlob method is:
5448 %
5449 % MagickBooleanType UnmapBlob(void *map,const size_t length)
5450 %
5451 % A description of each parameter follows:
5452 %
5453 % o map: the address of the binary large object.
5454 %
5455 % o length: the length of the binary large object.
5456 %
5457 */
5458 MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
5459 {
5460 #if defined(MAGICKCORE_HAVE_MMAP)
5461  int
5462  status;
5463 
5464  status=munmap(map,length);
5465  return(status == -1 ? MagickFalse : MagickTrue);
5466 #else
5467  (void) map;
5468  (void) length;
5469  return(MagickFalse);
5470 #endif
5471 }
5472 
5473 /*
5474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5475 % %
5476 % %
5477 % %
5478 + W r i t e B l o b %
5479 % %
5480 % %
5481 % %
5482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5483 %
5484 % WriteBlob() writes data to a blob or image file. It returns the number of
5485 % bytes written.
5486 %
5487 % The format of the WriteBlob method is:
5488 %
5489 % ssize_t WriteBlob(Image *image,const size_t length,const void *data)
5490 %
5491 % A description of each parameter follows:
5492 %
5493 % o image: the image.
5494 %
5495 % o length: Specifies an integer representing the number of bytes to
5496 % write to the file.
5497 %
5498 % o data: The address of the data to write to the blob or file.
5499 %
5500 */
5501 MagickExport ssize_t WriteBlob(Image *image,const size_t length,
5502  const void *data)
5503 {
5504  BlobInfo
5505  *magick_restrict blob_info;
5506 
5507  int
5508  c;
5509 
5510  register const unsigned char
5511  *p;
5512 
5513  register unsigned char
5514  *q;
5515 
5516  ssize_t
5517  count;
5518 
5519  assert(image != (Image *) NULL);
5520  assert(image->signature == MagickCoreSignature);
5521  assert(image->blob != (BlobInfo *) NULL);
5522  assert(image->blob->type != UndefinedStream);
5523  if (length == 0)
5524  return(0);
5525  assert(data != (const void *) NULL);
5526  blob_info=image->blob;
5527  count=0;
5528  p=(const unsigned char *) data;
5529  q=(unsigned char *) data;
5530  switch (blob_info->type)
5531  {
5532  case UndefinedStream:
5533  break;
5534  case StandardStream:
5535  case FileStream:
5536  case PipeStream:
5537  {
5538  switch (length)
5539  {
5540  default:
5541  {
5542  count=(ssize_t) fwrite((const char *) data,1,length,
5543  blob_info->file_info.file);
5544  break;
5545  }
5546  case 4:
5547  {
5548  c=putc((int) *p++,blob_info->file_info.file);
5549  if (c == EOF)
5550  break;
5551  count++;
5552  }
5553  case 3:
5554  {
5555  c=putc((int) *p++,blob_info->file_info.file);
5556  if (c == EOF)
5557  break;
5558  count++;
5559  }
5560  case 2:
5561  {
5562  c=putc((int) *p++,blob_info->file_info.file);
5563  if (c == EOF)
5564  break;
5565  count++;
5566  }
5567  case 1:
5568  {
5569  c=putc((int) *p++,blob_info->file_info.file);
5570  if (c == EOF)
5571  break;
5572  count++;
5573  }
5574  case 0:
5575  break;
5576  }
5577  break;
5578  }
5579  case ZipStream:
5580  {
5581 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5582  switch (length)
5583  {
5584  default:
5585  {
5586  register ssize_t
5587  i;
5588 
5589  for (i=0; i < (ssize_t) length; i+=count)
5590  {
5591  count=(ssize_t) gzwrite(blob_info->file_info.gzfile,q+i,
5592  (unsigned int) MagickMin(length-i,MagickMaxBufferExtent));
5593  if (count <= 0)
5594  {
5595  count=0;
5596  if (errno != EINTR)
5597  break;
5598  }
5599  }
5600  count=i;
5601  break;
5602  }
5603  case 4:
5604  {
5605  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5606  if (c == EOF)
5607  break;
5608  count++;
5609  }
5610  case 3:
5611  {
5612  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5613  if (c == EOF)
5614  break;
5615  count++;
5616  }
5617  case 2:
5618  {
5619  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5620  if (c == EOF)
5621  break;
5622  count++;
5623  }
5624  case 1:
5625  {
5626  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5627  if (c == EOF)
5628  break;
5629  count++;
5630  }
5631  case 0:
5632  break;
5633  }
5634 #endif
5635  break;
5636  }
5637  case BZipStream:
5638  {
5639 #if defined(MAGICKCORE_BZLIB_DELEGATE)
5640  register ssize_t
5641  i;
5642 
5643  for (i=0; i < (ssize_t) length; i+=count)
5644  {
5645  count=(ssize_t) BZ2_bzwrite(blob_info->file_info.bzfile,q+i,
5646  (int) MagickMin(length-i,MagickMaxBufferExtent));
5647  if (count <= 0)
5648  {
5649  count=0;
5650  if (errno != EINTR)
5651  break;
5652  }
5653  }
5654  count=i;
5655 #endif
5656  break;
5657  }
5658  case FifoStream:
5659  {
5660  count=(ssize_t) blob_info->stream(image,data,length);
5661  break;
5662  }
5663  case BlobStream:
5664  {
5665  register unsigned char
5666  *q;
5667 
5668  if ((blob_info->offset+(MagickOffsetType) length) >=
5669  (MagickOffsetType) blob_info->extent)
5670  {
5671  if (blob_info->mapped != MagickFalse)
5672  return(0);
5673  blob_info->extent+=length+blob_info->quantum;
5674  blob_info->quantum<<=1;
5675  blob_info->data=(unsigned char *) ResizeQuantumMemory(
5676  blob_info->data,blob_info->extent+1,sizeof(*blob_info->data));
5677  (void) SyncBlob(image);
5678  if (blob_info->data == (unsigned char *) NULL)
5679  {
5680  (void) DetachBlob(blob_info);
5681  return(0);
5682  }
5683  }
5684  q=blob_info->data+blob_info->offset;
5685  (void) memcpy(q,p,length);
5686  blob_info->offset+=length;
5687  if (blob_info->offset >= (MagickOffsetType) blob_info->length)
5688  blob_info->length=(size_t) blob_info->offset;
5689  count=(ssize_t) length;
5690  break;
5691  }
5692  case CustomStream:
5693  {
5694  if (blob_info->custom_stream->writer != (CustomStreamHandler) NULL)
5695  count=blob_info->custom_stream->writer((unsigned char *) data,
5696  length,blob_info->custom_stream->data);
5697  break;
5698  }
5699  }
5700  return(count);
5701 }
5702 
5703 /*
5704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5705 % %
5706 % %
5707 % %
5708 + W r i t e B l o b B y t e %
5709 % %
5710 % %
5711 % %
5712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5713 %
5714 % WriteBlobByte() write an integer to a blob. It returns the number of bytes
5715 % written (either 0 or 1);
5716 %
5717 % The format of the WriteBlobByte method is:
5718 %
5719 % ssize_t WriteBlobByte(Image *image,const unsigned char value)
5720 %
5721 % A description of each parameter follows.
5722 %
5723 % o image: the image.
5724 %
5725 % o value: Specifies the value to write.
5726 %
5727 */
5728 MagickExport ssize_t WriteBlobByte(Image *image,const unsigned char value)
5729 {
5730  BlobInfo
5731  *magick_restrict blob_info;
5732 
5733  ssize_t
5734  count;
5735 
5736  assert(image != (Image *) NULL);
5737  assert(image->signature == MagickCoreSignature);
5738  assert(image->blob != (BlobInfo *) NULL);
5739  assert(image->blob->type != UndefinedStream);
5740  blob_info=image->blob;
5741  count=0;
5742  switch (blob_info->type)
5743  {
5744  case StandardStream:
5745  case FileStream:
5746  case PipeStream:
5747  {
5748  int
5749  c;
5750 
5751  c=putc((int) value,blob_info->file_info.file);
5752  if (c == EOF)
5753  break;
5754  count++;
5755  break;
5756  }
5757  default:
5758  {
5759  count=WriteBlobStream(image,1,&value);
5760  break;
5761  }
5762  }
5763  return(count);
5764 }
5765 
5766 /*
5767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5768 % %
5769 % %
5770 % %
5771 + W r i t e B l o b F l o a t %
5772 % %
5773 % %
5774 % %
5775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5776 %
5777 % WriteBlobFloat() writes a float value as a 32-bit quantity in the byte-order
5778 % specified by the endian member of the image structure.
5779 %
5780 % The format of the WriteBlobFloat method is:
5781 %
5782 % ssize_t WriteBlobFloat(Image *image,const float value)
5783 %
5784 % A description of each parameter follows.
5785 %
5786 % o image: the image.
5787 %
5788 % o value: Specifies the value to write.
5789 %
5790 */
5791 MagickExport ssize_t WriteBlobFloat(Image *image,const float value)
5792 {
5793  union
5794  {
5795  unsigned int
5796  unsigned_value;
5797 
5798  float
5799  float_value;
5800  } quantum;
5801 
5802  quantum.unsigned_value=0U;
5803  quantum.float_value=value;
5804  return(WriteBlobLong(image,quantum.unsigned_value));
5805 }
5806 
5807 /*
5808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5809 % %
5810 % %
5811 % %
5812 + W r i t e B l o b L o n g %
5813 % %
5814 % %
5815 % %
5816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5817 %
5818 % WriteBlobLong() writes a unsigned int value as a 32-bit quantity in the
5819 % byte-order specified by the endian member of the image structure.
5820 %
5821 % The format of the WriteBlobLong method is:
5822 %
5823 % ssize_t WriteBlobLong(Image *image,const unsigned int value)
5824 %
5825 % A description of each parameter follows.
5826 %
5827 % o image: the image.
5828 %
5829 % o value: Specifies the value to write.
5830 %
5831 */
5832 MagickExport ssize_t WriteBlobLong(Image *image,const unsigned int value)
5833 {
5834  unsigned char
5835  buffer[4];
5836 
5837  assert(image != (Image *) NULL);
5838  assert(image->signature == MagickCoreSignature);
5839  if (image->endian == LSBEndian)
5840  {
5841  buffer[0]=(unsigned char) value;
5842  buffer[1]=(unsigned char) (value >> 8);
5843  buffer[2]=(unsigned char) (value >> 16);
5844  buffer[3]=(unsigned char) (value >> 24);
5845  return(WriteBlobStream(image,4,buffer));
5846  }
5847  buffer[0]=(unsigned char) (value >> 24);
5848  buffer[1]=(unsigned char) (value >> 16);
5849  buffer[2]=(unsigned char) (value >> 8);
5850  buffer[3]=(unsigned char) value;
5851  return(WriteBlobStream(image,4,buffer));
5852 }
5853 
5854 /*
5855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5856 % %
5857 % %
5858 % %
5859 + W r i t e B l o b L o n g L o n g %
5860 % %
5861 % %
5862 % %
5863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5864 %
5865 % WriteBlobMSBLongLong() writes a long long value as a 64-bit quantity in the
5866 % byte-order specified by the endian member of the image structure.
5867 %
5868 % The format of the WriteBlobLongLong method is:
5869 %
5870 % ssize_t WriteBlobLongLong(Image *image,const MagickSizeType value)
5871 %
5872 % A description of each parameter follows.
5873 %
5874 % o value: Specifies the value to write.
5875 %
5876 % o image: the image.
5877 %
5878 */
5880 {
5881  unsigned char
5882  buffer[8];
5883 
5884  assert(image != (Image *) NULL);
5885  assert(image->signature == MagickCoreSignature);
5886  if (image->endian == LSBEndian)
5887  {
5888  buffer[0]=(unsigned char) value;
5889  buffer[1]=(unsigned char) (value >> 8);
5890  buffer[2]=(unsigned char) (value >> 16);
5891  buffer[3]=(unsigned char) (value >> 24);
5892  buffer[4]=(unsigned char) (value >> 32);
5893  buffer[5]=(unsigned char) (value >> 40);
5894  buffer[6]=(unsigned char) (value >> 48);
5895  buffer[7]=(unsigned char) (value >> 56);
5896  return(WriteBlobStream(image,8,buffer));
5897  }
5898  buffer[0]=(unsigned char) (value >> 56);
5899  buffer[1]=(unsigned char) (value >> 48);
5900  buffer[2]=(unsigned char) (value >> 40);
5901  buffer[3]=(unsigned char) (value >> 32);
5902  buffer[4]=(unsigned char) (value >> 24);
5903  buffer[5]=(unsigned char) (value >> 16);
5904  buffer[6]=(unsigned char) (value >> 8);
5905  buffer[7]=(unsigned char) value;
5906  return(WriteBlobStream(image,8,buffer));
5907 }
5908 
5909 /*
5910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5911 % %
5912 % %
5913 % %
5914 + W r i t e B l o b S h o r t %
5915 % %
5916 % %
5917 % %
5918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5919 %
5920 % WriteBlobShort() writes a short value as a 16-bit quantity in the
5921 % byte-order specified by the endian member of the image structure.
5922 %
5923 % The format of the WriteBlobShort method is:
5924 %
5925 % ssize_t WriteBlobShort(Image *image,const unsigned short value)
5926 %
5927 % A description of each parameter follows.
5928 %
5929 % o image: the image.
5930 %
5931 % o value: Specifies the value to write.
5932 %
5933 */
5934 MagickExport ssize_t WriteBlobShort(Image *image,const unsigned short value)
5935 {
5936  unsigned char
5937  buffer[2];
5938 
5939  assert(image != (Image *) NULL);
5940  assert(image->signature == MagickCoreSignature);
5941  if (image->endian == LSBEndian)
5942  {
5943  buffer[0]=(unsigned char) value;
5944  buffer[1]=(unsigned char) (value >> 8);
5945  return(WriteBlobStream(image,2,buffer));
5946  }
5947  buffer[0]=(unsigned char) (value >> 8);
5948  buffer[1]=(unsigned char) value;
5949  return(WriteBlobStream(image,2,buffer));
5950 }
5951 
5952 /*
5953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5954 % %
5955 % %
5956 % %
5957 + W r i t e B l o b S i g n e d L o n g %
5958 % %
5959 % %
5960 % %
5961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5962 %
5963 % WriteBlobSignedLong() writes a signed value as a 32-bit quantity in the
5964 % byte-order specified by the endian member of the image structure.
5965 %
5966 % The format of the WriteBlobSignedLong method is:
5967 %
5968 % ssize_t WriteBlobSignedLong(Image *image,const signed int value)
5969 %
5970 % A description of each parameter follows.
5971 %
5972 % o image: the image.
5973 %
5974 % o value: Specifies the value to write.
5975 %
5976 */
5977 MagickExport ssize_t WriteBlobSignedLong(Image *image,const signed int value)
5978 {
5979  union
5980  {
5981  unsigned int
5982  unsigned_value;
5983 
5984  signed int
5985  signed_value;
5986  } quantum;
5987 
5988  unsigned char
5989  buffer[4];
5990 
5991  assert(image != (Image *) NULL);
5992  assert(image->signature == MagickCoreSignature);
5993  quantum.signed_value=value;
5994  if (image->endian == LSBEndian)
5995  {
5996  buffer[0]=(unsigned char) quantum.unsigned_value;
5997  buffer[1]=(unsigned char) (quantum.unsigned_value >> 8);
5998  buffer[2]=(unsigned char) (quantum.unsigned_value >> 16);
5999  buffer[3]=(unsigned char) (quantum.unsigned_value >> 24);
6000  return(WriteBlobStream(image,4,buffer));
6001  }
6002  buffer[0]=(unsigned char) (quantum.unsigned_value >> 24);
6003  buffer[1]=(unsigned char) (quantum.unsigned_value >> 16);
6004  buffer[2]=(unsigned char) (quantum.unsigned_value >> 8);
6005  buffer[3]=(unsigned char) quantum.unsigned_value;
6006  return(WriteBlobStream(image,4,buffer));
6007 }
6008 
6009 /*
6010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6011 % %
6012 % %
6013 % %
6014 + W r i t e B l o b L S B L o n g %
6015 % %
6016 % %
6017 % %
6018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6019 %
6020 % WriteBlobLSBLong() writes a unsigned int value as a 32-bit quantity in
6021 % least-significant byte first order.
6022 %
6023 % The format of the WriteBlobLSBLong method is:
6024 %
6025 % ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
6026 %
6027 % A description of each parameter follows.
6028 %
6029 % o image: the image.
6030 %
6031 % o value: Specifies the value to write.
6032 %
6033 */
6034 MagickExport ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
6035 {
6036  unsigned char
6037  buffer[4];
6038 
6039  assert(image != (Image *) NULL);
6040  assert(image->signature == MagickCoreSignature);
6041  buffer[0]=(unsigned char) value;
6042  buffer[1]=(unsigned char) (value >> 8);
6043  buffer[2]=(unsigned char) (value >> 16);
6044  buffer[3]=(unsigned char) (value >> 24);
6045  return(WriteBlobStream(image,4,buffer));
6046 }
6047 
6048 /*
6049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6050 % %
6051 % %
6052 % %
6053 + W r i t e B l o b L S B S h o r t %
6054 % %
6055 % %
6056 % %
6057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6058 %
6059 % WriteBlobLSBShort() writes a unsigned short value as a 16-bit quantity in
6060 % least-significant byte first order.
6061 %
6062 % The format of the WriteBlobLSBShort method is:
6063 %
6064 % ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
6065 %
6066 % A description of each parameter follows.
6067 %
6068 % o image: the image.
6069 %
6070 % o value: Specifies the value to write.
6071 %
6072 */
6073 MagickExport ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
6074 {
6075  unsigned char
6076  buffer[2];
6077 
6078  assert(image != (Image *) NULL);
6079  assert(image->signature == MagickCoreSignature);
6080  buffer[0]=(unsigned char) value;
6081  buffer[1]=(unsigned char) (value >> 8);
6082  return(WriteBlobStream(image,2,buffer));
6083 }
6084 
6085 /*
6086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6087 % %
6088 % %
6089 % %
6090 + W r i t e B l o b L S B S i g n e d L o n g %
6091 % %
6092 % %
6093 % %
6094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6095 %
6096 % WriteBlobLSBSignedLong() writes a signed value as a 32-bit quantity in
6097 % least-significant byte first order.
6098 %
6099 % The format of the WriteBlobLSBSignedLong method is:
6100 %
6101 % ssize_t WriteBlobLSBSignedLong(Image *image,const signed int value)
6102 %
6103 % A description of each parameter follows.
6104 %
6105 % o image: the image.
6106 %
6107 % o value: Specifies the value to write.
6108 %
6109 */
6110 MagickExport ssize_t WriteBlobLSBSignedLong(Image *image,const signed int value)
6111 {
6112  union
6113  {
6114  unsigned int
6115  unsigned_value;
6116 
6117  signed int
6118  signed_value;
6119  } quantum;
6120 
6121  unsigned char
6122  buffer[4];
6123 
6124  assert(image != (Image *) NULL);
6125  assert(image->signature == MagickCoreSignature);
6126  quantum.signed_value=value;
6127  buffer[0]=(unsigned char) quantum.unsigned_value;
6128  buffer[1]=(unsigned char) (quantum.unsigned_value >> 8);
6129  buffer[2]=(unsigned char) (quantum.unsigned_value >> 16);
6130  buffer[3]=(unsigned char) (quantum.unsigned_value >> 24);
6131  return(WriteBlobStream(image,4,buffer));
6132 }
6133 
6134 /*
6135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6136 % %
6137 %