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