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