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