MagickCore  7.0.10
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-2020 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  register 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)
374  SSIZE_MAX));
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 {
1138  register MagickOffsetType
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  register 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) 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  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  register 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  register const unsigned char
2306  *p;
2307 
2308  register 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  if (file != -1)
2379  file=close(file);
2380  ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
2381  return(MagickFalse);
2382  }
2383  return(MagickTrue);
2384 }
2385 
2386 /*
2387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388 % %
2389 % %
2390 % %
2391 % I m a g e s T o B l o b %
2392 % %
2393 % %
2394 % %
2395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2396 %
2397 % ImagesToBlob() implements direct to memory image formats. It returns the
2398 % image sequence as a blob and its length. The magick member of the ImageInfo
2399 % structure determines the format of the returned blob (GIF, JPEG, PNG, etc.)
2400 %
2401 % Note, some image formats do not permit multiple images to the same image
2402 % stream (e.g. JPEG). in this instance, just the first image of the
2403 % sequence is returned as a blob.
2404 %
2405 % The format of the ImagesToBlob method is:
2406 %
2407 % void *ImagesToBlob(const ImageInfo *image_info,Image *images,
2408 % size_t *length,ExceptionInfo *exception)
2409 %
2410 % A description of each parameter follows:
2411 %
2412 % o image_info: the image info.
2413 %
2414 % o images: the image list.
2415 %
2416 % o length: return the actual length of the blob.
2417 %
2418 % o exception: return any errors or warnings in this structure.
2419 %
2420 */
2421 MagickExport void *ImagesToBlob(const ImageInfo *image_info,Image *images,
2422  size_t *length,ExceptionInfo *exception)
2423 {
2424  const MagickInfo
2425  *magick_info;
2426 
2427  ImageInfo
2428  *clone_info;
2429 
2431  status;
2432 
2433  void
2434  *blob;
2435 
2436  assert(image_info != (const ImageInfo *) NULL);
2437  assert(image_info->signature == MagickCoreSignature);
2438  if (image_info->debug != MagickFalse)
2440  image_info->filename);
2441  assert(images != (Image *) NULL);
2442  assert(images->signature == MagickCoreSignature);
2443  assert(exception != (ExceptionInfo *) NULL);
2444  *length=0;
2445  blob=(unsigned char *) NULL;
2446  clone_info=CloneImageInfo(image_info);
2447  (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(images),
2448  exception);
2449  if (*clone_info->magick != '\0')
2450  (void) CopyMagickString(images->magick,clone_info->magick,MagickPathExtent);
2451  magick_info=GetMagickInfo(images->magick,exception);
2452  if (magick_info == (const MagickInfo *) NULL)
2453  {
2454  (void) ThrowMagickException(exception,GetMagickModule(),
2455  MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
2456  images->magick);
2457  clone_info=DestroyImageInfo(clone_info);
2458  return(blob);
2459  }
2460  if (GetMagickAdjoin(magick_info) == MagickFalse)
2461  {
2462  clone_info=DestroyImageInfo(clone_info);
2463  return(ImageToBlob(image_info,images,length,exception));
2464  }
2465  (void) CopyMagickString(clone_info->magick,images->magick,MagickPathExtent);
2466  if (GetMagickBlobSupport(magick_info) != MagickFalse)
2467  {
2468  /*
2469  Native blob support for this images format.
2470  */
2471  clone_info->length=0;
2472  clone_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
2473  sizeof(unsigned char));
2474  if (clone_info->blob == (void *) NULL)
2475  (void) ThrowMagickException(exception,GetMagickModule(),
2476  ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
2477  else
2478  {
2479  (void) CloseBlob(images);
2480  images->blob->exempt=MagickTrue;
2481  *images->filename='\0';
2482  status=WriteImages(clone_info,images,images->filename,exception);
2483  *length=images->blob->length;
2484  blob=DetachBlob(images->blob);
2485  if (blob == (void *) NULL)
2486  clone_info->blob=RelinquishMagickMemory(clone_info->blob);
2487  else if (status == MagickFalse)
2488  blob=RelinquishMagickMemory(blob);
2489  else
2490  blob=ResizeQuantumMemory(blob,*length+1,sizeof(unsigned char));
2491  }
2492  }
2493  else
2494  {
2495  char
2496  filename[MagickPathExtent],
2497  unique[MagickPathExtent];
2498 
2499  int
2500  file;
2501 
2502  /*
2503  Write file to disk in blob images format.
2504  */
2505  file=AcquireUniqueFileResource(unique);
2506  if (file == -1)
2507  {
2508  ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",
2509  image_info->filename);
2510  }
2511  else
2512  {
2513  clone_info->file=fdopen(file,"wb");
2514  if (clone_info->file != (FILE *) NULL)
2515  {
2516  (void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
2517  images->magick,unique);
2518  status=WriteImages(clone_info,images,filename,exception);
2519  (void) CloseBlob(images);
2520  (void) fclose(clone_info->file);
2521  if (status != MagickFalse)
2522  blob=FileToBlob(unique,~0UL,length,exception);
2523  }
2524  (void) RelinquishUniqueFileResource(unique);
2525  }
2526  }
2527  clone_info=DestroyImageInfo(clone_info);
2528  return(blob);
2529 }
2530 
2531 /*
2532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2533 % %
2534 % %
2535 % %
2536 + I m a g e s T o C u s t o m B l o b %
2537 % %
2538 % %
2539 % %
2540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2541 %
2542 % ImagesToCustomStream() is the equivalent of WriteImages(), but writes the
2543 % formatted "file" to the custom stream rather than to an actual file.
2544 %
2545 % The format of the ImageToCustomStream method is:
2546 %
2547 % void ImagesToCustomStream(const ImageInfo *image_info,Image *images,
2548 % ExceptionInfo *exception)
2549 %
2550 % A description of each parameter follows:
2551 %
2552 % o image_info: the image info.
2553 %
2554 % o images: the image list.
2555 %
2556 % o exception: return any errors or warnings in this structure.
2557 %
2558 */
2560  Image *images,ExceptionInfo *exception)
2561 {
2562  const MagickInfo
2563  *magick_info;
2564 
2565  ImageInfo
2566  *clone_info;
2567 
2569  blob_support,
2570  status;
2571 
2572  assert(image_info != (const ImageInfo *) NULL);
2573  assert(image_info->signature == MagickCoreSignature);
2574  if (image_info->debug != MagickFalse)
2576  image_info->filename);
2577  assert(images != (Image *) NULL);
2578  assert(images->signature == MagickCoreSignature);
2579  assert(image_info->custom_stream != (CustomStreamInfo *) NULL);
2580  assert(image_info->custom_stream->signature == MagickCoreSignature);
2581  assert(image_info->custom_stream->reader != (CustomStreamHandler) NULL);
2582  assert(image_info->custom_stream->writer != (CustomStreamHandler) NULL);
2583  assert(exception != (ExceptionInfo *) NULL);
2584  clone_info=CloneImageInfo(image_info);
2585  (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(images),
2586  exception);
2587  if (*clone_info->magick != '\0')
2588  (void) CopyMagickString(images->magick,clone_info->magick,MagickPathExtent);
2589  magick_info=GetMagickInfo(images->magick,exception);
2590  if (magick_info == (const MagickInfo *) NULL)
2591  {
2592  (void) ThrowMagickException(exception,GetMagickModule(),
2593  MissingDelegateError,"NoEncodeDelegateForThisImageFormat","`%s'",
2594  images->magick);
2595  clone_info=DestroyImageInfo(clone_info);
2596  return;
2597  }
2598  (void) CopyMagickString(clone_info->magick,images->magick,MagickPathExtent);
2599  blob_support=GetMagickBlobSupport(magick_info);
2600  if ((blob_support != MagickFalse) &&
2601  (GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
2602  {
2603  if ((clone_info->custom_stream->seeker == (CustomStreamSeeker) NULL) ||
2604  (clone_info->custom_stream->teller == (CustomStreamTeller) NULL))
2605  blob_support=MagickFalse;
2606  }
2607  if (blob_support != MagickFalse)
2608  {
2609  /*
2610  Native blob support for this image format.
2611  */
2612  (void) CloseBlob(images);
2613  *images->filename='\0';
2614  (void) WriteImages(clone_info,images,images->filename,exception);
2615  (void) CloseBlob(images);
2616  }
2617  else
2618  {
2619  char
2620  filename[MagickPathExtent],
2621  unique[MagickPathExtent];
2622 
2623  int
2624  file;
2625 
2626  unsigned char
2627  *blob;
2628 
2629  /*
2630  Write file to disk in blob image format.
2631  */
2632  clone_info->custom_stream=(CustomStreamInfo *) NULL;
2633  blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
2634  sizeof(*blob));
2635  if (blob == (unsigned char *) NULL)
2636  {
2637  ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2638  image_info->filename);
2639  clone_info=DestroyImageInfo(clone_info);
2640  return;
2641  }
2642  file=AcquireUniqueFileResource(unique);
2643  if (file == -1)
2644  {
2645  ThrowFileException(exception,BlobError,"UnableToWriteBlob",
2646  image_info->filename);
2647  blob=(unsigned char *) RelinquishMagickMemory(blob);
2648  clone_info=DestroyImageInfo(clone_info);
2649  return;
2650  }
2651  clone_info->file=fdopen(file,"wb+");
2652  if (clone_info->file != (FILE *) NULL)
2653  {
2654  ssize_t
2655  count;
2656 
2657  (void) FormatLocaleString(filename,MagickPathExtent,"%s:%s",
2658  images->magick,unique);
2659  status=WriteImages(clone_info,images,filename,exception);
2660  (void) CloseBlob(images);
2661  if (status != MagickFalse)
2662  {
2663  (void) fseek(clone_info->file,0,SEEK_SET);
2664  count=(ssize_t) MagickMaxBufferExtent;
2665  while (count == (ssize_t) MagickMaxBufferExtent)
2666  {
2667  count=(ssize_t) fread(blob,sizeof(*blob),MagickMaxBufferExtent,
2668  clone_info->file);
2669  (void) image_info->custom_stream->writer(blob,(size_t) count,
2670  image_info->custom_stream->data);
2671  }
2672  }
2673  (void) fclose(clone_info->file);
2674  }
2675  blob=(unsigned char *) RelinquishMagickMemory(blob);
2676  (void) RelinquishUniqueFileResource(unique);
2677  }
2678  clone_info=DestroyImageInfo(clone_info);
2679 }
2680 
2681 /*
2682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2683 % %
2684 % %
2685 % %
2686 % I n j e c t I m a g e B l o b %
2687 % %
2688 % %
2689 % %
2690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2691 %
2692 % InjectImageBlob() injects the image with a copy of itself in the specified
2693 % format (e.g. inject JPEG into a PDF image).
2694 %
2695 % The format of the InjectImageBlob method is:
2696 %
2697 % MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
2698 % Image *image,Image *inject_image,const char *format,
2699 % ExceptionInfo *exception)
2700 %
2701 % A description of each parameter follows:
2702 %
2703 % o image_info: the image info..
2704 %
2705 % o image: the image.
2706 %
2707 % o inject_image: inject into the image stream.
2708 %
2709 % o format: the image format.
2710 %
2711 % o exception: return any errors or warnings in this structure.
2712 %
2713 */
2715  Image *image,Image *inject_image,const char *format,ExceptionInfo *exception)
2716 {
2717  char
2718  filename[MagickPathExtent];
2719 
2720  FILE
2721  *unique_file;
2722 
2723  Image
2724  *byte_image;
2725 
2726  ImageInfo
2727  *write_info;
2728 
2729  int
2730  file;
2731 
2733  status;
2734 
2735  register ssize_t
2736  i;
2737 
2738  size_t
2739  quantum;
2740 
2741  ssize_t
2742  count;
2743 
2744  struct stat
2745  file_stats;
2746 
2747  unsigned char
2748  *buffer;
2749 
2750  /*
2751  Write inject image to a temporary file.
2752  */
2753  assert(image_info != (ImageInfo *) NULL);
2754  assert(image_info->signature == MagickCoreSignature);
2755  assert(image != (Image *) NULL);
2756  assert(image->signature == MagickCoreSignature);
2757  if (image->debug != MagickFalse)
2758  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2759  assert(inject_image != (Image *) NULL);
2760  assert(inject_image->signature == MagickCoreSignature);
2761  assert(exception != (ExceptionInfo *) NULL);
2762  unique_file=(FILE *) NULL;
2763  file=AcquireUniqueFileResource(filename);
2764  if (file != -1)
2765  unique_file=fdopen(file,"wb");
2766  if ((file == -1) || (unique_file == (FILE *) NULL))
2767  {
2768  (void) CopyMagickString(image->filename,filename,MagickPathExtent);
2769  ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2770  image->filename);
2771  return(MagickFalse);
2772  }
2773  byte_image=CloneImage(inject_image,0,0,MagickFalse,exception);
2774  if (byte_image == (Image *) NULL)
2775  {
2776  (void) fclose(unique_file);
2777  (void) RelinquishUniqueFileResource(filename);
2778  return(MagickFalse);
2779  }
2780  (void) FormatLocaleString(byte_image->filename,MagickPathExtent,"%s:%s",
2781  format,filename);
2782  DestroyBlob(byte_image);
2783  byte_image->blob=CloneBlobInfo((BlobInfo *) NULL);
2784  write_info=CloneImageInfo(image_info);
2785  SetImageInfoFile(write_info,unique_file);
2786  status=WriteImage(write_info,byte_image,exception);
2787  write_info=DestroyImageInfo(write_info);
2788  byte_image=DestroyImage(byte_image);
2789  (void) fclose(unique_file);
2790  if (status == MagickFalse)
2791  {
2792  (void) RelinquishUniqueFileResource(filename);
2793  return(MagickFalse);
2794  }
2795  /*
2796  Inject into image stream.
2797  */
2798  file=open_utf8(filename,O_RDONLY | O_BINARY,0);
2799  if (file == -1)
2800  {
2801  (void) RelinquishUniqueFileResource(filename);
2802  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
2803  image_info->filename);
2804  return(MagickFalse);
2805  }
2806  quantum=(size_t) MagickMaxBufferExtent;
2807  if ((fstat(file,&file_stats) == 0) && (file_stats.st_size > 0))
2808  quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
2809  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
2810  if (buffer == (unsigned char *) NULL)
2811  {
2812  (void) RelinquishUniqueFileResource(filename);
2813  file=close(file);
2814  ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2815  image->filename);
2816  }
2817  for (i=0; ; i+=count)
2818  {
2819  count=read(file,buffer,quantum);
2820  if (count <= 0)
2821  {
2822  count=0;
2823  if (errno != EINTR)
2824  break;
2825  }
2826  status=WriteBlobStream(image,(size_t) count,buffer) == count ? MagickTrue :
2827  MagickFalse;
2828  }
2829  file=close(file);
2830  if (file == -1)
2831  ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",filename);
2832  (void) RelinquishUniqueFileResource(filename);
2833  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2834  return(status);
2835 }
2836 
2837 /*
2838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839 % %
2840 % %
2841 % %
2842 % I s B l o b E x e m p t %
2843 % %
2844 % %
2845 % %
2846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847 %
2848 % IsBlobExempt() returns true if the blob is exempt.
2849 %
2850 % The format of the IsBlobExempt method is:
2851 %
2852 % MagickBooleanType IsBlobExempt(const Image *image)
2853 %
2854 % A description of each parameter follows:
2855 %
2856 % o image: the image.
2857 %
2858 */
2860 {
2861  assert(image != (const Image *) NULL);
2862  assert(image->signature == MagickCoreSignature);
2863  if (image->debug != MagickFalse)
2864  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2865  return(image->blob->exempt);
2866 }
2867 
2868 /*
2869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2870 % %
2871 % %
2872 % %
2873 % I s B l o b S e e k a b l e %
2874 % %
2875 % %
2876 % %
2877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878 %
2879 % IsBlobSeekable() returns true if the blob is seekable.
2880 %
2881 % The format of the IsBlobSeekable method is:
2882 %
2883 % MagickBooleanType IsBlobSeekable(const Image *image)
2884 %
2885 % A description of each parameter follows:
2886 %
2887 % o image: the image.
2888 %
2889 */
2891 {
2892  BlobInfo
2893  *magick_restrict blob_info;
2894 
2895  assert(image != (const Image *) NULL);
2896  assert(image->signature == MagickCoreSignature);
2897  if (image->debug != MagickFalse)
2898  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2899  blob_info=image->blob;
2900  switch (blob_info->type)
2901  {
2902  case BlobStream:
2903  return(MagickTrue);
2904  case FileStream:
2905  {
2906  int
2907  status;
2908 
2909  if (blob_info->file_info.file == (FILE *) NULL)
2910  return(MagickFalse);
2911  status=fseek(blob_info->file_info.file,0,SEEK_CUR);
2912  return(status == -1 ? MagickFalse : MagickTrue);
2913  }
2914  case ZipStream:
2915  {
2916 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2918  offset;
2919 
2920  if (blob_info->file_info.gzfile == (gzFile) NULL)
2921  return(MagickFalse);
2922  offset=gzseek(blob_info->file_info.gzfile,0,SEEK_CUR);
2923  return(offset < 0 ? MagickFalse : MagickTrue);
2924 #else
2925  break;
2926 #endif
2927  }
2928  case UndefinedStream:
2929  case BZipStream:
2930  case FifoStream:
2931  case PipeStream:
2932  case StandardStream:
2933  break;
2934  case CustomStream:
2935  {
2936  if ((blob_info->custom_stream->seeker != (CustomStreamSeeker) NULL) &&
2937  (blob_info->custom_stream->teller != (CustomStreamTeller) NULL))
2938  return(MagickTrue);
2939  break;
2940  }
2941  default:
2942  break;
2943  }
2944  return(MagickFalse);
2945 }
2946 
2947 /*
2948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2949 % %
2950 % %
2951 % %
2952 % I s B l o b T e m p o r a r y %
2953 % %
2954 % %
2955 % %
2956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957 %
2958 % IsBlobTemporary() returns true if the blob is temporary.
2959 %
2960 % The format of the IsBlobTemporary method is:
2961 %
2962 % MagickBooleanType IsBlobTemporary(const Image *image)
2963 %
2964 % A description of each parameter follows:
2965 %
2966 % o image: the image.
2967 %
2968 */
2970 {
2971  assert(image != (const Image *) NULL);
2972  assert(image->signature == MagickCoreSignature);
2973  if (image->debug != MagickFalse)
2974  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2975  return(image->blob->temporary);
2976 }
2977 
2978 /*
2979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2980 % %
2981 % %
2982 % %
2983 + M a p B l o b %
2984 % %
2985 % %
2986 % %
2987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988 %
2989 % MapBlob() creates a mapping from a file to a binary large object.
2990 %
2991 % The format of the MapBlob method is:
2992 %
2993 % void *MapBlob(int file,const MapMode mode,const MagickOffsetType offset,
2994 % const size_t length)
2995 %
2996 % A description of each parameter follows:
2997 %
2998 % o file: map this file descriptor.
2999 %
3000 % o mode: ReadMode, WriteMode, or IOMode.
3001 %
3002 % o offset: starting at this offset within the file.
3003 %
3004 % o length: the length of the mapping is returned in this pointer.
3005 %
3006 */
3007 MagickExport void *MapBlob(int file,const MapMode mode,
3008  const MagickOffsetType offset,const size_t length)
3009 {
3010 #if defined(MAGICKCORE_HAVE_MMAP)
3011  int
3012  flags,
3013  protection;
3014 
3015  void
3016  *map;
3017 
3018  /*
3019  Map file.
3020  */
3021  flags=0;
3022  if (file == -1)
3023 #if defined(MAP_ANONYMOUS)
3024  flags|=MAP_ANONYMOUS;
3025 #else
3026  return(NULL);
3027 #endif
3028  switch (mode)
3029  {
3030  case ReadMode:
3031  default:
3032  {
3033  protection=PROT_READ;
3034  flags|=MAP_PRIVATE;
3035  break;
3036  }
3037  case WriteMode:
3038  {
3039  protection=PROT_WRITE;
3040  flags|=MAP_SHARED;
3041  break;
3042  }
3043  case IOMode:
3044  {
3045  protection=PROT_READ | PROT_WRITE;
3046  flags|=MAP_SHARED;
3047  break;
3048  }
3049  }
3050 #if !defined(MAGICKCORE_HAVE_HUGEPAGES) || !defined(MAP_HUGETLB)
3051  map=mmap((char *) NULL,length,protection,flags,file,offset);
3052 #else
3053  map=mmap((char *) NULL,length,protection,flags | MAP_HUGETLB,file,offset);
3054  if (map == MAP_FAILED)
3055  map=mmap((char *) NULL,length,protection,flags,file,offset);
3056 #endif
3057  if (map == MAP_FAILED)
3058  return(NULL);
3059  return(map);
3060 #else
3061  (void) file;
3062  (void) mode;
3063  (void) offset;
3064  (void) length;
3065  return(NULL);
3066 #endif
3067 }
3068 
3069 /*
3070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3071 % %
3072 % %
3073 % %
3074 + M S B O r d e r L o n g %
3075 % %
3076 % %
3077 % %
3078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3079 %
3080 % MSBOrderLong() converts a least-significant byte first buffer of integers to
3081 % most-significant byte first.
3082 %
3083 % The format of the MSBOrderLong method is:
3084 %
3085 % void MSBOrderLong(unsigned char *buffer,const size_t length)
3086 %
3087 % A description of each parameter follows.
3088 %
3089 % o buffer: Specifies a pointer to a buffer of integers.
3090 %
3091 % o length: Specifies the length of the buffer.
3092 %
3093 */
3094 MagickExport void MSBOrderLong(unsigned char *buffer,const size_t length)
3095 {
3096  int
3097  c;
3098 
3099  register unsigned char
3100  *p,
3101  *q;
3102 
3103  assert(buffer != (unsigned char *) NULL);
3104  q=buffer+length;
3105  while (buffer < q)
3106  {
3107  p=buffer+3;
3108  c=(int) (*p);
3109  *p=(*buffer);
3110  *buffer++=(unsigned char) c;
3111  p=buffer+1;
3112  c=(int) (*p);
3113  *p=(*buffer);
3114  *buffer++=(unsigned char) c;
3115  buffer+=2;
3116  }
3117 }
3118 
3119 /*
3120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3121 % %
3122 % %
3123 % %
3124 + M S B O r d e r S h o r t %
3125 % %
3126 % %
3127 % %
3128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3129 %
3130 % MSBOrderShort() converts a least-significant byte first buffer of integers
3131 % to most-significant byte first.
3132 %
3133 % The format of the MSBOrderShort method is:
3134 %
3135 % void MSBOrderShort(unsigned char *p,const size_t length)
3136 %
3137 % A description of each parameter follows.
3138 %
3139 % o p: Specifies a pointer to a buffer of integers.
3140 %
3141 % o length: Specifies the length of the buffer.
3142 %
3143 */
3144 MagickExport void MSBOrderShort(unsigned char *p,const size_t length)
3145 {
3146  int
3147  c;
3148 
3149  register unsigned char
3150  *q;
3151 
3152  assert(p != (unsigned char *) NULL);
3153  q=p+length;
3154  while (p < q)
3155  {
3156  c=(int) (*p);
3157  *p=(*(p+1));
3158  p++;
3159  *p++=(unsigned char) c;
3160  }
3161 }
3162 
3163 /*
3164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3165 % %
3166 % %
3167 % %
3168 + O p e n B l o b %
3169 % %
3170 % %
3171 % %
3172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3173 %
3174 % OpenBlob() opens a file associated with the image. A file name of '-' sets
3175 % the file to stdin for type 'r' and stdout for type 'w'. If the filename
3176 % suffix is '.gz' or '.Z', the image is decompressed for type 'r' and
3177 % compressed for type 'w'. If the filename prefix is '|', it is piped to or
3178 % from a system command.
3179 %
3180 % The format of the OpenBlob method is:
3181 %
3182 % MagickBooleanType OpenBlob(const ImageInfo *image_info,Image *image,
3183 % const BlobMode mode,ExceptionInfo *exception)
3184 %
3185 % A description of each parameter follows:
3186 %
3187 % o image_info: the image info.
3188 %
3189 % o image: the image.
3190 %
3191 % o mode: the mode for opening the file.
3192 %
3193 */
3194 
3195 static inline MagickBooleanType SetStreamBuffering(const ImageInfo *image_info,
3196  Image *image)
3197 {
3198  const char
3199  *option;
3200 
3201  int
3202  status;
3203 
3204  size_t
3205  size;
3206 
3207  size=MagickMinBufferExtent;
3208  option=GetImageOption(image_info,"stream:buffer-size");
3209  if (option != (const char *) NULL)
3210  size=StringToUnsignedLong(option);
3211  status=setvbuf(image->blob->file_info.file,(char *) NULL,size == 0 ?
3212  _IONBF : _IOFBF,size);
3213  return(status == 0 ? MagickTrue : MagickFalse);
3214 }
3215 
3217  Image *image,const BlobMode mode,ExceptionInfo *exception)
3218 {
3219  BlobInfo
3220  *magick_restrict blob_info;
3221 
3222  char
3223  extension[MagickPathExtent],
3224  filename[MagickPathExtent];
3225 
3226  const char
3227  *type;
3228 
3230  status;
3231 
3232  PolicyRights
3233  rights;
3234 
3235  assert(image_info != (ImageInfo *) NULL);
3236  assert(image_info->signature == MagickCoreSignature);
3237  if (image_info->debug != MagickFalse)
3239  image_info->filename);
3240  assert(image != (Image *) NULL);
3241  assert(image->signature == MagickCoreSignature);
3242  blob_info=image->blob;
3243  if (image_info->blob != (void *) NULL)
3244  {
3245  if (image_info->stream != (StreamHandler) NULL)
3246  blob_info->stream=(StreamHandler) image_info->stream;
3247  AttachBlob(blob_info,image_info->blob,image_info->length);
3248  return(MagickTrue);
3249  }
3250  if ((image_info->custom_stream != (CustomStreamInfo *) NULL) &&
3251  (*image->filename == '\0'))
3252  {
3253  blob_info->type=CustomStream;
3254  blob_info->custom_stream=image_info->custom_stream;
3255  return(MagickTrue);
3256  }
3257  (void) DetachBlob(blob_info);
3258  blob_info->mode=mode;
3259  switch (mode)
3260  {
3261  default: type="r"; break;
3262  case ReadBlobMode: type="r"; break;
3263  case ReadBinaryBlobMode: type="rb"; break;
3264  case WriteBlobMode: type="w"; break;
3265  case WriteBinaryBlobMode: type="w+b"; break;
3266  case AppendBlobMode: type="a"; break;
3267  case AppendBinaryBlobMode: type="a+b"; break;
3268  }
3269  if (*type != 'r')
3270  blob_info->synchronize=image_info->synchronize;
3271  if (image_info->stream != (StreamHandler) NULL)
3272  {
3273  blob_info->stream=image_info->stream;
3274  if (*type == 'w')
3275  {
3276  blob_info->type=FifoStream;
3277  return(MagickTrue);
3278  }
3279  }
3280  /*
3281  Open image file.
3282  */
3283  *filename='\0';
3284  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
3285  rights=ReadPolicyRights;
3286  if (*type == 'w')
3287  rights=WritePolicyRights;
3288  if (IsRightsAuthorized(PathPolicyDomain,rights,filename) == MagickFalse)
3289  {
3290  errno=EPERM;
3292  "NotAuthorized","`%s'",filename);
3293  return(MagickFalse);
3294  }
3295  if ((LocaleCompare(filename,"-") == 0) ||
3296  ((*filename == '\0') && (image_info->file == (FILE *) NULL)))
3297  {
3298  blob_info->file_info.file=(*type == 'r') ? stdin : stdout;
3299 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
3300  if (strchr(type,'b') != (char *) NULL)
3301  setmode(fileno(blob_info->file_info.file),_O_BINARY);
3302 #endif
3303  blob_info->type=StandardStream;
3304  blob_info->exempt=MagickTrue;
3305  return(SetStreamBuffering(image_info,image));
3306  }
3307  if ((LocaleNCompare(filename,"fd:",3) == 0) &&
3308  (IsGeometry(filename+3) != MagickFalse))
3309  {
3310  char
3311  fileMode[MagickPathExtent];
3312 
3313  *fileMode =(*type);
3314  fileMode[1]='\0';
3315  blob_info->file_info.file=fdopen(StringToLong(filename+3),fileMode);
3316  if (blob_info->file_info.file == (FILE *) NULL)
3317  {
3318  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3319  return(MagickFalse);
3320  }
3321 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__)
3322  if (strchr(type,'b') != (char *) NULL)
3323  setmode(fileno(blob_info->file_info.file),_O_BINARY);
3324 #endif
3325  blob_info->type=FileStream;
3326  blob_info->exempt=MagickTrue;
3327  return(SetStreamBuffering(image_info,image));
3328  }
3329 #if defined(MAGICKCORE_HAVE_POPEN) && defined(MAGICKCORE_PIPES_SUPPORT)
3330  if (*filename == '|')
3331  {
3332  char
3333  fileMode[MagickPathExtent],
3334  *sanitize_command;
3335 
3336  /*
3337  Pipe image to or from a system command.
3338  */
3339 #if defined(SIGPIPE)
3340  if (*type == 'w')
3341  (void) signal(SIGPIPE,SIG_IGN);
3342 #endif
3343  *fileMode =(*type);
3344  fileMode[1]='\0';
3345  sanitize_command=SanitizeString(filename+1);
3346  blob_info->file_info.file=(FILE *) popen_utf8(sanitize_command,fileMode);
3347  sanitize_command=DestroyString(sanitize_command);
3348  if (blob_info->file_info.file == (FILE *) NULL)
3349  {
3350  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3351  return(MagickFalse);
3352  }
3353  blob_info->type=PipeStream;
3354  blob_info->exempt=MagickTrue;
3355  return(SetStreamBuffering(image_info,image));
3356  }
3357 #endif
3358  status=GetPathAttributes(filename,&blob_info->properties);
3359 #if defined(S_ISFIFO)
3360  if ((status != MagickFalse) && S_ISFIFO(blob_info->properties.st_mode))
3361  {
3362  blob_info->file_info.file=(FILE *) fopen_utf8(filename,type);
3363  if (blob_info->file_info.file == (FILE *) NULL)
3364  {
3365  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3366  return(MagickFalse);
3367  }
3368  blob_info->type=FileStream;
3369  blob_info->exempt=MagickTrue;
3370  return(SetStreamBuffering(image_info,image));
3371  }
3372 #endif
3373  GetPathComponent(image->filename,ExtensionPath,extension);
3374  if (*type == 'w')
3375  {
3376  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
3377  if ((image_info->adjoin == MagickFalse) ||
3378  (strchr(filename,'%') != (char *) NULL))
3379  {
3380  /*
3381  Form filename for multi-part images.
3382  */
3383  (void) InterpretImageFilename(image_info,image,image->filename,(int)
3384  image->scene,filename,exception);
3385  if ((LocaleCompare(filename,image->filename) == 0) &&
3386  ((GetPreviousImageInList(image) != (Image *) NULL) ||
3387  (GetNextImageInList(image) != (Image *) NULL)))
3388  {
3389  char
3390  path[MagickPathExtent];
3391 
3392  GetPathComponent(image->filename,RootPath,path);
3393  if (*extension == '\0')
3394  (void) FormatLocaleString(filename,MagickPathExtent,"%s-%.20g",
3395  path,(double) image->scene);
3396  else
3397  (void) FormatLocaleString(filename,MagickPathExtent,
3398  "%s-%.20g.%s",path,(double) image->scene,extension);
3399  }
3400  (void) CopyMagickString(image->filename,filename,MagickPathExtent);
3401 #if defined(macintosh)
3402  SetApplicationType(filename,image_info->magick,'8BIM');
3403 #endif
3404  }
3405  }
3406  if (image_info->file != (FILE *) NULL)
3407  {
3408  blob_info->file_info.file=image_info->file;
3409  blob_info->type=FileStream;
3410  blob_info->exempt=MagickTrue;
3411  }
3412  else
3413  if (*type == 'r')
3414  {
3415  blob_info->file_info.file=(FILE *) fopen_utf8(filename,type);
3416  if (blob_info->file_info.file != (FILE *) NULL)
3417  {
3418  size_t
3419  count;
3420 
3421  unsigned char
3422  magick[3];
3423 
3424  blob_info->type=FileStream;
3425  (void) SetStreamBuffering(image_info,image);
3426  (void) memset(magick,0,sizeof(magick));
3427  count=fread(magick,1,sizeof(magick),blob_info->file_info.file);
3428  (void) fseek(blob_info->file_info.file,-((off_t) count),SEEK_CUR);
3429 #if defined(MAGICKCORE_POSIX_SUPPORT)
3430  (void) fflush(blob_info->file_info.file);
3431 #endif
3433  " read %.20g magic header bytes",(double) count);
3434 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3435  if (((int) magick[0] == 0x1F) && ((int) magick[1] == 0x8B) &&
3436  ((int) magick[2] == 0x08))
3437  {
3438  if (blob_info->file_info.file != (FILE *) NULL)
3439  (void) fclose(blob_info->file_info.file);
3440  blob_info->file_info.file=(FILE *) NULL;
3441  blob_info->file_info.gzfile=gzopen(filename,"rb");
3442  if (blob_info->file_info.gzfile != (gzFile) NULL)
3443  blob_info->type=ZipStream;
3444  }
3445 #endif
3446 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3447  if (strncmp((char *) magick,"BZh",3) == 0)
3448  {
3449  if (blob_info->file_info.file != (FILE *) NULL)
3450  (void) fclose(blob_info->file_info.file);
3451  blob_info->file_info.file=(FILE *) NULL;
3452  blob_info->file_info.bzfile=BZ2_bzopen(filename,"r");
3453  if (blob_info->file_info.bzfile != (BZFILE *) NULL)
3454  blob_info->type=BZipStream;
3455  }
3456 #endif
3457  if (blob_info->type == FileStream)
3458  {
3459  const MagickInfo
3460  *magick_info;
3461 
3463  *sans_exception;
3464 
3465  size_t
3466  length;
3467 
3468  sans_exception=AcquireExceptionInfo();
3469  magick_info=GetMagickInfo(image_info->magick,sans_exception);
3470  sans_exception=DestroyExceptionInfo(sans_exception);
3471  length=(size_t) blob_info->properties.st_size;
3472  if ((magick_info != (const MagickInfo *) NULL) &&
3473  (GetMagickBlobSupport(magick_info) != MagickFalse) &&
3474  (length > MagickMaxBufferExtent) &&
3476  {
3477  void
3478  *blob;
3479 
3480  blob=MapBlob(fileno(blob_info->file_info.file),ReadMode,0,
3481  length);
3482  if (blob == (void *) NULL)
3484  else
3485  {
3486  /*
3487  Format supports blobs-- use memory-mapped I/O.
3488  */
3489  if (image_info->file != (FILE *) NULL)
3490  blob_info->exempt=MagickFalse;
3491  else
3492  {
3493  (void) fclose(blob_info->file_info.file);
3494  blob_info->file_info.file=(FILE *) NULL;
3495  }
3496  AttachBlob(blob_info,blob,length);
3497  blob_info->mapped=MagickTrue;
3498  }
3499  }
3500  }
3501  }
3502  }
3503  else
3504 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3505  if ((LocaleCompare(extension,"Z") == 0) ||
3506  (LocaleCompare(extension,"gz") == 0) ||
3507  (LocaleCompare(extension,"wmz") == 0) ||
3508  (LocaleCompare(extension,"svgz") == 0))
3509  {
3510  blob_info->file_info.gzfile=gzopen(filename,"wb");
3511  if (blob_info->file_info.gzfile != (gzFile) NULL)
3512  blob_info->type=ZipStream;
3513  }
3514  else
3515 #endif
3516 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3517  if (LocaleCompare(extension,"bz2") == 0)
3518  {
3519  blob_info->file_info.bzfile=BZ2_bzopen(filename,"w");
3520  if (blob_info->file_info.bzfile != (BZFILE *) NULL)
3521  blob_info->type=BZipStream;
3522  }
3523  else
3524 #endif
3525  {
3526  blob_info->file_info.file=(FILE *) fopen_utf8(filename,type);
3527  if (blob_info->file_info.file != (FILE *) NULL)
3528  {
3529  blob_info->type=FileStream;
3530  (void) SetStreamBuffering(image_info,image);
3531  }
3532  }
3533  blob_info->status=MagickFalse;
3534  blob_info->error_number=MagickFalse;
3535  if (blob_info->type != UndefinedStream)
3536  blob_info->size=GetBlobSize(image);
3537  else
3538  {
3539  ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
3540  return(MagickFalse);
3541  }
3542  return(MagickTrue);
3543 }
3544 
3545 /*
3546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3547 % %
3548 % %
3549 % %
3550 + P i n g B l o b %
3551 % %
3552 % %
3553 % %
3554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3555 %
3556 % PingBlob() returns all the attributes of an image or image sequence except
3557 % for the pixels. It is much faster and consumes far less memory than
3558 % BlobToImage(). On failure, a NULL image is returned and exception
3559 % describes the reason for the failure.
3560 %
3561 % The format of the PingBlob method is:
3562 %
3563 % Image *PingBlob(const ImageInfo *image_info,const void *blob,
3564 % const size_t length,ExceptionInfo *exception)
3565 %
3566 % A description of each parameter follows:
3567 %
3568 % o image_info: the image info.
3569 %
3570 % o blob: the address of a character stream in one of the image formats
3571 % understood by ImageMagick.
3572 %
3573 % o length: This size_t integer reflects the length in bytes of the blob.
3574 %
3575 % o exception: return any errors or warnings in this structure.
3576 %
3577 */
3578 
3579 #if defined(__cplusplus) || defined(c_plusplus)
3580 extern "C" {
3581 #endif
3582 
3583 static size_t PingStream(const Image *magick_unused(image),
3584  const void *magick_unused(pixels),const size_t columns)
3585 {
3586  magick_unreferenced(image);
3587  magick_unreferenced(pixels);
3588  return(columns);
3589 }
3590 
3591 #if defined(__cplusplus) || defined(c_plusplus)
3592 }
3593 #endif
3594 
3595 MagickExport Image *PingBlob(const ImageInfo *image_info,const void *blob,
3596  const size_t length,ExceptionInfo *exception)
3597 {
3598  const MagickInfo
3599  *magick_info;
3600 
3601  Image
3602  *image;
3603 
3604  ImageInfo
3605  *clone_info,
3606  *ping_info;
3607 
3609  status;
3610 
3611  assert(image_info != (ImageInfo *) NULL);
3612  assert(image_info->signature == MagickCoreSignature);
3613  if (image_info->debug != MagickFalse)
3615  image_info->filename);
3616  assert(exception != (ExceptionInfo *) NULL);
3617  if ((blob == (const void *) NULL) || (length == 0))
3618  {
3619  (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
3620  "ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
3621  return((Image *) NULL);
3622  }
3623  ping_info=CloneImageInfo(image_info);
3624  ping_info->blob=(void *) blob;
3625  ping_info->length=length;
3626  ping_info->ping=MagickTrue;
3627  if (*ping_info->magick == '\0')
3628  (void) SetImageInfo(ping_info,0,exception);
3629  magick_info=GetMagickInfo(ping_info->magick,exception);
3630  if (magick_info == (const MagickInfo *) NULL)
3631  {
3632  (void) ThrowMagickException(exception,GetMagickModule(),
3633  MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
3634  ping_info->magick);
3635  ping_info=DestroyImageInfo(ping_info);
3636  return((Image *) NULL);
3637  }
3638  if (GetMagickBlobSupport(magick_info) != MagickFalse)
3639  {
3640  char
3641  filename[MagickPathExtent];
3642 
3643  /*
3644  Native blob support for this image format.
3645  */
3646  (void) CopyMagickString(filename,ping_info->filename,MagickPathExtent);
3647  (void) FormatLocaleString(ping_info->filename,MagickPathExtent,"%s:%s",
3648  ping_info->magick,filename);
3649  image=ReadStream(ping_info,&PingStream,exception);
3650  if (image != (Image *) NULL)
3651  (void) DetachBlob(image->blob);
3652  ping_info=DestroyImageInfo(ping_info);
3653  return(image);
3654  }
3655  /*
3656  Write blob to a temporary file on disk.
3657  */
3658  ping_info->blob=(void *) NULL;
3659  ping_info->length=0;
3660  *ping_info->filename='\0';
3661  status=BlobToFile(ping_info->filename,blob,length,exception);
3662  if (status == MagickFalse)
3663  {
3664  (void) RelinquishUniqueFileResource(ping_info->filename);
3665  ping_info=DestroyImageInfo(ping_info);
3666  return((Image *) NULL);
3667  }
3668  clone_info=CloneImageInfo(ping_info);
3669  (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:%s",
3670  ping_info->magick,ping_info->filename);
3671  image=ReadStream(clone_info,&PingStream,exception);
3672  if (image != (Image *) NULL)
3673  {
3674  Image
3675  *images;
3676 
3677  /*
3678  Restore original filenames and image format.
3679  */
3680  for (images=GetFirstImageInList(image); images != (Image *) NULL; )
3681  {
3682  (void) CopyMagickString(images->filename,image_info->filename,
3684  (void) CopyMagickString(images->magick_filename,image_info->filename,
3686  (void) CopyMagickString(images->magick,magick_info->name,
3688  images=GetNextImageInList(images);
3689  }
3690  }
3691  clone_info=DestroyImageInfo(clone_info);
3692  (void) RelinquishUniqueFileResource(ping_info->filename);
3693  ping_info=DestroyImageInfo(ping_info);
3694  return(image);
3695 }
3696 
3697 /*
3698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3699 % %
3700 % %
3701 % %
3702 + R e a d B l o b %
3703 % %
3704 % %
3705 % %
3706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3707 %
3708 % ReadBlob() reads data from the blob or image file and returns it. It
3709 % returns the number of bytes read. If length is zero, ReadBlob() returns
3710 % zero and has no other results. If length is greater than SSIZE_MAX, the
3711 % result is unspecified.
3712 %
3713 % The format of the ReadBlob method is:
3714 %
3715 % ssize_t ReadBlob(Image *image,const size_t length,void *data)
3716 %
3717 % A description of each parameter follows:
3718 %
3719 % o image: the image.
3720 %
3721 % o length: Specifies an integer representing the number of bytes to read
3722 % from the file.
3723 %
3724 % o data: Specifies an area to place the information requested from the
3725 % file.
3726 %
3727 */
3728 MagickExport ssize_t ReadBlob(Image *image,const size_t length,void *data)
3729 {
3730  BlobInfo
3731  *magick_restrict blob_info;
3732 
3733  int
3734  c;
3735 
3736  register unsigned char
3737  *q;
3738 
3739  ssize_t
3740  count;
3741 
3742  assert(image != (Image *) NULL);
3743  assert(image->signature == MagickCoreSignature);
3744  assert(image->blob != (BlobInfo *) NULL);
3745  assert(image->blob->type != UndefinedStream);
3746  if (length == 0)
3747  return(0);
3748  assert(data != (void *) NULL);
3749  blob_info=image->blob;
3750  count=0;
3751  q=(unsigned char *) data;
3752  switch (blob_info->type)
3753  {
3754  case UndefinedStream:
3755  break;
3756  case StandardStream:
3757  case FileStream:
3758  case PipeStream:
3759  {
3760  switch (length)
3761  {
3762  default:
3763  {
3764  count=(ssize_t) fread(q,1,length,blob_info->file_info.file);
3765  break;
3766  }
3767  case 4:
3768  {
3769  c=getc(blob_info->file_info.file);
3770  if (c == EOF)
3771  break;
3772  *q++=(unsigned char) c;
3773  count++;
3774  }
3775  case 3:
3776  {
3777  c=getc(blob_info->file_info.file);
3778  if (c == EOF)
3779  break;
3780  *q++=(unsigned char) c;
3781  count++;
3782  }
3783  case 2:
3784  {
3785  c=getc(blob_info->file_info.file);
3786  if (c == EOF)
3787  break;
3788  *q++=(unsigned char) c;
3789  count++;
3790  }
3791  case 1:
3792  {
3793  c=getc(blob_info->file_info.file);
3794  if (c == EOF)
3795  break;
3796  *q++=(unsigned char) c;
3797  count++;
3798  }
3799  case 0:
3800  break;
3801  }
3802  if ((count != (ssize_t) length) &&
3803  (ferror(blob_info->file_info.file) != 0))
3804  ThrowBlobException(blob_info);
3805  break;
3806  }
3807  case ZipStream:
3808  {
3809 #if defined(MAGICKCORE_ZLIB_DELEGATE)
3810  int
3811  status;
3812 
3813  switch (length)
3814  {
3815  default:
3816  {
3817  register ssize_t
3818  i;
3819 
3820  for (i=0; i < (ssize_t) length; i+=count)
3821  {
3822  count=(ssize_t) gzread(blob_info->file_info.gzfile,q+i,
3823  (unsigned int) MagickMin(length-i,MagickMaxBufferExtent));
3824  if (count <= 0)
3825  {
3826  count=0;
3827  if (errno != EINTR)
3828  break;
3829  }
3830  }
3831  count=i;
3832  break;
3833  }
3834  case 4:
3835  {
3836  c=gzgetc(blob_info->file_info.gzfile);
3837  if (c == EOF)
3838  break;
3839  *q++=(unsigned char) c;
3840  count++;
3841  }
3842  case 3:
3843  {
3844  c=gzgetc(blob_info->file_info.gzfile);
3845  if (c == EOF)
3846  break;
3847  *q++=(unsigned char) c;
3848  count++;
3849  }
3850  case 2:
3851  {
3852  c=gzgetc(blob_info->file_info.gzfile);
3853  if (c == EOF)
3854  break;
3855  *q++=(unsigned char) c;
3856  count++;
3857  }
3858  case 1:
3859  {
3860  c=gzgetc(blob_info->file_info.gzfile);
3861  if (c == EOF)
3862  break;
3863  *q++=(unsigned char) c;
3864  count++;
3865  }
3866  case 0:
3867  break;
3868  }
3869  status=Z_OK;
3870  (void) gzerror(blob_info->file_info.gzfile,&status);
3871  if ((count != (ssize_t) length) && (status != Z_OK))
3872  ThrowBlobException(blob_info);
3873  if (blob_info->eof == MagickFalse)
3874  blob_info->eof=gzeof(blob_info->file_info.gzfile);
3875 #endif
3876  break;
3877  }
3878  case BZipStream:
3879  {
3880 #if defined(MAGICKCORE_BZLIB_DELEGATE)
3881  int
3882  status;
3883 
3884  register ssize_t
3885  i;
3886 
3887  for (i=0; i < (ssize_t) length; i+=count)
3888  {
3889  count=(ssize_t) BZ2_bzread(blob_info->file_info.bzfile,q+i,
3890  (unsigned int) MagickMin(length-i,MagickMaxBufferExtent));
3891  if (count <= 0)
3892  {
3893  count=0;
3894  if (errno != EINTR)
3895  break;
3896  }
3897  }
3898  count=i;
3899  status=BZ_OK;
3900  (void) BZ2_bzerror(blob_info->file_info.bzfile,&status);
3901  if ((count != (ssize_t) length) && (status != BZ_OK))
3902  ThrowBlobException(blob_info);
3903 #endif
3904  break;
3905  }
3906  case FifoStream:
3907  break;
3908  case BlobStream:
3909  {
3910  register const unsigned char
3911  *p;
3912 
3913  if (blob_info->offset >= (MagickOffsetType) blob_info->length)
3914  {
3915  blob_info->eof=MagickTrue;
3916  break;
3917  }
3918  p=blob_info->data+blob_info->offset;
3919  count=(ssize_t) MagickMin((MagickOffsetType) length,(MagickOffsetType)
3920  blob_info->length-blob_info->offset);
3921  blob_info->offset+=count;
3922  if (count != (ssize_t) length)
3923  blob_info->eof=MagickTrue;
3924  (void) memcpy(q,p,(size_t) count);
3925  break;
3926  }
3927  case CustomStream:
3928  {
3929  if (blob_info->custom_stream->reader != (CustomStreamHandler) NULL)
3930  count=blob_info->custom_stream->reader(q,length,
3931  blob_info->custom_stream->data);
3932  break;
3933  }
3934  }
3935  return(count);
3936 }
3937 
3938 /*
3939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3940 % %
3941 % %
3942 % %
3943 + R e a d B l o b B y t e %
3944 % %
3945 % %
3946 % %
3947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3948 %
3949 % ReadBlobByte() reads a single byte from the image file and returns it.
3950 %
3951 % The format of the ReadBlobByte method is:
3952 %
3953 % int ReadBlobByte(Image *image)
3954 %
3955 % A description of each parameter follows.
3956 %
3957 % o image: the image.
3958 %
3959 */
3961 {
3962  BlobInfo
3963  *magick_restrict blob_info;
3964 
3965  register const unsigned char
3966  *p;
3967 
3968  unsigned char
3969  buffer[1];
3970 
3971  assert(image != (Image *) NULL);
3972  assert(image->signature == MagickCoreSignature);
3973  assert(image->blob != (BlobInfo *) NULL);
3974  assert(image->blob->type != UndefinedStream);
3975  blob_info=image->blob;
3976  switch (blob_info->type)
3977  {
3978  case StandardStream:
3979  case FileStream:
3980  case PipeStream:
3981  {
3982  int
3983  c;
3984 
3985  p=(const unsigned char *) buffer;
3986  c=getc(blob_info->file_info.file);
3987  if (c == EOF)
3988  return(EOF);
3989  *buffer=(unsigned char) c;
3990  break;
3991  }
3992  default:
3993  {
3994  ssize_t
3995  count;
3996 
3997  p=(const unsigned char *) ReadBlobStream(image,1,buffer,&count);
3998  if (count != 1)
3999  return(EOF);
4000  break;
4001  }
4002  }
4003  return((int) (*p));
4004 }
4005 
4006 /*
4007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4008 % %
4009 % %
4010 % %
4011 + R e a d B l o b D o u b l e %
4012 % %
4013 % %
4014 % %
4015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4016 %
4017 % ReadBlobDouble() reads a double value as a 64-bit quantity in the byte-order
4018 % specified by the endian member of the image structure.
4019 %
4020 % The format of the ReadBlobDouble method is:
4021 %
4022 % double ReadBlobDouble(Image *image)
4023 %
4024 % A description of each parameter follows.
4025 %
4026 % o image: the image.
4027 %
4028 */
4030 {
4031  union
4032  {
4034  unsigned_value;
4035 
4036  double
4037  double_value;
4038  } quantum;
4039 
4040  quantum.double_value=0.0;
4041  quantum.unsigned_value=ReadBlobLongLong(image);
4042  return(quantum.double_value);
4043 }
4044 
4045 /*
4046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4047 % %
4048 % %
4049 % %
4050 + R e a d B l o b F l o a t %
4051 % %
4052 % %
4053 % %
4054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4055 %
4056 % ReadBlobFloat() reads a float value as a 32-bit quantity in the byte-order
4057 % specified by the endian member of the image structure.
4058 %
4059 % The format of the ReadBlobFloat method is:
4060 %
4061 % float ReadBlobFloat(Image *image)
4062 %
4063 % A description of each parameter follows.
4064 %
4065 % o image: the image.
4066 %
4067 */
4069 {
4070  union
4071  {
4072  unsigned int
4073  unsigned_value;
4074 
4075  float
4076  float_value;
4077  } quantum;
4078 
4079  quantum.float_value=0.0;
4080  quantum.unsigned_value=ReadBlobLong(image);
4081  return(quantum.float_value);
4082 }
4083 
4084 /*
4085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4086 % %
4087 % %
4088 % %
4089 + R e a d B l o b L o n g %
4090 % %
4091 % %
4092 % %
4093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4094 %
4095 % ReadBlobLong() reads a unsigned int value as a 32-bit quantity in the
4096 % byte-order specified by the endian member of the image structure.
4097 %
4098 % The format of the ReadBlobLong method is:
4099 %
4100 % unsigned int ReadBlobLong(Image *image)
4101 %
4102 % A description of each parameter follows.
4103 %
4104 % o image: the image.
4105 %
4106 */
4107 MagickExport unsigned int ReadBlobLong(Image *image)
4108 {
4109  register const unsigned char
4110  *p;
4111 
4112  ssize_t
4113  count;
4114 
4115  unsigned char
4116  buffer[4];
4117 
4118  unsigned int
4119  value;
4120 
4121  assert(image != (Image *) NULL);
4122  assert(image->signature == MagickCoreSignature);
4123  *buffer='\0';
4124  p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
4125  if (count != 4)
4126  return(0UL);
4127  if (image->endian == LSBEndian)
4128  {
4129  value=(unsigned int) (*p++);
4130  value|=(unsigned int) (*p++) << 8;
4131  value|=(unsigned int) (*p++) << 16;
4132  value|=(unsigned int) (*p++) << 24;
4133  return(value);
4134  }
4135  value=(unsigned int) (*p++) << 24;
4136  value|=(unsigned int) (*p++) << 16;
4137  value|=(unsigned int) (*p++) << 8;
4138  value|=(unsigned int) (*p++);
4139  return(value);
4140 }
4141 
4142 /*
4143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4144 % %
4145 % %
4146 % %
4147 + R e a d B l o b L o n g L o n g %
4148 % %
4149 % %
4150 % %
4151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4152 %
4153 % ReadBlobLongLong() reads a long long value as a 64-bit quantity in the
4154 % byte-order specified by the endian member of the image structure.
4155 %
4156 % The format of the ReadBlobLongLong method is:
4157 %
4158 % MagickSizeType ReadBlobLongLong(Image *image)
4159 %
4160 % A description of each parameter follows.
4161 %
4162 % o image: the image.
4163 %
4164 */
4166 {
4168  value;
4169 
4170  register const unsigned char
4171  *p;
4172 
4173  ssize_t
4174  count;
4175 
4176  unsigned char
4177  buffer[8];
4178 
4179  assert(image != (Image *) NULL);
4180  assert(image->signature == MagickCoreSignature);
4181  *buffer='\0';
4182  p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
4183  if (count != 8)
4184  return(MagickULLConstant(0));
4185  if (image->endian == LSBEndian)
4186  {
4187  value=(MagickSizeType) (*p++);
4188  value|=(MagickSizeType) (*p++) << 8;
4189  value|=(MagickSizeType) (*p++) << 16;
4190  value|=(MagickSizeType) (*p++) << 24;
4191  value|=(MagickSizeType) (*p++) << 32;
4192  value|=(MagickSizeType) (*p++) << 40;
4193  value|=(MagickSizeType) (*p++) << 48;
4194  value|=(MagickSizeType) (*p++) << 56;
4195  return(value);
4196  }
4197  value=(MagickSizeType) (*p++) << 56;
4198  value|=(MagickSizeType) (*p++) << 48;
4199  value|=(MagickSizeType) (*p++) << 40;
4200  value|=(MagickSizeType) (*p++) << 32;
4201  value|=(MagickSizeType) (*p++) << 24;
4202  value|=(MagickSizeType) (*p++) << 16;
4203  value|=(MagickSizeType) (*p++) << 8;
4204  value|=(MagickSizeType) (*p++);
4205  return(value);
4206 }
4207 
4208 /*
4209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4210 % %
4211 % %
4212 % %
4213 + R e a d B l o b S h o r t %
4214 % %
4215 % %
4216 % %
4217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4218 %
4219 % ReadBlobShort() reads a short value as a 16-bit quantity in the byte-order
4220 % specified by the endian member of the image structure.
4221 %
4222 % The format of the ReadBlobShort method is:
4223 %
4224 % unsigned short ReadBlobShort(Image *image)
4225 %
4226 % A description of each parameter follows.
4227 %
4228 % o image: the image.
4229 %
4230 */
4231 MagickExport unsigned short ReadBlobShort(Image *image)
4232 {
4233  register const unsigned char
4234  *p;
4235 
4236  register unsigned short
4237  value;
4238 
4239  ssize_t
4240  count;
4241 
4242  unsigned char
4243  buffer[2];
4244 
4245  assert(image != (Image *) NULL);
4246  assert(image->signature == MagickCoreSignature);
4247  *buffer='\0';
4248  p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
4249  if (count != 2)
4250  return((unsigned short) 0U);
4251  if (image->endian == LSBEndian)
4252  {
4253  value=(unsigned short) (*p++);
4254  value|=(unsigned short) (*p++) << 8;
4255  return(value);
4256  }
4257  value=(unsigned short) ((unsigned short) (*p++) << 8);
4258  value|=(unsigned short) (*p++);
4259  return(value);
4260 }
4261 
4262 /*
4263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4264 % %
4265 % %
4266 % %
4267 + R e a d B l o b L S B L o n g %
4268 % %
4269 % %
4270 % %
4271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4272 %
4273 % ReadBlobLSBLong() reads a unsigned int value as a 32-bit quantity in
4274 % least-significant byte first order.
4275 %
4276 % The format of the ReadBlobLSBLong method is:
4277 %
4278 % unsigned int ReadBlobLSBLong(Image *image)
4279 %
4280 % A description of each parameter follows.
4281 %
4282 % o image: the image.
4283 %
4284 */
4285 MagickExport unsigned int ReadBlobLSBLong(Image *image)
4286 {
4287  register const unsigned char
4288  *p;
4289 
4290  register unsigned int
4291  value;
4292 
4293  ssize_t
4294  count;
4295 
4296  unsigned char
4297  buffer[4];
4298 
4299  assert(image != (Image *) NULL);
4300  assert(image->signature == MagickCoreSignature);
4301  *buffer='\0';
4302  p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
4303  if (count != 4)
4304  return(0U);
4305  value=(unsigned int) (*p++);
4306  value|=(unsigned int) (*p++) << 8;
4307  value|=(unsigned int) (*p++) << 16;
4308  value|=(unsigned int) (*p++) << 24;
4309  return(value);
4310 }
4311 
4312 /*
4313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4314 % %
4315 % %
4316 % %
4317 + R e a d B l o b L S B S i g n e d L o n g %
4318 % %
4319 % %
4320 % %
4321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4322 %
4323 % ReadBlobLSBSignedLong() reads a signed int value as a 32-bit quantity in
4324 % least-significant byte first order.
4325 %
4326 % The format of the ReadBlobLSBSignedLong method is:
4327 %
4328 % signed int ReadBlobLSBSignedLong(Image *image)
4329 %
4330 % A description of each parameter follows.
4331 %
4332 % o image: the image.
4333 %
4334 */
4336 {
4337  union
4338  {
4339  unsigned int
4340  unsigned_value;
4341 
4342  signed int
4343  signed_value;
4344  } quantum;
4345 
4346  quantum.unsigned_value=ReadBlobLSBLong(image);
4347  return(quantum.signed_value);
4348 }
4349 
4350 /*
4351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4352 % %
4353 % %
4354 % %
4355 + R e a d B l o b L S B S h o r t %
4356 % %
4357 % %
4358 % %
4359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4360 %
4361 % ReadBlobLSBShort() reads a short value as a 16-bit quantity in
4362 % least-significant byte first order.
4363 %
4364 % The format of the ReadBlobLSBShort method is:
4365 %
4366 % unsigned short ReadBlobLSBShort(Image *image)
4367 %
4368 % A description of each parameter follows.
4369 %
4370 % o image: the image.
4371 %
4372 */
4373 MagickExport unsigned short ReadBlobLSBShort(Image *image)
4374 {
4375  register const unsigned char
4376  *p;
4377 
4378  register unsigned short
4379  value;
4380 
4381  ssize_t
4382  count;
4383 
4384  unsigned char
4385  buffer[2];
4386 
4387  assert(image != (Image *) NULL);
4388  assert(image->signature == MagickCoreSignature);
4389  *buffer='\0';
4390  p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
4391  if (count != 2)
4392  return((unsigned short) 0U);
4393  value=(unsigned short) (*p++);
4394  value|=(unsigned short) (*p++) << 8;
4395  return(value);
4396 }
4397 
4398 /*
4399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4400 % %
4401 % %
4402 % %
4403 + R e a d B l o b L S B S i g n e d S h o r t %
4404 % %
4405 % %
4406 % %
4407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4408 %
4409 % ReadBlobLSBSignedShort() reads a signed short value as a 16-bit quantity in
4410 % least-significant byte-order.
4411 %
4412 % The format of the ReadBlobLSBSignedShort method is:
4413 %
4414 % signed short ReadBlobLSBSignedShort(Image *image)
4415 %
4416 % A description of each parameter follows.
4417 %
4418 % o image: the image.
4419 %
4420 */
4422 {
4423  union
4424  {
4425  unsigned short
4426  unsigned_value;
4427 
4428  signed short
4429  signed_value;
4430  } quantum;
4431 
4432  quantum.unsigned_value=ReadBlobLSBShort(image);
4433  return(quantum.signed_value);
4434 }
4435 
4436 /*
4437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4438 % %
4439 % %
4440 % %
4441 + R e a d B l o b M S B L o n g %
4442 % %
4443 % %
4444 % %
4445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4446 %
4447 % ReadBlobMSBLong() reads a unsigned int value as a 32-bit quantity in
4448 % most-significant byte first order.
4449 %
4450 % The format of the ReadBlobMSBLong method is:
4451 %
4452 % unsigned int ReadBlobMSBLong(Image *image)
4453 %
4454 % A description of each parameter follows.
4455 %
4456 % o image: the image.
4457 %
4458 */
4459 MagickExport unsigned int ReadBlobMSBLong(Image *image)
4460 {
4461  register const unsigned char
4462  *p;
4463 
4464  register unsigned int
4465  value;
4466 
4467  ssize_t
4468  count;
4469 
4470  unsigned char
4471  buffer[4];
4472 
4473  assert(image != (Image *) NULL);
4474  assert(image->signature == MagickCoreSignature);
4475  *buffer='\0';
4476  p=(const unsigned char *) ReadBlobStream(image,4,buffer,&count);
4477  if (count != 4)
4478  return(0UL);
4479  value=(unsigned int) (*p++) << 24;
4480  value|=(unsigned int) (*p++) << 16;
4481  value|=(unsigned int) (*p++) << 8;
4482  value|=(unsigned int) (*p++);
4483  return(value);
4484 }
4485 
4486 /*
4487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4488 % %
4489 % %
4490 % %
4491 + R e a d B l o b M S B L o n g L o n g %
4492 % %
4493 % %
4494 % %
4495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4496 %
4497 % ReadBlobMSBLongLong() reads a unsigned long long value as a 64-bit quantity
4498 % in most-significant byte first order.
4499 %
4500 % The format of the ReadBlobMSBLongLong method is:
4501 %
4502 % unsigned int ReadBlobMSBLongLong(Image *image)
4503 %
4504 % A description of each parameter follows.
4505 %
4506 % o image: the image.
4507 %
4508 */
4510 {
4511  register const unsigned char
4512  *p;
4513 
4514  register MagickSizeType
4515  value;
4516 
4517  ssize_t
4518  count;
4519 
4520  unsigned char
4521  buffer[8];
4522 
4523  assert(image != (Image *) NULL);
4524  assert(image->signature == MagickCoreSignature);
4525  *buffer='\0';
4526  p=(const unsigned char *) ReadBlobStream(image,8,buffer,&count);
4527  if (count != 8)
4528  return(MagickULLConstant(0));
4529  value=(MagickSizeType) (*p++) << 56;
4530  value|=(MagickSizeType) (*p++) << 48;
4531  value|=(MagickSizeType) (*p++) << 40;
4532  value|=(MagickSizeType) (*p++) << 32;
4533  value|=(MagickSizeType) (*p++) << 24;
4534  value|=(MagickSizeType) (*p++) << 16;
4535  value|=(MagickSizeType) (*p++) << 8;
4536  value|=(MagickSizeType) (*p++);
4537  return(value);
4538 }
4539 
4540 /*
4541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4542 % %
4543 % %
4544 % %
4545 + R e a d B l o b M S B S h o r t %
4546 % %
4547 % %
4548 % %
4549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4550 %
4551 % ReadBlobMSBShort() reads a short value as a 16-bit quantity in
4552 % most-significant byte first order.
4553 %
4554 % The format of the ReadBlobMSBShort method is:
4555 %
4556 % unsigned short ReadBlobMSBShort(Image *image)
4557 %
4558 % A description of each parameter follows.
4559 %
4560 % o image: the image.
4561 %
4562 */
4563 MagickExport unsigned short ReadBlobMSBShort(Image *image)
4564 {
4565  register const unsigned char
4566  *p;
4567 
4568  register unsigned short
4569  value;
4570 
4571  ssize_t
4572  count;
4573 
4574  unsigned char
4575  buffer[2];
4576 
4577  assert(image != (Image *) NULL);
4578  assert(image->signature == MagickCoreSignature);
4579  *buffer='\0';
4580  p=(const unsigned char *) ReadBlobStream(image,2,buffer,&count);
4581  if (count != 2)
4582  return((unsigned short) 0U);
4583  value=(unsigned short) ((*p++) << 8);
4584  value|=(unsigned short) (*p++);
4585  return((unsigned short) (value & 0xffff));
4586 }
4587 
4588 /*
4589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4590 % %
4591 % %
4592 % %
4593 + R e a d B l o b M S B S i g n e d L o n g %
4594 % %
4595 % %
4596 % %
4597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4598 %
4599 % ReadBlobMSBSignedLong() reads a signed int value as a 32-bit quantity in
4600 % most-significant byte-order.
4601 %
4602 % The format of the ReadBlobMSBSignedLong method is:
4603 %
4604 % signed int ReadBlobMSBSignedLong(Image *image)
4605 %
4606 % A description of each parameter follows.
4607 %
4608 % o image: the image.
4609 %
4610 */
4612 {
4613  union
4614  {
4615  unsigned int
4616  unsigned_value;
4617 
4618  signed int
4619  signed_value;
4620  } quantum;
4621 
4622  quantum.unsigned_value=ReadBlobMSBLong(image);
4623  return(quantum.signed_value);
4624 }
4625 
4626 /*
4627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4628 % %
4629 % %
4630 % %
4631 + R e a d B l o b M S B S i g n e d S h o r t %
4632 % %
4633 % %
4634 % %
4635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4636 %
4637 % ReadBlobMSBSignedShort() reads a signed short value as a 16-bit quantity in
4638 % most-significant byte-order.
4639 %
4640 % The format of the ReadBlobMSBSignedShort method is:
4641 %
4642 % signed short ReadBlobMSBSignedShort(Image *image)
4643 %
4644 % A description of each parameter follows.
4645 %
4646 % o image: the image.
4647 %
4648 */
4650 {
4651  union
4652  {
4653  unsigned short
4654  unsigned_value;
4655 
4656  signed short
4657  signed_value;
4658  } quantum;
4659 
4660  quantum.unsigned_value=ReadBlobMSBShort(image);
4661  return(quantum.signed_value);
4662 }
4663 
4664 /*
4665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4666 % %
4667 % %
4668 % %
4669 + R e a d B l o b S i g n e d L o n g %
4670 % %
4671 % %
4672 % %
4673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4674 %
4675 % ReadBlobSignedLong() reads a signed int value as a 32-bit quantity in the
4676 % byte-order specified by the endian member of the image structure.
4677 %
4678 % The format of the ReadBlobSignedLong method is:
4679 %
4680 % signed int ReadBlobSignedLong(Image *image)
4681 %
4682 % A description of each parameter follows.
4683 %
4684 % o image: the image.
4685 %
4686 */
4688 {
4689  union
4690  {
4691  unsigned int
4692  unsigned_value;
4693 
4694  signed int
4695  signed_value;
4696  } quantum;
4697 
4698  quantum.unsigned_value=ReadBlobLong(image);
4699  return(quantum.signed_value);
4700 }
4701 
4702 /*
4703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704 % %
4705 % %
4706 % %
4707 + R e a d B l o b S i g n e d S h o r t %
4708 % %
4709 % %
4710 % %
4711 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4712 %
4713 % ReadBlobSignedShort() reads a signed short value as a 16-bit quantity in the
4714 % byte-order specified by the endian member of the image structure.
4715 %
4716 % The format of the ReadBlobSignedShort method is:
4717 %
4718 % signed short ReadBlobSignedShort(Image *image)
4719 %
4720 % A description of each parameter follows.
4721 %
4722 % o image: the image.
4723 %
4724 */
4726 {
4727  union
4728  {
4729  unsigned short
4730  unsigned_value;
4731 
4732  signed short
4733  signed_value;
4734  } quantum;
4735 
4736  quantum.unsigned_value=ReadBlobShort(image);
4737  return(quantum.signed_value);
4738 }
4739 
4740 /*
4741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4742 % %
4743 % %
4744 % %
4745 + R e a d B l o b S t r e a m %
4746 % %
4747 % %
4748 % %
4749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4750 %
4751 % ReadBlobStream() reads data from the blob or image file and returns it. It
4752 % returns a pointer to the data buffer you supply or to the image memory
4753 % buffer if its supported (zero-copy). If length is zero, ReadBlobStream()
4754 % returns a count of zero and has no other results. If length is greater than
4755 % SSIZE_MAX, the result is unspecified.
4756 %
4757 % The format of the ReadBlobStream method is:
4758 %
4759 % const void *ReadBlobStream(Image *image,const size_t length,
4760 % void *magick_restrict data,ssize_t *count)
4761 %
4762 % A description of each parameter follows:
4763 %
4764 % o image: the image.
4765 %
4766 % o length: Specifies an integer representing the number of bytes to read
4767 % from the file.
4768 %
4769 % o count: returns the number of bytes read.
4770 %
4771 % o data: Specifies an area to place the information requested from the
4772 % file.
4773 %
4774 */
4776  const size_t length,void *magick_restrict data,ssize_t *count)
4777 {
4778  BlobInfo
4779  *magick_restrict blob_info;
4780 
4781  assert(image != (Image *) NULL);
4782  assert(image->signature == MagickCoreSignature);
4783  assert(image->blob != (BlobInfo *) NULL);
4784  assert(image->blob->type != UndefinedStream);
4785  assert(count != (ssize_t *) NULL);
4786  blob_info=image->blob;
4787  if (blob_info->type != BlobStream)
4788  {
4789  assert(data != NULL);
4790  *count=ReadBlob(image,length,(unsigned char *) data);
4791  return(data);
4792  }
4793  if (blob_info->offset >= (MagickOffsetType) blob_info->length)
4794  {
4795  *count=0;
4796  blob_info->eof=MagickTrue;
4797  return(data);
4798  }
4799  data=blob_info->data+blob_info->offset;
4800  *count=(ssize_t) MagickMin((MagickOffsetType) length,(MagickOffsetType)
4801  blob_info->length-blob_info->offset);
4802  blob_info->offset+=(*count);
4803  if (*count != (ssize_t) length)
4804  blob_info->eof=MagickTrue;
4805  return(data);
4806 }
4807 
4808 /*
4809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4810 % %
4811 % %
4812 % %
4813 + R e a d B l o b S t r i n g %
4814 % %
4815 % %
4816 % %
4817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4818 %
4819 % ReadBlobString() reads characters from a blob or file until a newline
4820 % character is read or an end-of-file condition is encountered.
4821 %
4822 % The format of the ReadBlobString method is:
4823 %
4824 % char *ReadBlobString(Image *image,char *string)
4825 %
4826 % A description of each parameter follows:
4827 %
4828 % o image: the image.
4829 %
4830 % o string: the address of a character buffer.
4831 %
4832 */
4833 MagickExport char *ReadBlobString(Image *image,char *string)
4834 {
4835  int
4836  c;
4837 
4838  register ssize_t
4839  i;
4840 
4841  assert(image != (Image *) NULL);
4842  assert(image->signature == MagickCoreSignature);
4843  for (i=0; i < (MagickPathExtent-1L); i++)
4844  {
4845  c=ReadBlobByte(image);
4846  if (c == EOF)
4847  {
4848  if (i == 0)
4849  return((char *) NULL);
4850  break;
4851  }
4852  string[i]=c;
4853  if (c == '\n')
4854  {
4855  if ((i > 0) && (string[i-1] == '\r'))
4856  i--;
4857  break;
4858  }
4859  }
4860  string[i]='\0';
4861  return(string);
4862 }
4863 
4864 /*
4865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866 % %
4867 % %
4868 % %
4869 + R e f e r e n c e B l o b %
4870 % %
4871 % %
4872 % %
4873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4874 %
4875 % ReferenceBlob() increments the reference count associated with the pixel
4876 % blob returning a pointer to the blob.
4877 %
4878 % The format of the ReferenceBlob method is:
4879 %
4880 % BlobInfo ReferenceBlob(BlobInfo *blob_info)
4881 %
4882 % A description of each parameter follows:
4883 %
4884 % o blob_info: the blob_info.
4885 %
4886 */
4888 {
4889  assert(blob != (BlobInfo *) NULL);
4890  assert(blob->signature == MagickCoreSignature);
4891  if (blob->debug != MagickFalse)
4892  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4894  blob->reference_count++;
4896  return(blob);
4897 }
4898 
4899 /*
4900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4901 % %
4902 % %
4903 % %
4904 + S e e k B l o b %
4905 % %
4906 % %
4907 % %
4908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4909 %
4910 % SeekBlob() sets the offset in bytes from the beginning of a blob or file
4911 % and returns the resulting offset.
4912 %
4913 % The format of the SeekBlob method is:
4914 %
4915 % MagickOffsetType SeekBlob(Image *image,const MagickOffsetType offset,
4916 % const int whence)
4917 %
4918 % A description of each parameter follows:
4919 %
4920 % o image: the image.
4921 %
4922 % o offset: Specifies an integer representing the offset in bytes.
4923 %
4924 % o whence: Specifies an integer representing how the offset is
4925 % treated relative to the beginning of the blob as follows:
4926 %
4927 % SEEK_SET Set position equal to offset bytes.
4928 % SEEK_CUR Set position to current location plus offset.
4929 % SEEK_END Set position to EOF plus offset.
4930 %
4931 */
4933  const MagickOffsetType offset,const int whence)
4934 {
4935  BlobInfo
4936  *magick_restrict blob_info;
4937 
4938  assert(image != (Image *) NULL);
4939  assert(image->signature == MagickCoreSignature);
4940  if (image->debug != MagickFalse)
4941  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4942  assert(image->blob != (BlobInfo *) NULL);
4943  assert(image->blob->type != UndefinedStream);
4944  blob_info=image->blob;
4945  switch (blob_info->type)
4946  {
4947  case UndefinedStream:
4948  break;
4949  case StandardStream:
4950  case PipeStream:
4951  return(-1);
4952  case FileStream:
4953  {
4954  if ((offset < 0) && (whence == SEEK_SET))
4955  return(-1);
4956  if (fseek(blob_info->file_info.file,offset,whence) < 0)
4957  return(-1);
4958  blob_info->offset=TellBlob(image);
4959  break;
4960  }
4961  case ZipStream:
4962  {
4963 #if defined(MAGICKCORE_ZLIB_DELEGATE)
4964  if (gzseek(blob_info->file_info.gzfile,offset,whence) < 0)
4965  return(-1);
4966 #endif
4967  blob_info->offset=TellBlob(image);
4968  break;
4969  }
4970  case BZipStream:
4971  return(-1);
4972  case FifoStream:
4973  return(-1);
4974  case BlobStream:
4975  {
4976  switch (whence)
4977  {
4978  case SEEK_SET:
4979  default:
4980  {
4981  if (offset < 0)
4982  return(-1);
4983  blob_info->offset=offset;
4984  break;
4985  }
4986  case SEEK_CUR:
4987  {
4988  if (((offset > 0) && (blob_info->offset > (SSIZE_MAX-offset))) ||
4989  ((offset < 0) && (blob_info->offset < (-SSIZE_MAX-offset))))
4990  {
4991  errno=EOVERFLOW;
4992  return(-1);
4993  }
4994  if ((blob_info->offset+offset) < 0)
4995  return(-1);
4996  blob_info->offset+=offset;
4997  break;
4998  }
4999  case SEEK_END:
5000  {
5001  if (((MagickOffsetType) blob_info->length+offset) < 0)
5002  return(-1);
5003  blob_info->offset=blob_info->length+offset;
5004  break;
5005  }
5006  }
5007  if (blob_info->offset < (MagickOffsetType) ((off_t) blob_info->length))
5008  {
5009  blob_info->eof=MagickFalse;
5010  break;
5011  }
5012  if (blob_info->offset >= (MagickOffsetType) ((off_t) blob_info->extent))
5013  return(-1);
5014  break;
5015  }
5016  case CustomStream:
5017  {
5018  if (blob_info->custom_stream->seeker == (CustomStreamSeeker) NULL)
5019  return(-1);
5020  blob_info->offset=blob_info->custom_stream->seeker(offset,whence,
5021  blob_info->custom_stream->data);
5022  break;
5023  }
5024  }
5025  return(blob_info->offset);
5026 }
5027 
5028 /*
5029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5030 % %
5031 % %
5032 % %
5033 + S e t B l o b E x e m p t %
5034 % %
5035 % %
5036 % %
5037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5038 %
5039 % SetBlobExempt() sets the blob exempt status.
5040 %
5041 % The format of the SetBlobExempt method is:
5042 %
5043 % MagickBooleanType SetBlobExempt(const Image *image,
5044 % const MagickBooleanType exempt)
5045 %
5046 % A description of each parameter follows:
5047 %
5048 % o image: the image.
5049 %
5050 % o exempt: Set to true if this blob is exempt from being closed.
5051 %
5052 */
5054 {
5055  assert(image != (const Image *) NULL);
5056  assert(image->signature == MagickCoreSignature);
5057  if (image->debug != MagickFalse)
5058  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5059  image->blob->exempt=exempt;
5060 }
5061 
5062 /*
5063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5064 % %
5065 % %
5066 % %
5067 + S e t B l o b E x t e n t %
5068 % %
5069 % %
5070 % %
5071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5072 %
5073 % SetBlobExtent() ensures enough space is allocated for the blob. If the
5074 % method is successful, subsequent writes to bytes in the specified range are
5075 % guaranteed not to fail.
5076 %
5077 % The format of the SetBlobExtent method is:
5078 %
5079 % MagickBooleanType SetBlobExtent(Image *image,const MagickSizeType extent)
5080 %
5081 % A description of each parameter follows:
5082 %
5083 % o image: the image.
5084 %
5085 % o extent: the blob maximum extent.
5086 %
5087 */
5089  const MagickSizeType extent)
5090 {
5091  BlobInfo
5092  *magick_restrict blob_info;
5093 
5094  assert(image != (Image *) NULL);
5095  assert(image->signature == MagickCoreSignature);
5096  if (image->debug != MagickFalse)
5097  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5098  assert(image->blob != (BlobInfo *) NULL);
5099  assert(image->blob->type != UndefinedStream);
5100  blob_info=image->blob;
5101  switch (blob_info->type)
5102  {
5103  case UndefinedStream:
5104  break;
5105  case StandardStream:
5106  return(MagickFalse);
5107  case FileStream:
5108  {
5110  offset;
5111 
5112  ssize_t
5113  count;
5114 
5115  if (extent != (MagickSizeType) ((off_t) extent))
5116  return(MagickFalse);
5117  offset=SeekBlob(image,0,SEEK_END);
5118  if (offset < 0)
5119  return(MagickFalse);
5120  if ((MagickSizeType) offset >= extent)
5121  break;
5122  offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
5123  if (offset < 0)
5124  break;
5125  count=(ssize_t) fwrite((const unsigned char *) "",1,1,
5126  blob_info->file_info.file);
5127 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
5128  if (blob_info->synchronize != MagickFalse)
5129  {
5130  int
5131  file;
5132 
5133  file=fileno(blob_info->file_info.file);
5134  if ((file == -1) || (offset < 0))
5135  return(MagickFalse);
5136  (void) posix_fallocate(file,offset,extent-offset);
5137  }
5138 #endif
5139  offset=SeekBlob(image,offset,SEEK_SET);
5140  if (count != 1)
5141  return(MagickFalse);
5142  break;
5143  }
5144  case PipeStream:
5145  case ZipStream:
5146  return(MagickFalse);
5147  case BZipStream:
5148  return(MagickFalse);
5149  case FifoStream:
5150  return(MagickFalse);
5151  case BlobStream:
5152  {
5153  if (extent != (MagickSizeType) ((size_t) extent))
5154  return(MagickFalse);
5155  if (blob_info->mapped != MagickFalse)
5156  {
5158  offset;
5159 
5160  ssize_t
5161  count;
5162 
5163  (void) UnmapBlob(blob_info->data,blob_info->length);
5164  RelinquishMagickResource(MapResource,blob_info->length);
5165  if (extent != (MagickSizeType) ((off_t) extent))
5166  return(MagickFalse);
5167  offset=SeekBlob(image,0,SEEK_END);
5168  if (offset < 0)
5169  return(MagickFalse);
5170  if ((MagickSizeType) offset >= extent)
5171  break;
5172  offset=SeekBlob(image,(MagickOffsetType) extent-1,SEEK_SET);
5173  count=(ssize_t) fwrite((const unsigned char *) "",1,1,
5174  blob_info->file_info.file);
5175 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
5176  if (blob_info->synchronize != MagickFalse)
5177  {
5178  int
5179  file;
5180 
5181  file=fileno(blob_info->file_info.file);
5182  if ((file == -1) || (offset < 0))
5183  return(MagickFalse);
5184  (void) posix_fallocate(file,offset,extent-offset);
5185  }
5186 #endif
5187  offset=SeekBlob(image,offset,SEEK_SET);
5188  if (count != 1)
5189  return(MagickFalse);
5190  (void) AcquireMagickResource(MapResource,extent);
5191  blob_info->data=(unsigned char*) MapBlob(fileno(
5192  blob_info->file_info.file),WriteMode,0,(size_t) extent);
5193  blob_info->extent=(size_t) extent;
5194  blob_info->length=(size_t) extent;
5195  (void) SyncBlob(image);
5196  break;
5197  }
5198  blob_info->extent=(size_t) extent;
5199  blob_info->data=(unsigned char *) ResizeQuantumMemory(blob_info->data,
5200  blob_info->extent+1,sizeof(*blob_info->data));
5201  (void) SyncBlob(image);
5202  if (blob_info->data == (unsigned char *) NULL)
5203  {
5204  (void) DetachBlob(blob_info);
5205  return(MagickFalse);
5206  }
5207  break;
5208  }
5209  case CustomStream:
5210  break;
5211  }
5212  return(MagickTrue);
5213 }
5214 
5215 /*
5216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217 % %
5218 % %
5219 % %
5220 + S e t C u s t o m S t r e a m D a t a %
5221 % %
5222 % %
5223 % %
5224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5225 %
5226 % SetCustomStreamData() sets the stream info data member.
5227 %
5228 % The format of the SetCustomStreamData method is:
5229 %
5230 % void SetCustomStreamData(CustomStreamInfo *custom_stream,void *)
5231 %
5232 % A description of each parameter follows:
5233 %
5234 % o custom_stream: the custom stream info.
5235 %
5236 % o data: an object containing information about the custom stream.
5237 %
5238 */
5240  void *data)
5241 {
5242  assert(custom_stream != (CustomStreamInfo *) NULL);
5243  assert(custom_stream->signature == MagickCoreSignature);
5244  custom_stream->data=data;
5245 }
5246 
5247 /*
5248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5249 % %
5250 % %
5251 % %
5252 + S e t C u s t o m S t r e a m R e a d e r %
5253 % %
5254 % %
5255 % %
5256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5257 %
5258 % SetCustomStreamReader() sets the stream info reader member.
5259 %
5260 % The format of the SetCustomStreamReader method is:
5261 %
5262 % void SetCustomStreamReader(CustomStreamInfo *custom_stream,
5263 % CustomStreamHandler reader)
5264 %
5265 % A description of each parameter follows:
5266 %
5267 % o custom_stream: the custom stream info.
5268 %
5269 % o reader: a function to read from the stream.
5270 %
5271 */
5273  CustomStreamHandler reader)
5274 {
5275  assert(custom_stream != (CustomStreamInfo *) NULL);
5276  assert(custom_stream->signature == MagickCoreSignature);
5277  custom_stream->reader=reader;
5278 }
5279 
5280 /*
5281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5282 % %
5283 % %
5284 % %
5285 + S e t C u s t o m S t r e a m S e e k e r %
5286 % %
5287 % %
5288 % %
5289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5290 %
5291 % SetCustomStreamSeeker() sets the stream info seeker member.
5292 %
5293 % The format of the SetCustomStreamReader method is:
5294 %
5295 % void SetCustomStreamSeeker(CustomStreamInfo *custom_stream,
5296 % CustomStreamSeeker seeker)
5297 %
5298 % A description of each parameter follows:
5299 %
5300 % o custom_stream: the custom stream info.
5301 %
5302 % o seeker: a function to seek in the custom stream.
5303 %
5304 */
5306  CustomStreamSeeker seeker)
5307 {
5308  assert(custom_stream != (CustomStreamInfo *) NULL);
5309  assert(custom_stream->signature == MagickCoreSignature);
5310  custom_stream->seeker=seeker;
5311 }
5312 
5313 /*
5314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315 % %
5316 % %
5317 % %
5318 + S e t C u s t o m S t r e a m T e l l e r %
5319 % %
5320 % %
5321 % %
5322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5323 %
5324 % SetCustomStreamTeller() sets the stream info teller member.
5325 %
5326 % The format of the SetCustomStreamTeller method is:
5327 %
5328 % void SetCustomStreamTeller(CustomStreamInfo *custom_stream,
5329 % CustomStreamTeller *teller)
5330 %
5331 % A description of each parameter follows:
5332 %
5333 % o custom_stream: the custom stream info.
5334 %
5335 % o teller: a function to set the position in the stream.
5336 %
5337 */
5339  CustomStreamTeller teller)
5340 {
5341  assert(custom_stream != (CustomStreamInfo *) NULL);
5342  assert(custom_stream->signature == MagickCoreSignature);
5343  custom_stream->teller=teller;
5344 }
5345 
5346 /*
5347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5348 % %
5349 % %
5350 % %
5351 + S e t C u s t o m S t r e a m W r i t e r %
5352 % %
5353 % %
5354 % %
5355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5356 %
5357 % SetCustomStreamWriter() sets the stream info writer member.
5358 %
5359 % The format of the SetCustomStreamWriter method is:
5360 %
5361 % void SetCustomStreamWriter(CustomStreamInfo *custom_stream,
5362 % CustomStreamHandler *writer)
5363 %
5364 % A description of each parameter follows:
5365 %
5366 % o custom_stream: the custom stream info.
5367 %
5368 % o writer: a function to write to the custom stream.
5369 %
5370 */
5372  CustomStreamHandler writer)
5373 {
5374  assert(custom_stream != (CustomStreamInfo *) NULL);
5375  assert(custom_stream->signature == MagickCoreSignature);
5376  custom_stream->writer=writer;
5377 }
5378 
5379 /*
5380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5381 % %
5382 % %
5383 % %
5384 + S y n c B l o b %
5385 % %
5386 % %
5387 % %
5388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5389 %
5390 % SyncBlob() flushes the datastream if it is a file or synchronizes the data
5391 % attributes if it is an blob.
5392 %
5393 % The format of the SyncBlob method is:
5394 %
5395 % int SyncBlob(Image *image)
5396 %
5397 % A description of each parameter follows:
5398 %
5399 % o image: the image.
5400 %
5401 */
5402 static int SyncBlob(Image *image)
5403 {
5404  BlobInfo
5405  *magick_restrict blob_info;
5406 
5407  int
5408  status;
5409 
5410  assert(image != (Image *) NULL);
5411  assert(image->signature == MagickCoreSignature);
5412  if (image->debug != MagickFalse)
5413  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5414  assert(image->blob != (BlobInfo *) NULL);
5415  assert(image->blob->type != UndefinedStream);
5416  blob_info=image->blob;
5417  status=0;
5418  switch (blob_info->type)
5419  {
5420  case UndefinedStream:
5421  case StandardStream:
5422  break;
5423  case FileStream:
5424  case PipeStream:
5425  {
5426  status=fflush(blob_info->file_info.file);
5427  break;
5428  }
5429  case ZipStream:
5430  {
5431 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5432  status=gzflush(blob_info->file_info.gzfile,Z_SYNC_FLUSH);
5433 #endif
5434  break;
5435  }
5436  case BZipStream:
5437  {
5438 #if defined(MAGICKCORE_BZLIB_DELEGATE)
5439  status=BZ2_bzflush(blob_info->file_info.bzfile);
5440 #endif
5441  break;
5442  }
5443  case FifoStream:
5444  break;
5445  case BlobStream:
5446  break;
5447  case CustomStream:
5448  break;
5449  }
5450  return(status);
5451 }
5452 
5453 /*
5454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5455 % %
5456 % %
5457 % %
5458 + T e l l B l o b %
5459 % %
5460 % %
5461 % %
5462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5463 %
5464 % TellBlob() obtains the current value of the blob or file position.
5465 %
5466 % The format of the TellBlob method is:
5467 %
5468 % MagickOffsetType TellBlob(const Image *image)
5469 %
5470 % A description of each parameter follows:
5471 %
5472 % o image: the image.
5473 %
5474 */
5476 {
5477  BlobInfo
5478  *magick_restrict blob_info;
5479 
5481  offset;
5482 
5483  assert(image != (Image *) NULL);
5484  assert(image->signature == MagickCoreSignature);
5485  if (image->debug != MagickFalse)
5486  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5487  assert(image->blob != (BlobInfo *) NULL);
5488  assert(image->blob->type != UndefinedStream);
5489  blob_info=image->blob;
5490  offset=(-1);
5491  switch (blob_info->type)
5492  {
5493  case UndefinedStream:
5494  case StandardStream:
5495  break;
5496  case FileStream:
5497  {
5498  offset=ftell(blob_info->file_info.file);
5499  break;
5500  }
5501  case PipeStream:
5502  break;
5503  case ZipStream:
5504  {
5505 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5506  offset=(MagickOffsetType) gztell(blob_info->file_info.gzfile);
5507 #endif
5508  break;
5509  }
5510  case BZipStream:
5511  break;
5512  case FifoStream:
5513  break;
5514  case BlobStream:
5515  {
5516  offset=blob_info->offset;
5517  break;
5518  }
5519  case CustomStream:
5520  {
5521  if (blob_info->custom_stream->teller != (CustomStreamTeller) NULL)
5522  offset=blob_info->custom_stream->teller(blob_info->custom_stream->data);
5523  break;
5524  }
5525  }
5526  return(offset);
5527 }
5528 
5529 /*
5530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5531 % %
5532 % %
5533 % %
5534 + U n m a p B l o b %
5535 % %
5536 % %
5537 % %
5538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5539 %
5540 % UnmapBlob() deallocates the binary large object previously allocated with
5541 % the MapBlob method.
5542 %
5543 % The format of the UnmapBlob method is:
5544 %
5545 % MagickBooleanType UnmapBlob(void *map,const size_t length)
5546 %
5547 % A description of each parameter follows:
5548 %
5549 % o map: the address of the binary large object.
5550 %
5551 % o length: the length of the binary large object.
5552 %
5553 */
5554 MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
5555 {
5556 #if defined(MAGICKCORE_HAVE_MMAP)
5557  int
5558  status;
5559 
5560  status=munmap(map,length);
5561  return(status == -1 ? MagickFalse : MagickTrue);
5562 #else
5563  (void) map;
5564  (void) length;
5565  return(MagickFalse);
5566 #endif
5567 }
5568 
5569 /*
5570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5571 % %
5572 % %
5573 % %
5574 + W r i t e B l o b %
5575 % %
5576 % %
5577 % %
5578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5579 %
5580 % WriteBlob() writes data to a blob or image file. It returns the number of
5581 % bytes written.
5582 %
5583 % The format of the WriteBlob method is:
5584 %
5585 % ssize_t WriteBlob(Image *image,const size_t length,const void *data)
5586 %
5587 % A description of each parameter follows:
5588 %
5589 % o image: the image.
5590 %
5591 % o length: Specifies an integer representing the number of bytes to
5592 % write to the file.
5593 %
5594 % o data: The address of the data to write to the blob or file.
5595 %
5596 */
5597 MagickExport ssize_t WriteBlob(Image *image,const size_t length,
5598  const void *data)
5599 {
5600  BlobInfo
5601  *magick_restrict blob_info;
5602 
5603  int
5604  c;
5605 
5606  register const unsigned char
5607  *p;
5608 
5609  register unsigned char
5610  *q;
5611 
5612  ssize_t
5613  count;
5614 
5615  assert(image != (Image *) NULL);
5616  assert(image->signature == MagickCoreSignature);
5617  assert(image->blob != (BlobInfo *) NULL);
5618  assert(image->blob->type != UndefinedStream);
5619  if (length == 0)
5620  return(0);
5621  assert(data != (const void *) NULL);
5622  blob_info=image->blob;
5623  count=0;
5624  p=(const unsigned char *) data;
5625  q=(unsigned char *) data;
5626  switch (blob_info->type)
5627  {
5628  case UndefinedStream:
5629  break;
5630  case StandardStream:
5631  case FileStream:
5632  case PipeStream:
5633  {
5634  switch (length)
5635  {
5636  default:
5637  {
5638  count=(ssize_t) fwrite((const char *) data,1,length,
5639  blob_info->file_info.file);
5640  break;
5641  }
5642  case 4:
5643  {
5644  c=putc((int) *p++,blob_info->file_info.file);
5645  if (c == EOF)
5646  break;
5647  count++;
5648  }
5649  case 3:
5650  {
5651  c=putc((int) *p++,blob_info->file_info.file);
5652  if (c == EOF)
5653  break;
5654  count++;
5655  }
5656  case 2:
5657  {
5658  c=putc((int) *p++,blob_info->file_info.file);
5659  if (c == EOF)
5660  break;
5661  count++;
5662  }
5663  case 1:
5664  {
5665  c=putc((int) *p++,blob_info->file_info.file);
5666  if (c == EOF)
5667  break;
5668  count++;
5669  }
5670  case 0:
5671  break;
5672  }
5673  if ((count != (ssize_t) length) &&
5674  (ferror(blob_info->file_info.file) != 0))
5675  ThrowBlobException(blob_info);
5676  break;
5677  }
5678  case ZipStream:
5679  {
5680 #if defined(MAGICKCORE_ZLIB_DELEGATE)
5681  int
5682  status;
5683 
5684  switch (length)
5685  {
5686  default:
5687  {
5688  register ssize_t
5689  i;
5690 
5691  for (i=0; i < (ssize_t) length; i+=count)
5692  {
5693  count=(ssize_t) gzwrite(blob_info->file_info.gzfile,q+i,
5694  (unsigned int) MagickMin(length-i,MagickMaxBufferExtent));
5695  if (count <= 0)
5696  {
5697  count=0;
5698  if (errno != EINTR)
5699  break;
5700  }
5701  }
5702  count=i;
5703  break;
5704  }
5705  case 4:
5706  {
5707  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5708  if (c == EOF)
5709  break;
5710  count++;
5711  }
5712  case 3:
5713  {
5714  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5715  if (c == EOF)
5716  break;
5717  count++;
5718  }
5719  case 2:
5720  {
5721  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5722  if (c == EOF)
5723  break;
5724  count++;
5725  }
5726  case 1:
5727  {
5728  c=gzputc(blob_info->file_info.gzfile,(int) *p++);
5729  if (c == EOF)
5730  break;
5731  count++;
5732  }
5733  case 0:
5734  break;
5735  }
5736  status=Z_OK;
5737  (void) gzerror(blob_info->file_info.gzfile,&status);
5738  if ((count != (ssize_t) length) && (status != Z_OK))
5739  ThrowBlobException(blob_info);
5740 #endif
5741  break;
5742  }
5743  case BZipStream:
5744  {
5745 #if defined(MAGICKCORE_BZLIB_DELEGATE)
5746  int
5747  status;
5748 
5749  register ssize_t
5750  i;
5751 
5752  for (i=0; i < (ssize_t) length; i+=count)
5753  {
5754  count=(ssize_t) BZ2_bzwrite(blob_info->file_info.bzfile,q+i,
5755  (int) MagickMin(length-i,MagickMaxBufferExtent));
5756  if (count <= 0)
5757  {
5758  count=0;
5759  if (errno != EINTR)
5760  break;
5761  }
5762  }
5763  count=i;
5764  status=BZ_OK;
5765  (void) BZ2_bzerror(blob_info->file_info.bzfile,&status);
5766  if ((count != (ssize_t) length) && (status != BZ_OK))
5767  ThrowBlobException(blob_info);
5768 #endif
5769  break;
5770  }
5771  case FifoStream:
5772  {
5773  count=(ssize_t) blob_info->stream(image,data,length);
5774  break;
5775  }
5776  case BlobStream:
5777  {
5778  if ((blob_info->offset+(MagickOffsetType) length) >=
5779  (MagickOffsetType) blob_info->extent)
5780  {
5781  if (blob_info->mapped != MagickFalse)
5782  return(0);
5783  blob_info->extent+=length+blob_info->quantum;
5784  blob_info->quantum<<=1;
5785  blob_info->data=(unsigned char *) ResizeQuantumMemory(
5786  blob_info->data,blob_info->extent+1,sizeof(*blob_info->data));
5787  (void) SyncBlob(image);
5788  if (blob_info->data == (unsigned char *) NULL)
5789  {
5790  (void) DetachBlob(blob_info);
5791  return(0);
5792  }
5793  }
5794  q=blob_info->data+blob_info->offset;
5795  (void) memcpy(q,p,length);
5796  blob_info->offset+=length;
5797  if (blob_info->offset >= (MagickOffsetType) blob_info->length)
5798  blob_info->length=(size_t) blob_info->offset;
5799  count=(ssize_t) length;
5800  break;
5801  }
5802  case CustomStream:
5803  {
5804  if (blob_info->custom_stream->writer != (CustomStreamHandler) NULL)
5805  count=blob_info->custom_stream->writer((unsigned char *) data,
5806  length,blob_info->custom_stream->data);
5807  break;
5808  }
5809  }
5810  return(count);
5811 }
5812 
5813 /*
5814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5815 % %
5816 % %
5817 % %
5818 + W r i t e B l o b B y t e %
5819 % %
5820 % %
5821 % %
5822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5823 %
5824 % WriteBlobByte() write an integer to a blob. It returns the number of bytes
5825 % written (either 0 or 1);
5826 %
5827 % The format of the WriteBlobByte method is:
5828 %
5829 % ssize_t WriteBlobByte(Image *image,const unsigned char value)
5830 %
5831 % A description of each parameter follows.
5832 %
5833 % o image: the image.
5834 %
5835 % o value: Specifies the value to write.
5836 %
5837 */
5838 MagickExport ssize_t WriteBlobByte(Image *image,const unsigned char value)
5839 {
5840  BlobInfo
5841  *magick_restrict blob_info;
5842 
5843  ssize_t
5844  count;
5845 
5846  assert(image != (Image *) NULL);
5847  assert(image->signature == MagickCoreSignature);
5848  assert(image->blob != (BlobInfo *) NULL);
5849  assert(image->blob->type != UndefinedStream);
5850  blob_info=image->blob;
5851  count=0;
5852  switch (blob_info->type)
5853  {
5854  case StandardStream:
5855  case FileStream:
5856  case PipeStream:
5857  {
5858  int
5859  c;
5860 
5861  c=putc((int) value,blob_info->file_info.file);
5862  if (c == EOF)
5863  {
5864  if (ferror(blob_info->file_info.file) != 0)
5865  ThrowBlobException(blob_info);
5866  break;
5867  }
5868  count++;
5869  break;
5870  }
5871  default:
5872  {
5873  count=WriteBlobStream(image,1,&value);
5874  break;
5875  }
5876  }
5877  return(count);
5878 }
5879 
5880 /*
5881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5882 % %
5883 % %
5884 % %
5885 + W r i t e B l o b F l o a t %
5886 % %
5887 % %
5888 % %
5889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5890 %
5891 % WriteBlobFloat() writes a float value as a 32-bit quantity in the byte-order
5892 % specified by the endian member of the image structure.
5893 %
5894 % The format of the WriteBlobFloat method is:
5895 %
5896 % ssize_t WriteBlobFloat(Image *image,const float value)
5897 %
5898 % A description of each parameter follows.
5899 %
5900 % o image: the image.
5901 %
5902 % o value: Specifies the value to write.
5903 %
5904 */
5905 MagickExport ssize_t WriteBlobFloat(Image *image,const float value)
5906 {
5907  union
5908  {
5909  unsigned int
5910  unsigned_value;
5911 
5912  float
5913  float_value;
5914  } quantum;
5915 
5916  quantum.unsigned_value=0U;
5917  quantum.float_value=value;
5918  return(WriteBlobLong(image,quantum.unsigned_value));
5919 }
5920 
5921 /*
5922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5923 % %
5924 % %
5925 % %
5926 + W r i t e B l o b L o n g %
5927 % %
5928 % %
5929 % %
5930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5931 %
5932 % WriteBlobLong() writes a unsigned int value as a 32-bit quantity in the
5933 % byte-order specified by the endian member of the image structure.
5934 %
5935 % The format of the WriteBlobLong method is:
5936 %
5937 % ssize_t WriteBlobLong(Image *image,const unsigned int value)
5938 %
5939 % A description of each parameter follows.
5940 %
5941 % o image: the image.
5942 %
5943 % o value: Specifies the value to write.
5944 %
5945 */
5946 MagickExport ssize_t WriteBlobLong(Image *image,const unsigned int value)
5947 {
5948  unsigned char
5949  buffer[4];
5950 
5951  assert(image != (Image *) NULL);
5952  assert(image->signature == MagickCoreSignature);
5953  if (image->endian == LSBEndian)
5954  {
5955  buffer[0]=(unsigned char) value;
5956  buffer[1]=(unsigned char) (value >> 8);
5957  buffer[2]=(unsigned char) (value >> 16);
5958  buffer[3]=(unsigned char) (value >> 24);
5959  return(WriteBlobStream(image,4,buffer));
5960  }
5961  buffer[0]=(unsigned char) (value >> 24);
5962  buffer[1]=(unsigned char) (value >> 16);
5963  buffer[2]=(unsigned char) (value >> 8);
5964  buffer[3]=(unsigned char) value;
5965  return(WriteBlobStream(image,4,buffer));
5966 }
5967 
5968 /*
5969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5970 % %
5971 % %
5972 % %
5973 + W r i t e B l o b L o n g L o n g %
5974 % %
5975 % %
5976 % %
5977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5978 %
5979 % WriteBlobMSBLongLong() writes a long long value as a 64-bit quantity in the
5980 % byte-order specified by the endian member of the image structure.
5981 %
5982 % The format of the WriteBlobLongLong method is:
5983 %
5984 % ssize_t WriteBlobLongLong(Image *image,const MagickSizeType value)
5985 %
5986 % A description of each parameter follows.
5987 %
5988 % o value: Specifies the value to write.
5989 %
5990 % o image: the image.
5991 %
5992 */
5994 {
5995  unsigned char
5996  buffer[8];
5997 
5998  assert(image != (Image *) NULL);
5999  assert(image->signature == MagickCoreSignature);
6000  if (image->endian == LSBEndian)
6001  {
6002  buffer[0]=(unsigned char) value;
6003  buffer[1]=(unsigned char) (value >> 8);
6004  buffer[2]=(unsigned char) (value >> 16);
6005  buffer[3]=(unsigned char) (value >> 24);
6006  buffer[4]=(unsigned char) (value >> 32);
6007  buffer[5]=(unsigned char) (value >> 40);
6008  buffer[6]=(unsigned char) (value >> 48);
6009  buffer[7]=(unsigned char) (value >> 56);
6010  return(WriteBlobStream(image,8,buffer));
6011  }
6012  buffer[0]=(unsigned char) (value >> 56);
6013  buffer[1]=(unsigned char) (value >> 48);
6014  buffer[2]=(unsigned char) (value >> 40);
6015  buffer[3]=(unsigned char) (value >> 32);
6016  buffer[4]=(unsigned char) (value >> 24);
6017  buffer[5]=(unsigned char) (value >> 16);
6018  buffer[6]=(unsigned char) (value >> 8);
6019  buffer[7]=(unsigned char) value;
6020  return(WriteBlobStream(image,8,buffer));
6021 }
6022 
6023 /*
6024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6025 % %
6026 % %
6027 % %
6028 + W r i t e B l o b S h o r t %
6029 % %
6030 % %
6031 % %
6032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6033 %
6034 % WriteBlobShort() writes a short value as a 16-bit quantity in the
6035 % byte-order specified by the endian member of the image structure.
6036 %
6037 % The format of the WriteBlobShort method is:
6038 %
6039 % ssize_t WriteBlobShort(Image *image,const unsigned short value)
6040 %
6041 % A description of each parameter follows.
6042 %
6043 % o image: the image.
6044 %
6045 % o value: Specifies the value to write.
6046 %
6047 */
6048 MagickExport ssize_t WriteBlobShort(Image *image,const unsigned short value)
6049 {
6050  unsigned char
6051  buffer[2];
6052 
6053  assert(image != (Image *) NULL);
6054  assert(image->signature == MagickCoreSignature);
6055  if (image->endian == LSBEndian)
6056  {
6057  buffer[0]=(unsigned char) value;
6058  buffer[1]=(unsigned char) (value >> 8);
6059  return(WriteBlobStream(image,2,buffer));
6060  }
6061  buffer[0]=(unsigned char) (value >> 8);
6062  buffer[1]=(unsigned char) value;
6063  return(WriteBlobStream(image,2,buffer));
6064 }
6065 
6066 /*
6067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6068 % %
6069 % %
6070 % %
6071 + W r i t e B l o b S i g n e d L o n g %
6072 % %
6073 % %
6074 % %
6075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6076 %
6077 % WriteBlobSignedLong() writes a signed value as a 32-bit qu