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