blob: e96ebd7ec1cda10844cf97a53e9eecb1ea453c7a [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/client.h"
48#include "magick/constitute.h"
49#include "magick/delegate.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
52#include "magick/image-private.h"
53#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
57#include "magick/policy.h"
58#include "magick/resource_.h"
59#include "magick/semaphore.h"
60#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000061#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000062#include "magick/utility.h"
63#if defined(MAGICKCORE_HAVE_MMAP_FILEIO) && !defined(__WINDOWS__)
64# include <sys/mman.h>
65#endif
66#if defined(MAGICKCORE_ZLIB_DELEGATE)
67#include "zlib.h"
68#endif
69#if defined(MAGICKCORE_BZLIB_DELEGATE)
70#include "bzlib.h"
71#endif
72
73/*
74 Define declarations.
75*/
76#define MagickMaxBlobExtent 65541
77#if defined(MAGICKCORE_HAVE_FSEEKO)
78# define fseek fseeko
79# define ftell ftello
80#endif
81#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
82# define MAP_ANONYMOUS MAP_ANON
83#endif
84#if !defined(MAP_FAILED)
85#define MAP_FAILED ((void *) -1)
86#endif
87#if !defined(MS_SYNC)
88#define MS_SYNC 0x04
89#endif
90#if defined(__OS2__)
91#include <io.h>
92#define _O_BINARY O_BINARY
93#endif
94
95/*
96 Typedef declarations.
97*/
98struct _BlobInfo
99{
100 size_t
101 length,
102 extent,
103 quantum;
104
105 MagickBooleanType
106 mapped,
107 eof;
108
109 MagickOffsetType
110 offset;
111
112 MagickSizeType
113 size;
114
115 MagickBooleanType
116 exempt,
117 synchronize,
118 status,
119 temporary;
120
121 StreamType
122 type;
123
124 FILE
125 *file;
126
127 struct stat
128 properties;
129
130 StreamHandler
131 stream;
132
133 unsigned char
134 *data;
135
136 MagickBooleanType
137 debug;
138
139 SemaphoreInfo
140 *semaphore;
141
142 long
143 reference_count;
144
145 unsigned long
146 signature;
147};
148
149/*
150 Forward declarations.
151*/
152static int
153 SyncBlob(Image *);
154
155/*
156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
157% %
158% %
159% %
160+ A t t a c h B l o b %
161% %
162% %
163% %
164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165%
166% AttachBlob() attaches a blob to the BlobInfo structure.
167%
168% The format of the AttachBlob method is:
169%
170% void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
171%
172% A description of each parameter follows:
173%
174% o blob_info: Specifies a pointer to a BlobInfo structure.
175%
176% o blob: the address of a character stream in one of the image formats
177% understood by ImageMagick.
178%
179% o length: This size_t integer reflects the length in bytes of the blob.
180%
181*/
182MagickExport void AttachBlob(BlobInfo *blob_info,const void *blob,
183 const size_t length)
184{
185 assert(blob_info != (BlobInfo *) NULL);
186 if (blob_info->debug != MagickFalse)
187 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
188 blob_info->length=length;
189 blob_info->extent=length;
190 blob_info->quantum=(size_t) MagickMaxBlobExtent;
191 blob_info->offset=0;
192 blob_info->type=BlobStream;
193 blob_info->file=(FILE *) NULL;
194 blob_info->data=(unsigned char *) blob;
195 blob_info->mapped=MagickFalse;
196}
197
198/*
199%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200% %
201% %
202% %
203+ B l o b T o F i l e %
204% %
205% %
206% %
207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208%
209% BlobToFile() writes a blob to a file. It returns MagickFalse if an error
210% occurs otherwise MagickTrue.
211%
212% The format of the BlobToFile method is:
213%
214% MagickBooleanType BlobToFile(char *filename,const void *blob,
215% const size_t length,ExceptionInfo *exception)
216%
217% A description of each parameter follows:
218%
219% o filename: Write the blob to this file.
220%
221% o blob: the address of a blob.
222%
223% o length: This length in bytes of the blob.
224%
225% o exception: return any errors or warnings in this structure.
226%
227*/
228
229static inline size_t MagickMin(const size_t x,const size_t y)
230{
231 if (x < y)
232 return(x);
233 return(y);
234}
235
236MagickExport MagickBooleanType BlobToFile(char *filename,const void *blob,
237 const size_t length,ExceptionInfo *exception)
238{
239 int
240 file;
241
242 register size_t
243 i;
244
245 ssize_t
246 count;
247
248 assert(filename != (const char *) NULL);
249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
250 assert(blob != (const void *) NULL);
251 if (*filename == '\0')
252 file=AcquireUniqueFileResource(filename);
253 else
254 file=open(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
255 if (file == -1)
256 {
257 ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
258 return(MagickFalse);
259 }
260 for (i=0; i < length; i+=count)
261 {
262 count=(ssize_t) write(file,(const char *) blob+i,MagickMin(length-i,(size_t)
263 SSIZE_MAX));
264 if (count <= 0)
265 {
266 count=0;
267 if (errno != EINTR)
268 break;
269 }
270 }
271 file=close(file)-1;
272 if (i < length)
273 {
274 ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
275 return(MagickFalse);
276 }
277 return(MagickTrue);
278}
279
280/*
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282% %
283% %
284% %
285% B l o b T o I m a g e %
286% %
287% %
288% %
289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290%
291% BlobToImage() implements direct to memory image formats. It returns the
292% blob as an image.
293%
294% The format of the BlobToImage method is:
295%
296% Image *BlobToImage(const ImageInfo *image_info,const void *blob,
297% const size_t length,ExceptionInfo *exception)
298%
299% A description of each parameter follows:
300%
301% o image_info: the image info.
302%
303% o blob: the address of a character stream in one of the image formats
304% understood by ImageMagick.
305%
306% o length: This size_t integer reflects the length in bytes of the blob.
307%
308% o exception: return any errors or warnings in this structure.
309%
310*/
311MagickExport Image *BlobToImage(const ImageInfo *image_info,const void *blob,
312 const size_t length,ExceptionInfo *exception)
313{
314 const MagickInfo
315 *magick_info;
316
317 Image
318 *image;
319
320 ImageInfo
321 *blob_info,
322 *clone_info;
323
324 MagickBooleanType
325 status;
326
327 assert(image_info != (ImageInfo *) NULL);
328 assert(image_info->signature == MagickSignature);
329 if (image_info->debug != MagickFalse)
330 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
331 image_info->filename);
332 assert(exception != (ExceptionInfo *) NULL);
333 if ((blob == (const void *) NULL) || (length == 0))
334 {
335 (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
336 "ZeroLengthBlobNotPermitted","`%s'",image_info->filename);
337 return((Image *) NULL);
338 }
339 blob_info=CloneImageInfo(image_info);
340 blob_info->blob=(void *) blob;
341 blob_info->length=length;
342 if (*blob_info->magick == '\0')
343 (void) SetImageInfo(blob_info,MagickFalse,exception);
344 magick_info=GetMagickInfo(blob_info->magick,exception);
345 if (magick_info == (const MagickInfo *) NULL)
346 {
347 blob_info=DestroyImageInfo(blob_info);
348 (void) ThrowMagickException(exception,GetMagickModule(),
349 MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
350 image_info->filename);
351 return((Image *) NULL);
352 }
353 if (GetMagickBlobSupport(magick_info) != MagickFalse)
354 {
355 /*
356 Native blob support for this image format.
357 */
358 (void) CopyMagickString(blob_info->filename,image_info->filename,
359 MaxTextExtent);
360 (void) CopyMagickString(blob_info->magick,image_info->magick,
361 MaxTextExtent);
362 image=ReadImage(blob_info,exception);
363 if (image != (Image *) NULL)
364 (void) DetachBlob(image->blob);
365 blob_info=DestroyImageInfo(blob_info);
366 return(image);
367 }
368 /*
369 Write blob to a temporary file on disk.
370 */
371 blob_info->blob=(void *) NULL;
372 blob_info->length=0;
373 *blob_info->filename='\0';
374 status=BlobToFile(blob_info->filename,blob,length,exception);
375 if (status == MagickFalse)
376 {
377 (void) RelinquishUniqueFileResource(blob_info->filename);
378 blob_info=DestroyImageInfo(blob_info);
379 return((Image *) NULL);
380 }
381 clone_info=CloneImageInfo(blob_info);
382 (void) FormatMagickString(clone_info->filename,MaxTextExtent,"%s:%s",
383 blob_info->magick,blob_info->filename);
384 image=ReadImage(clone_info,exception);
385 clone_info=DestroyImageInfo(clone_info);
386 (void) RelinquishUniqueFileResource(blob_info->filename);
387 blob_info=DestroyImageInfo(blob_info);
388 return(image);
389}
390
391/*
392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393% %
394% %
395% %
396+ C l o n e B l o b I n f o %
397% %
398% %
399% %
400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
401%
402% CloneBlobInfo() makes a duplicate of the given blob info structure, or if
403% blob info is NULL, a new one.
404%
405% The format of the CloneBlobInfo method is:
406%
407% BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
408%
409% A description of each parameter follows:
410%
411% o blob_info: the blob info.
412%
413*/
414MagickExport BlobInfo *CloneBlobInfo(const BlobInfo *blob_info)
415{
416 BlobInfo
417 *clone_info;
418
cristy90823212009-12-12 20:48:33 +0000419 clone_info=(BlobInfo *) AcquireAlignedMemory(1,sizeof(*clone_info));
cristy3ed852e2009-09-05 21:47:34 +0000420 if (clone_info == (BlobInfo *) NULL)
421 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
422 GetBlobInfo(clone_info);
423 if (blob_info == (BlobInfo *) NULL)
424 return(clone_info);
425 clone_info->length=blob_info->length;
426 clone_info->extent=blob_info->extent;
427 clone_info->synchronize=blob_info->synchronize;
428 clone_info->quantum=blob_info->quantum;
429 clone_info->mapped=blob_info->mapped;
430 clone_info->eof=blob_info->eof;
431 clone_info->offset=blob_info->offset;
432 clone_info->size=blob_info->size;
433 clone_info->exempt=blob_info->exempt;
434 clone_info->status=blob_info->status;
435 clone_info->temporary=blob_info->temporary;
436 clone_info->type=blob_info->type;
437 clone_info->file=blob_info->file;
438 clone_info->properties=blob_info->properties;
439 clone_info->stream=blob_info->stream;
440 clone_info->data=blob_info->data;
441 clone_info->debug=IsEventLogging();
442 clone_info->reference_count=1;
443 return(clone_info);
444}
445
446/*
447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448% %
449% %
450% %
451+ C l o s e B l o b %
452% %
453% %
454% %
455%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456%
457% CloseBlob() closes a stream associated with the image.
458%
459% The format of the CloseBlob method is:
460%
461% MagickBooleanType CloseBlob(Image *image)
462%
463% A description of each parameter follows:
464%
465% o image: the image.
466%
467*/
468MagickExport MagickBooleanType CloseBlob(Image *image)
469{
470 int
471 status;
472
473 /*
474 Close image file.
475 */
476 assert(image != (Image *) NULL);
477 assert(image->signature == MagickSignature);
478 if (image->debug != MagickFalse)
479 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
480 assert(image->blob != (BlobInfo *) NULL);
481 if (image->blob->type == UndefinedStream)
482 return(MagickTrue);
483 if (image->blob->synchronize != MagickFalse)
484 SyncBlob(image);
485 image->blob->size=GetBlobSize(image);
cristy81b8ce52010-02-05 01:53:17 +0000486 image->extent=image->blob->size;
cristy3ed852e2009-09-05 21:47:34 +0000487 image->blob->eof=MagickFalse;
488 if (image->blob->exempt != MagickFalse)
489 {
490 image->blob->type=UndefinedStream;
491 return(MagickTrue);
492 }
493 status=0;
494 switch (image->blob->type)
495 {
496 case UndefinedStream:
497 break;
498 case FileStream:
499 case StandardStream:
500 case PipeStream:
501 {
502 status=ferror(image->blob->file);
503 break;
504 }
505 case ZipStream:
506 {
507#if defined(MAGICKCORE_ZLIB_DELEGATE)
508 (void) gzerror(image->blob->file,&status);
509#endif
510 break;
511 }
512 case BZipStream:
513 {
514#if defined(MAGICKCORE_BZLIB_DELEGATE)
515 (void) BZ2_bzerror((BZFILE *) image->blob->file,&status);
516#endif
517 break;
518 }
519 case FifoStream:
520 case BlobStream:
521 break;
522 }
523 image->blob->status=status < 0 ? MagickTrue : MagickFalse;
524 switch (image->blob->type)
525 {
526 case UndefinedStream:
527 break;
528 case FileStream:
529 case StandardStream:
530 {
531 if (image->blob->synchronize != MagickFalse)
532 status=fsync(fileno(image->blob->file));
533 status=fclose(image->blob->file);
534 break;
535 }
536 case PipeStream:
537 {
538#if defined(MAGICKCORE_HAVE_PCLOSE)
539 status=pclose(image->blob->file);
540#endif
541 break;
542 }
543 case ZipStream:
544 {
545#if defined(MAGICKCORE_ZLIB_DELEGATE)
546 status=gzclose(image->blob->file);
547#endif
548 break;
549 }
550 case BZipStream:
551 {
552#if defined(MAGICKCORE_BZLIB_DELEGATE)
553 BZ2_bzclose((BZFILE *) image->blob->file);
554#endif
555 break;
556 }
557 case FifoStream:
558 case BlobStream:
559 break;
560 }
561 (void) DetachBlob(image->blob);
562 image->blob->status=status < 0 ? MagickTrue : MagickFalse;
563 return(image->blob->status);
564}
565
566/*
567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
568% %
569% %
570% %
571+ D e s t r o y B l o b %
572% %
573% %
574% %
575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
576%
577% DestroyBlob() deallocates memory associated with a blob.
578%
579% The format of the DestroyBlob method is:
580%
581% void DestroyBlob(Image *image)
582%
583% A description of each parameter follows:
584%
585% o image: the image.
586%
587*/
588MagickExport void DestroyBlob(Image *image)
589{
590 MagickBooleanType
591 destroy;
592
593 assert(image != (Image *) NULL);
594 assert(image->signature == MagickSignature);
595 if (image->debug != MagickFalse)
596 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
597 assert(image->blob != (BlobInfo *) NULL);
598 assert(image->blob->signature == MagickSignature);
599 destroy=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000600 LockSemaphoreInfo(image->blob->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000601 image->blob->reference_count--;
602 assert(image->blob->reference_count >= 0);
603 if (image->blob->reference_count == 0)
604 destroy=MagickTrue;
cristyf84a1932010-01-03 18:00:18 +0000605 UnlockSemaphoreInfo(image->blob->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000606 if (destroy == MagickFalse)
607 return;
608 (void) CloseBlob(image);
609 if (image->blob->mapped != MagickFalse)
610 (void) UnmapBlob(image->blob->data,image->blob->length);
611 if (image->blob->semaphore != (SemaphoreInfo *) NULL)
612 DestroySemaphoreInfo(&image->blob->semaphore);
613 image->blob->signature=(~MagickSignature);
614 image->blob=(BlobInfo *) RelinquishMagickMemory(image->blob);
615}
616
617/*
618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619% %
620% %
621% %
622+ D e t a c h B l o b %
623% %
624% %
625% %
626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627%
628% DetachBlob() detaches a blob from the BlobInfo structure.
629%
630% The format of the DetachBlob method is:
631%
632% unsigned char *DetachBlob(BlobInfo *blob_info)
633%
634% A description of each parameter follows:
635%
636% o blob_info: Specifies a pointer to a BlobInfo structure.
637%
638*/
639MagickExport unsigned char *DetachBlob(BlobInfo *blob_info)
640{
641 unsigned char
642 *data;
643
644 assert(blob_info != (BlobInfo *) NULL);
645 if (blob_info->debug != MagickFalse)
646 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
647 if (blob_info->mapped != MagickFalse)
648 (void) UnmapBlob(blob_info->data,blob_info->length);
649 blob_info->mapped=MagickFalse;
650 blob_info->length=0;
651 blob_info->offset=0;
652 blob_info->eof=MagickFalse;
653 blob_info->exempt=MagickFalse;
654 blob_info->type=UndefinedStream;
655 blob_info->file=(FILE *) NULL;
656 data=blob_info->data;
657 blob_info->data=(unsigned char *) NULL;
658 blob_info->stream=(StreamHandler) NULL;
659 return(data);
660}
661
662/*
663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664% %
665% %
666% %
667+ D u p l i c a t e s B l o b %
668% %
669% %
670% %
671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672%
673% DuplicateBlob() duplicates a blob descriptor.
674%
675% The format of the DuplicateBlob method is:
676%
677% void DuplicateBlob(Image *image,const Image *duplicate)
678%
679% A description of each parameter follows:
680%
681% o image: the image.
682%
683% o duplicate: the duplicate image.
684%
685*/
686MagickExport void DuplicateBlob(Image *image,const Image *duplicate)
687{
688 assert(image != (Image *) NULL);
689 assert(image->signature == MagickSignature);
690 if (image->debug != MagickFalse)
691 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
692 assert(duplicate != (Image *) NULL);
693 assert(duplicate->signature == MagickSignature);
694 DestroyBlob(image);
695 image->blob=ReferenceBlob(duplicate->blob);
696}
697
698/*
699%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700% %
701% %
702% %
703+ E O F B l o b %
704% %
705% %
706% %
707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708%
709% EOFBlob() returns a non-zero value when EOF has been detected reading from
710% a blob or file.
711%
712% The format of the EOFBlob method is:
713%
714% int EOFBlob(const Image *image)
715%
716% A description of each parameter follows:
717%
718% o image: the image.
719%
720*/
721MagickExport int EOFBlob(const Image *image)
722{
723 assert(image != (Image *) NULL);
724 assert(image->signature == MagickSignature);
725 if (image->debug != MagickFalse)
726 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
727 assert(image->blob != (BlobInfo *) NULL);
728 assert(image->blob->type != UndefinedStream);
729 switch (image->blob->type)
730 {
731 case UndefinedStream:
732 break;
733 case FileStream:
734 case StandardStream:
735 case PipeStream:
736 {
737 image->blob->eof=feof(image->blob->file) != 0 ? MagickTrue : MagickFalse;
738 break;
739 }
740 case ZipStream:
741 {
742 image->blob->eof=MagickFalse;
743 break;
744 }
745 case BZipStream:
746 {
747#if defined(MAGICKCORE_BZLIB_DELEGATE)
748 int
749 status;
750
751 status=0;
752 (void) BZ2_bzerror((BZFILE *) image->blob->file,&status);
753 image->blob->eof=status == BZ_UNEXPECTED_EOF ? MagickTrue : MagickFalse;
754#endif
755 break;
756 }
757 case FifoStream:
758 {
759 image->blob->eof=MagickFalse;
760 break;
761 }
762 case BlobStream:
763 break;
764 }
765 return((int) image->blob->eof);
766}
767
768/*
769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
770% %
771% %
772% %
773+ F i l e T o B l o b %
774% %
775% %
776% %
777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778%
779% FileToBlob() returns the contents of a file as a blob. It returns the
780% file as a blob and its length. If an error occurs, NULL is returned.
781%
782% The format of the FileToBlob method is:
783%
784% unsigned char *FileToBlob(const char *filename,const size_t extent,
785% size_t *length,ExceptionInfo *exception)
786%
787% A description of each parameter follows:
788%
789% o blob: FileToBlob() returns the contents of a file as a blob. If
790% an error occurs NULL is returned.
791%
792% o filename: the filename.
793%
794% o extent: The maximum length of the blob.
795%
796% o length: On return, this reflects the actual length of the blob.
797%
798% o exception: return any errors or warnings in this structure.
799%
800*/
801MagickExport unsigned char *FileToBlob(const char *filename,const size_t extent,
802 size_t *length,ExceptionInfo *exception)
803{
804 int
805 file;
806
807 MagickOffsetType
808 offset;
809
810 register size_t
811 i;
812
813 ssize_t
814 count;
815
816 unsigned char
817 *blob;
818
819 void
820 *map;
821
822 assert(filename != (const char *) NULL);
823 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
824 assert(exception != (ExceptionInfo *) NULL);
825 *length=0;
826 file=fileno(stdin);
827 if (LocaleCompare(filename,"-") != 0)
828 file=open(filename,O_RDONLY | O_BINARY);
829 if (file == -1)
830 {
831 ThrowFileException(exception,BlobError,"UnableToOpenFile",filename);
832 return((unsigned char *) NULL);
833 }
834 offset=(MagickOffsetType) MagickSeek(file,0,SEEK_END);
835 count=0;
836 if ((offset < 0) || (offset != (MagickOffsetType) ((ssize_t) offset)))
837 {
838 size_t
839 quantum;
840
841 struct stat
842 file_info;
843
844 /*
845 Stream is not seekable.
846 */
847 quantum=(size_t) MagickMaxBufferExtent;
848 if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
849 quantum=MagickMin((size_t) file_info.st_size,MagickMaxBufferExtent);
850 blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
851 for (i=0; blob != (unsigned char *) NULL; i+=count)
852 {
853 count=(ssize_t) read(file,blob+i,quantum);
854 if (count <= 0)
855 {
856 count=0;
857 if (errno != EINTR)
858 break;
859 }
860 if (~(1UL*i) < (quantum+1))
861 {
862 blob=(unsigned char *) RelinquishMagickMemory(blob);
863 break;
864 }
865 blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
866 sizeof(*blob));
867 if ((size_t) (i+count) >= extent)
868 break;
869 }
870 file=close(file)-1;
871 if (blob == (unsigned char *) NULL)
872 {
873 (void) ThrowMagickException(exception,GetMagickModule(),
874 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
875 return((unsigned char *) NULL);
876 }
877 *length=MagickMin(i+count,extent);
878 blob[*length]='\0';
879 return(blob);
880 }
881 *length=MagickMin((size_t) offset,extent);
882 blob=(unsigned char *) NULL;
883 if (~(*length) >= MaxTextExtent)
884 blob=(unsigned char *) AcquireQuantumMemory(*length+MaxTextExtent,
885 sizeof(*blob));
886 if (blob == (unsigned char *) NULL)
887 {
888 file=close(file)-1;
889 (void) ThrowMagickException(exception,GetMagickModule(),
890 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
891 return((unsigned char *) NULL);
892 }
893 map=MapBlob(file,ReadMode,0,*length);
894 if (map != (unsigned char *) NULL)
895 {
896 (void) CopyMagickMemory(blob,map,*length);
897 (void) UnmapBlob(map,*length);
898 }
899 else
900 {
901 (void) MagickSeek(file,0,SEEK_SET);
902 for (i=0; i < *length; i+=count)
903 {
904 count=(ssize_t) read(file,blob+i,MagickMin(*length-i,(size_t)
905 SSIZE_MAX));
906 if (count <= 0)
907 {
908 count=0;
909 if (errno != EINTR)
910 break;
911 }
912 }
913 if (i < *length)
914 {
915 file=close(file)-1;
916 blob=(unsigned char *) RelinquishMagickMemory(blob);
917 ThrowFileException(exception,BlobError,"UnableToReadBlob",filename);
918 return((unsigned char *) NULL);
919 }
920 }
921 file=close(file)-1;
922 blob[*length]='\0';
923 return(blob);
924}
925
926/*
927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928% %
929% %
930% %
931% F i l e T o I m a g e %
932% %
933% %
934% %
935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
936%
937% FileToImage() write the contents of a file to an image.
938%
939% The format of the FileToImage method is:
940%
941% MagickBooleanType FileToImage(Image *,const char *filename)
942%
943% A description of each parameter follows:
944%
945% o image: the image.
946%
947% o filename: the filename.
948%
949*/
950
951static inline ssize_t WriteBlobStream(Image *image,const size_t length,
952 const unsigned char *data)
953{
954 MagickSizeType
955 extent;
956
957 register unsigned char
958 *q;
959
960 assert(image->blob != (BlobInfo *) NULL);
961 if (image->blob->type != BlobStream)
962 return(WriteBlob(image,length,data));
963 assert(image->blob->type != UndefinedStream);
964 assert(data != (void *) NULL);
965 extent=(MagickSizeType) (image->blob->offset+(MagickOffsetType) length);
966 if (extent >= image->blob->extent)
967 {
968 image->blob->quantum<<=1;
969 extent=image->blob->extent+image->blob->quantum+length;
970 if (SetBlobExtent(image,extent) == MagickFalse)
971 return(0);
972 }
973 q=image->blob->data+image->blob->offset;
974 (void) CopyMagickMemory(q,data,length);
975 image->blob->offset+=length;
976 if (image->blob->offset >= (MagickOffsetType) image->blob->length)
977 image->blob->length=(size_t) image->blob->offset;
978 return((ssize_t) length);
979}
980
981MagickExport MagickBooleanType FileToImage(Image *image,const char *filename)
982{
983 int
984 file;
985
986 size_t
987 length,
988 quantum;
989
990 ssize_t
991 count;
992
993 struct stat
994 file_info;
995
996 unsigned char
997 *blob;
998
999 assert(image != (const Image *) NULL);
1000 assert(image->signature == MagickSignature);
1001 assert(filename != (const char *) NULL);
1002 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1003 file=open(filename,O_RDONLY | O_BINARY);
1004 if (file == -1)
1005 {
1006 ThrowFileException(&image->exception,BlobError,"UnableToOpenBlob",
1007 filename);
1008 return(MagickFalse);
1009 }
1010 quantum=(size_t) MagickMaxBufferExtent;
1011 if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
1012 quantum=MagickMin((size_t) file_info.st_size,MagickMaxBufferExtent);
1013 blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
1014 if (blob == (unsigned char *) NULL)
1015 {
1016 ThrowFileException(&image->exception,ResourceLimitError,
1017 "MemoryAllocationFailed",filename);
1018 return(MagickFalse);
1019 }
1020 for ( ; ; )
1021 {
1022 count=(ssize_t) read(file,blob,quantum);
1023 if (count <= 0)
1024 {
1025 count=0;
1026 if (errno != EINTR)
1027 break;
1028 }
1029 length=(size_t) count;
1030 count=WriteBlobStream(image,length,blob);
1031 if (count != (ssize_t) length)
1032 {
1033 ThrowFileException(&image->exception,BlobError,"UnableToWriteBlob",
1034 filename);
1035 break;
1036 }
1037 }
1038 file=close(file)-1;
1039 blob=(unsigned char *) RelinquishMagickMemory(blob);
1040 return(MagickTrue);
1041}
1042
1043/*
1044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045% %
1046% %
1047% %
1048+ G e t B l o b E r r o r %
1049% %
1050% %
1051% %
1052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053%
1054% GetBlobError() returns MagickTrue if the blob associated with the specified
1055% image encountered an error.
1056%
1057% The format of the GetBlobError method is:
1058%
1059% MagickBooleanType GetBlobError(const Image *image)
1060%
1061% A description of each parameter follows:
1062%
1063% o image: the image.
1064%
1065*/
1066MagickExport MagickBooleanType GetBlobError(const Image *image)
1067{
1068 assert(image != (const Image *) NULL);
1069 assert(image->signature == MagickSignature);
1070 if (image->debug != MagickFalse)
1071 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1072 return(image->blob->status);
1073}
1074
1075/*
1076%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1077% %
1078% %
1079% %
1080+ G e t B l o b F i l e H a n d l e %
1081% %
1082% %
1083% %
1084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085%
1086% GetBlobFileHandle() returns the file handle associated with the image blob.
1087%
1088% The format of the GetBlobFile method is:
1089%
1090% FILE *GetBlobFileHandle(const Image *image)
1091%
1092% A description of each parameter follows:
1093%
1094% o image: the image.
1095%
1096*/
1097MagickExport FILE *GetBlobFileHandle(const Image *image)
1098{
1099 assert(image != (const Image *) NULL);
1100 assert(image->signature == MagickSignature);
1101 return(image->blob->file);
1102}
1103
1104/*
1105%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1106% %
1107% %
1108% %
1109+ G e t B l o b I n f o %
1110% %
1111% %
1112% %
1113%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1114%
1115% GetBlobInfo() initializes the BlobInfo structure.
1116%
1117% The format of the GetBlobInfo method is:
1118%
1119% void GetBlobInfo(BlobInfo *blob_info)
1120%
1121% A description of each parameter follows:
1122%
1123% o blob_info: Specifies a pointer to a BlobInfo structure.
1124%
1125*/
1126MagickExport void GetBlobInfo(BlobInfo *blob_info)
1127{
1128 assert(blob_info != (BlobInfo *) NULL);
1129 (void) ResetMagickMemory(blob_info,0,sizeof(*blob_info));
1130 blob_info->type=UndefinedStream;
1131 blob_info->quantum=(size_t) MagickMaxBlobExtent;
1132 blob_info->properties.st_mtime=time((time_t *) NULL);
1133 blob_info->properties.st_ctime=time((time_t *) NULL);
1134 blob_info->debug=IsEventLogging();
1135 blob_info->reference_count=1;
1136 blob_info->semaphore=AllocateSemaphoreInfo();
1137 blob_info->signature=MagickSignature;
1138}
1139
1140/*
1141%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1142% %
1143% %
1144% %
1145% G e t B l o b P r o p e r t i e s %
1146% %
1147% %
1148% %
1149%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1150%
1151% GetBlobProperties() returns information about an image blob.
1152%
1153% The format of the GetBlobProperties method is:
1154%
1155% const struct stat *GetBlobProperties(const Image *image)
1156%
1157% A description of each parameter follows:
1158%
1159% o image: the image.
1160%
1161*/
1162MagickExport const struct stat *GetBlobProperties(const Image *image)
1163{
1164 assert(image != (Image *) NULL);
1165 assert(image->signature == MagickSignature);
1166 if (image->debug != MagickFalse)
1167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1168 return(&image->blob->properties);
1169}
1170
1171/*
1172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173% %
1174% %
1175% %
1176+ G e t B l o b S i z e %
1177% %
1178% %
1179% %
1180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181%
1182% GetBlobSize() returns the current length of the image file or blob; zero is
1183% returned if the size cannot be determined.
1184%
1185% The format of the GetBlobSize method is:
1186%
1187% MagickSizeType GetBlobSize(const Image *image)
1188%
1189% A description of each parameter follows:
1190%
1191% o image: the image.
1192%
1193*/
1194MagickExport MagickSizeType GetBlobSize(const Image *image)
1195{
1196 MagickSizeType
cristy81b8ce52010-02-05 01:53:17 +00001197 extent;
cristy3ed852e2009-09-05 21:47:34 +00001198
1199 assert(image != (Image *) NULL);
1200 assert(image->signature == MagickSignature);
1201 if (image->debug != MagickFalse)
1202 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1203 assert(image->blob != (BlobInfo *) NULL);
cristy81b8ce52010-02-05 01:53:17 +00001204 extent=0;
cristy3ed852e2009-09-05 21:47:34 +00001205 switch (image->blob->type)
1206 {
1207 case UndefinedStream:
1208 {
cristy81b8ce52010-02-05 01:53:17 +00001209 extent=image->blob->size;
cristy3ed852e2009-09-05 21:47:34 +00001210 break;
1211 }
1212 case FileStream:
1213 {
1214 if (fstat(fileno(image->blob->file),&image->blob->properties) == 0)
cristy81b8ce52010-02-05 01:53:17 +00001215 extent=(MagickSizeType) image->blob->properties.st_size;
cristy3ed852e2009-09-05 21:47:34 +00001216 break;
1217 }
1218 case StandardStream:
1219 case PipeStream:
1220 {
cristy81b8ce52010-02-05 01:53:17 +00001221 extent=image->blob->size;
cristy3ed852e2009-09-05 21:47:34 +00001222 break;
1223 }
1224 case ZipStream:
1225 case BZipStream:
1226 {
1227 MagickBooleanType
1228 status;
1229
1230 status=GetPathAttributes(image->filename,&image->blob->properties);
1231 if (status != MagickFalse)
cristy81b8ce52010-02-05 01:53:17 +00001232 extent=(MagickSizeType) image->blob->properties.st_size;
cristy3ed852e2009-09-05 21:47:34 +00001233 break;
1234 }
1235 case FifoStream:
1236 break;
1237 case BlobStream:
1238 {
cristy81b8ce52010-02-05 01:53:17 +00001239 extent=(MagickSizeType) image->blob->extent;
cristy3ed852e2009-09-05 21:47:34 +00001240 break;
1241 }
1242 }
cristy81b8ce52010-02-05 01:53:17 +00001243 return(extent);
cristy3ed852e2009-09-05 21:47:34 +00001244}
1245
1246/*
1247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248% %
1249% %
1250% %
1251+ G e t B l o b S t r e a m D a t a %
1252% %
1253% %
1254% %
1255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1256%
1257% GetBlobStreamData() returns the stream data for the image.
1258%
1259% The format of the GetBlobStreamData method is:
1260%
1261% unsigned char *GetBlobStreamData(const Image *image)
1262%
1263% A description of each parameter follows:
1264%
1265% o image: the image.
1266%
1267*/
1268MagickExport unsigned char *GetBlobStreamData(const Image *image)
1269{
1270 assert(image != (const Image *) NULL);
1271 assert(image->signature == MagickSignature);
1272 return(image->blob->data);
1273}
1274
1275/*
1276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1277% %
1278% %
1279% %
1280+ G e t B l o b S t r e a m H a n d l e r %
1281% %
1282% %
1283% %
1284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285%
1286% GetBlobStreamHandler() returns the stream handler for the image.
1287%
1288% The format of the GetBlobStreamHandler method is:
1289%
1290% StreamHandler GetBlobStreamHandler(const Image *image)
1291%
1292% A description of each parameter follows:
1293%
1294% o image: the image.
1295%
1296*/
1297MagickExport StreamHandler GetBlobStreamHandler(const Image *image)
1298{
1299 assert(image != (const Image *) NULL);
1300 assert(image->signature == MagickSignature);
1301 if (image->debug != MagickFalse)
1302 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1303 return(image->blob->stream);
1304}
1305
1306/*
1307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308% %
1309% %
1310% %
1311% I m a g e T o B l o b %
1312% %
1313% %
1314% %
1315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316%
1317% ImageToBlob() implements direct to memory image formats. It returns the
1318% image as a blob and its length. The magick member of the ImageInfo structure
1319% determines the format of the returned blob (GIF, JPEG, PNG, etc.)
1320%
1321% The format of the ImageToBlob method is:
1322%
1323% unsigned char *ImageToBlob(const ImageInfo *image_info,Image *image,
1324% size_t *length,ExceptionInfo *exception)
1325%
1326% A description of each parameter follows:
1327%
1328% o image_info: the image info.
1329%
1330% o image: the image.
1331%
1332% o length: This pointer to a size_t integer sets the initial length of the
1333% blob. On return, it reflects the actual length of the blob.
1334%
1335% o exception: return any errors or warnings in this structure.
1336%
1337*/
1338MagickExport unsigned char *ImageToBlob(const ImageInfo *image_info,
1339 Image *image,size_t *length,ExceptionInfo *exception)
1340{
1341 const MagickInfo
1342 *magick_info;
1343
1344 ImageInfo
1345 *blob_info;
1346
1347 MagickBooleanType
1348 status;
1349
1350 unsigned char
1351 *blob;
1352
1353 assert(image_info != (const ImageInfo *) NULL);
1354 assert(image_info->signature == MagickSignature);
1355 if (image_info->debug != MagickFalse)
1356 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1357 image_info->filename);
1358 assert(image != (Image *) NULL);
1359 assert(image->signature == MagickSignature);
1360 assert(exception != (ExceptionInfo *) NULL);
1361 *length=0;
1362 blob=(unsigned char *) NULL;
1363 blob_info=CloneImageInfo(image_info);
1364 blob_info->adjoin=MagickFalse;
1365 (void) SetImageInfo(blob_info,MagickTrue,exception);
1366 if (*blob_info->magick != '\0')
1367 (void) CopyMagickString(image->magick,blob_info->magick,MaxTextExtent);
1368 magick_info=GetMagickInfo(image->magick,exception);
1369 if (magick_info == (const MagickInfo *) NULL)
1370 {
1371 (void) ThrowMagickException(exception,GetMagickModule(),
1372 MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
1373 image->filename);
1374 return(blob);
1375 }
1376 (void) CopyMagickString(blob_info->magick,image->magick,MaxTextExtent);
1377 if (GetMagickBlobSupport(magick_info) != MagickFalse)
1378 {
1379 /*
1380 Native blob support for this image format.
1381 */
1382 blob_info->length=0;
1383 blob_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
1384 sizeof(unsigned char));
1385 if (blob_info->blob == (void *) NULL)
1386 (void) ThrowMagickException(exception,GetMagickModule(),
1387 ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1388 else
1389 {
1390 (void) CloseBlob(image);
1391 image->blob->exempt=MagickTrue;
1392 *image->filename='\0';
1393 status=WriteImage(blob_info,image);
1394 if ((status == MagickFalse) || (image->blob->length == 0))
1395 InheritException(exception,&image->exception);
1396 else
1397 {
1398 *length=image->blob->length;
1399 blob=DetachBlob(image->blob);
1400 blob=(unsigned char *) ResizeQuantumMemory(blob,*length,
1401 sizeof(*blob));
1402 }
1403 }
1404 }
1405 else
1406 {
1407 char
1408 unique[MaxTextExtent];
1409
1410 int
1411 file;
1412
1413 /*
1414 Write file to disk in blob image format.
1415 */
1416 file=AcquireUniqueFileResource(unique);
1417 if (file == -1)
1418 {
1419 ThrowFileException(exception,BlobError,"UnableToWriteBlob",
1420 image_info->filename);
1421 }
1422 else
1423 {
1424 blob_info->file=fdopen(file,"wb");
1425 if (blob_info->file != (FILE *) NULL)
1426 {
1427 (void) FormatMagickString(image->filename,MaxTextExtent,"%s:%s",
1428 image->magick,unique);
1429 status=WriteImage(blob_info,image);
1430 (void) fclose(blob_info->file);
1431 if (status == MagickFalse)
1432 InheritException(exception,&image->exception);
1433 else
1434 blob=FileToBlob(image->filename,~0UL,length,exception);
1435 }
1436 (void) RelinquishUniqueFileResource(unique);
1437 }
1438 }
1439 blob_info=DestroyImageInfo(blob_info);
1440 return(blob);
1441}
1442
1443/*
1444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1445% %
1446% %
1447% %
1448% I m a g e T o F i l e %
1449% %
1450% %
1451% %
1452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453%
1454% ImageToFile() writes an image to a file. It returns MagickFalse if an error
1455% occurs otherwise MagickTrue.
1456%
1457% The format of the ImageToFile method is:
1458%
1459% MagickBooleanType ImageToFile(Image *image,char *filename,
1460% ExceptionInfo *exception)
1461%
1462% A description of each parameter follows:
1463%
1464% o image: the image.
1465%
1466% o filename: Write the image to this file.
1467%
1468% o exception: return any errors or warnings in this structure.
1469%
1470*/
1471
1472static inline const unsigned char *ReadBlobStream(Image *image,
1473 const size_t length,unsigned char *data,ssize_t *count)
1474{
1475 assert(count != (ssize_t *) NULL);
1476 assert(image->blob != (BlobInfo *) NULL);
1477 if (image->blob->type != BlobStream)
1478 {
1479 *count=ReadBlob(image,length,data);
1480 return(data);
1481 }
1482 if (image->blob->offset >= (MagickOffsetType) image->blob->length)
1483 {
1484 *count=0;
1485 image->blob->eof=MagickTrue;
1486 return(data);
1487 }
1488 data=image->blob->data+image->blob->offset;
1489 *count=(ssize_t) MagickMin(length,(size_t) (image->blob->length-
1490 image->blob->offset));
1491 image->blob->offset+=(*count);
1492 if (*count != (ssize_t) length)
1493 image->blob->eof=MagickTrue;
1494 return(data);
1495}
1496
1497MagickExport MagickBooleanType ImageToFile(Image *image,char *filename,
1498 ExceptionInfo *exception)
1499{
1500 int
1501 file;
1502
1503 register const unsigned char
1504 *p;
1505
1506 register size_t
1507 i;
1508
1509 size_t
1510 length,
1511 quantum;
1512
1513 ssize_t
1514 count;
1515
1516 struct stat
1517 file_info;
1518
1519 unsigned char
1520 *buffer;
1521
1522 assert(image != (Image *) NULL);
1523 assert(image->signature == MagickSignature);
1524 assert(image->blob != (BlobInfo *) NULL);
1525 assert(image->blob->type != UndefinedStream);
1526 if (image->debug != MagickFalse)
1527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
1528 assert(filename != (const char *) NULL);
1529 if (*filename == '\0')
1530 file=AcquireUniqueFileResource(filename);
1531 else
1532 if (LocaleCompare(filename,"-") == 0)
1533 file=fileno(stdout);
1534 else
1535 file=open(filename,O_RDWR | O_CREAT | O_EXCL | O_BINARY,S_MODE);
1536 if (file == -1)
1537 {
1538 ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1539 return(MagickFalse);
1540 }
1541 quantum=(size_t) MagickMaxBufferExtent;
1542 if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
1543 quantum=MagickMin((size_t) file_info.st_size,MagickMaxBufferExtent);
1544 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
1545 if (buffer == (unsigned char *) NULL)
1546 {
1547 file=close(file)-1;
1548 (void) ThrowMagickException(exception,GetMagickModule(),
1549 ResourceLimitError,"MemoryAllocationError","`%s'",filename);
1550 return(MagickFalse);
1551 }
1552 length=0;
1553 p=ReadBlobStream(image,quantum,buffer,&count);
1554 for (i=0; count > 0; p=ReadBlobStream(image,quantum,buffer,&count))
1555 {
1556 length=(size_t) count;
1557 for (i=0; i < length; i+=count)
1558 {
1559 count=write(file,p+i,(size_t) (length-i));
1560 if (count <= 0)
1561 {
1562 count=0;
1563 if (errno != EINTR)
1564 break;
1565 }
1566 }
1567 if (i < length)
1568 break;
1569 }
1570 file=close(file)-1;
1571 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1572 if (i < length)
1573 {
1574 ThrowFileException(exception,BlobError,"UnableToWriteBlob",filename);
1575 return(MagickFalse);
1576 }
1577 return(MagickTrue);
1578}
1579
1580/*
1581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582% %
1583% %
1584% %
1585% I m a g e s T o B l o b %
1586% %
1587% %
1588% %
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590%
1591% ImagesToBlob() implements direct to memory image formats. It returns the
1592% image sequence as a blob and its length. The magick member of the ImageInfo
1593% structure determines the format of the returned blob (GIF, JPEG, PNG, etc.)
1594%
1595% Note, some image formats do not permit multiple images to the same image
1596% stream (e.g. JPEG). in this instance, just the first image of the
1597% sequence is returned as a blob.
1598%
1599% The format of the ImagesToBlob method is:
1600%
1601% unsigned char *ImagesToBlob(const ImageInfo *image_info,Image *images,
1602% size_t *length,ExceptionInfo *exception)
1603%
1604% A description of each parameter follows:
1605%
1606% o image_info: the image info.
1607%
1608% o images: the image list.
1609%
1610% o length: This pointer to a size_t integer sets the initial length of the
1611% blob. On return, it reflects the actual length of the blob.
1612%
1613% o exception: return any errors or warnings in this structure.
1614%
1615*/
1616MagickExport unsigned char *ImagesToBlob(const ImageInfo *image_info,
1617 Image *images,size_t *length,ExceptionInfo *exception)
1618{
1619 const MagickInfo
1620 *magick_info;
1621
1622 ImageInfo
1623 *blob_info;
1624
1625 MagickBooleanType
1626 status;
1627
1628 unsigned char
1629 *blob;
1630
1631 assert(image_info != (const ImageInfo *) NULL);
1632 assert(image_info->signature == MagickSignature);
1633 if (image_info->debug != MagickFalse)
1634 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1635 image_info->filename);
1636 assert(images != (Image *) NULL);
1637 assert(images->signature == MagickSignature);
1638 assert(exception != (ExceptionInfo *) NULL);
1639 *length=0;
1640 blob=(unsigned char *) NULL;
1641 blob_info=CloneImageInfo(image_info);
1642 (void) SetImageInfo(blob_info,MagickTrue,exception);
1643 if (*blob_info->magick != '\0')
1644 (void) CopyMagickString(images->magick,blob_info->magick,MaxTextExtent);
1645 if (blob_info->adjoin == MagickFalse)
1646 {
1647 blob_info=DestroyImageInfo(blob_info);
1648 return(ImageToBlob(image_info,images,length,exception));
1649 }
1650 magick_info=GetMagickInfo(images->magick,exception);
1651 if (magick_info == (const MagickInfo *) NULL)
1652 {
1653 (void) ThrowMagickException(exception,GetMagickModule(),
1654 MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
1655 images->filename);
1656 return(blob);
1657 }
1658 (void) CopyMagickString(blob_info->magick,images->magick,MaxTextExtent);
1659 if (GetMagickBlobSupport(magick_info) != MagickFalse)
1660 {
1661 /*
1662 Native blob support for this images format.
1663 */
1664 blob_info->length=0;
1665 blob_info->blob=(void *) AcquireQuantumMemory(MagickMaxBlobExtent,
1666 sizeof(unsigned char));
1667 if (blob_info->blob == (void *) NULL)
1668 (void) ThrowMagickException(exception,GetMagickModule(),
1669 ResourceLimitError,"MemoryAllocationFailed","`%s'",images->filename);
1670 else
1671 {
1672 images->blob->exempt=MagickTrue;
1673 *images->filename='\0';
1674 status=WriteImages(blob_info,images,images->filename,exception);
1675 if ((status == MagickFalse) || (images->blob->length == 0))
1676 InheritException(exception,&images->exception);
1677 else
1678 {
1679 *length=images->blob->length;
1680 blob=DetachBlob(images->blob);
1681 blob=(unsigned char *) ResizeQuantumMemory(blob,*length,
1682 sizeof(*blob));
1683 }
1684 }
1685 }
1686 else
1687 {
1688 char
1689 filename[MaxTextExtent],
1690 unique[MaxTextExtent];
1691
1692 int
1693 file;
1694
1695 /*
1696 Write file to disk in blob images format.
1697 */
1698 file=AcquireUniqueFileResource(unique);
1699 if (file == -1)
1700 {
1701 ThrowFileException(exception,FileOpenError,"UnableToWriteBlob",
1702 image_info->filename);
1703 }
1704 else
1705 {
1706 blob_info->file=fdopen(file,"wb");
1707 if (blob_info->file != (FILE *) NULL)
1708 {
1709 (void) FormatMagickString(filename,MaxTextExtent,"%s:%s",
1710 images->magick,unique);
1711 status=WriteImages(blob_info,images,filename,exception);
1712 (void) fclose(blob_info->file);
1713 if (status == MagickFalse)
1714 InheritException(exception,&images->exception);
1715 else
1716 blob=FileToBlob(images->filename,~0UL,length,exception);
1717 }
1718 (void) RelinquishUniqueFileResource(unique);
1719 }
1720 }
1721 blob_info=DestroyImageInfo(blob_info);
1722 return(blob);
1723}
1724/*
1725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1726% %
1727% %
1728% %
1729% I n j e c t I m a g e B l o b %
1730% %
1731% %
1732% %
1733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734%
1735% InjectImageBlob() injects the image with a copy of itself in the specified
1736% format (e.g. inject JPEG into a PDF image).
1737%
1738% The format of the InjectImageBlob method is:
1739%
1740% MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
1741% Image *image,Image *inject_image,const char *format,
1742% ExceptionInfo *exception)
1743%
1744% A description of each parameter follows:
1745%
1746% o image_info: the image info..
1747%
1748% o image: the image.
1749%
1750% o inject_image: inject into the image stream.
1751%
1752% o format: the image format.
1753%
1754% o exception: return any errors or warnings in this structure.
1755%
1756*/
1757MagickExport MagickBooleanType InjectImageBlob(const ImageInfo *image_info,
1758 Image *image,Image *inject_image,const char *format,ExceptionInfo *exception)
1759{
1760 char
1761 filename[MaxTextExtent];
1762
1763 FILE
1764 *unique_file;
1765
1766 Image
1767 *byte_image;
1768
1769 ImageInfo
1770 *write_info;
1771
1772 int
1773 file;
1774
1775 MagickBooleanType
1776 status;
1777
1778 register long
1779 i;
1780
1781 size_t
1782 quantum;
1783
1784 ssize_t
1785 count;
1786
1787 struct stat
1788 file_info;
1789
1790 unsigned char
1791 *buffer;
1792
1793 /*
1794 Write inject image to a temporary file.
1795 */
1796 assert(image_info != (ImageInfo *) NULL);
1797 assert(image_info->signature == MagickSignature);
1798 assert(image != (Image *) NULL);
1799 assert(image->signature == MagickSignature);
1800 if (image->debug != MagickFalse)
1801 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1802 assert(inject_image != (Image *) NULL);
1803 assert(inject_image->signature == MagickSignature);
1804 assert(exception != (ExceptionInfo *) NULL);
1805 unique_file=(FILE *) NULL;
1806 file=AcquireUniqueFileResource(filename);
1807 if (file != -1)
1808 unique_file=fdopen(file,"wb");
1809 if ((file == -1) || (unique_file == (FILE *) NULL))
1810 {
1811 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
1812 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
1813 image->filename);
1814 return(MagickFalse);
1815 }
1816 byte_image=CloneImage(inject_image,0,0,MagickFalse,exception);
1817 if (byte_image == (Image *) NULL)
1818 {
1819 (void) fclose(unique_file);
1820 (void) RelinquishUniqueFileResource(filename);
1821 return(MagickFalse);
1822 }
1823 (void) FormatMagickString(byte_image->filename,MaxTextExtent,"%s:%s",format,
1824 filename);
1825 DestroyBlob(byte_image);
1826 byte_image->blob=CloneBlobInfo((BlobInfo *) NULL);
1827 write_info=CloneImageInfo(image_info);
1828 SetImageInfoFile(write_info,unique_file);
1829 status=WriteImage(write_info,byte_image);
1830 write_info=DestroyImageInfo(write_info);
1831 byte_image=DestroyImage(byte_image);
1832 (void) fclose(unique_file);
1833 if (status == MagickFalse)
1834 {
1835 (void) RelinquishUniqueFileResource(filename);
1836 return(MagickFalse);
1837 }
1838 /*
1839 Inject into image stream.
1840 */
1841 file=open(filename,O_RDONLY | O_BINARY);
1842 if (file == -1)
1843 {
1844 (void) RelinquishUniqueFileResource(filename);
1845 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1846 image_info->filename);
1847 return(MagickFalse);
1848 }
1849 quantum=(size_t) MagickMaxBufferExtent;
1850 if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
1851 quantum=MagickMin((size_t) file_info.st_size,MagickMaxBufferExtent);
1852 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
1853 if (buffer == (unsigned char *) NULL)
1854 {
1855 (void) RelinquishUniqueFileResource(filename);
1856 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1857 image->filename);
1858 }
1859 for (i=0; ; i+=count)
1860 {
1861 count=(ssize_t) read(file,buffer,quantum);
1862 if (count <= 0)
1863 {
1864 count=0;
1865 if (errno != EINTR)
1866 break;
1867 }
1868 status=WriteBlobStream(image,(size_t) count,buffer) == count ? MagickTrue :
1869 MagickFalse;
1870 }
1871 file=close(file)-1;
1872 (void) RelinquishUniqueFileResource(filename);
1873 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1874 return(status);
1875}
1876
1877/*
1878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1879% %
1880% %
1881% %
1882+ I s B l o b E x e m p t %
1883% %
1884% %
1885% %
1886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1887%
1888% IsBlobExempt() returns true if the blob is exempt.
1889%
1890% The format of the IsBlobExempt method is:
1891%
1892% MagickBooleanType IsBlobExempt(const Image *image)
1893%
1894% A description of each parameter follows:
1895%
1896% o image: the image.
1897%
1898*/
1899MagickExport MagickBooleanType IsBlobExempt(const Image *image)
1900{
1901 assert(image != (const Image *) NULL);
1902 assert(image->signature == MagickSignature);
1903 if (image->debug != MagickFalse)
1904 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1905 return(image->blob->exempt);
1906}
1907
1908/*
1909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910% %
1911% %
1912% %
1913+ I s B l o b S e e k a b l e %
1914% %
1915% %
1916% %
1917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1918%
1919% IsBlobSeekable() returns true if the blob is seekable.
1920%
1921% The format of the IsBlobSeekable method is:
1922%
1923% MagickBooleanType IsBlobSeekable(const Image *image)
1924%
1925% A description of each parameter follows:
1926%
1927% o image: the image.
1928%
1929*/
1930MagickExport MagickBooleanType IsBlobSeekable(const Image *image)
1931{
1932 MagickBooleanType
1933 seekable;
1934
1935 assert(image != (const Image *) NULL);
1936 assert(image->signature == MagickSignature);
1937 if (image->debug != MagickFalse)
1938 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1939 seekable=(image->blob->type == FileStream) ||
1940 (image->blob->type == BlobStream) ? MagickTrue : MagickFalse;
1941 return(seekable);
1942}
1943
1944/*
1945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946% %
1947% %
1948% %
1949+ I s B l o b T e m p o r a r y %
1950% %
1951% %
1952% %
1953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1954%
1955% IsBlobTemporary() returns true if the blob is temporary.
1956%
1957% The format of the IsBlobTemporary method is:
1958%
1959% MagickBooleanType IsBlobTemporary(const Image *image)
1960%
1961% A description of each parameter follows:
1962%
1963% o image: the image.
1964%
1965*/
1966MagickExport MagickBooleanType IsBlobTemporary(const Image *image)
1967{
1968 assert(image != (const Image *) NULL);
1969 assert(image->signature == MagickSignature);
1970 if (image->debug != MagickFalse)
1971 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1972 return(image->blob->temporary);
1973}
1974
1975/*
1976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977% %
1978% %
1979% %
1980+ M a p B l o b %
1981% %
1982% %
1983% %
1984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1985%
1986% MapBlob() creates a mapping from a file to a binary large object.
1987%
1988% The format of the MapBlob method is:
1989%
1990% unsigned char *MapBlob(int file,const MapMode mode,
1991% const MagickOffsetType offset,const size_t length)
1992%
1993% A description of each parameter follows:
1994%
1995% o file: map this file descriptor.
1996%
1997% o mode: ReadMode, WriteMode, or IOMode.
1998%
1999% o offset: starting at this offset within the file.
2000%
2001% o length: the length of the mapping is returned in this pointer.
2002%
2003*/
2004MagickExport unsigned char *MapBlob(int file,const MapMode mode,
2005 const MagickOffsetType offset,const size_t length)
2006{
2007#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
2008 int
2009 flags,
2010 protection;
2011
2012 unsigned char
2013 *map;
2014
2015 /*
2016 Map file.
2017 */
2018 flags=0;
2019 if (file == -1)
2020#if defined(MAP_ANONYMOUS)
2021 flags|=MAP_ANONYMOUS;
2022#else
2023 return((unsigned char *) NULL);
2024#endif
2025 switch (mode)
2026 {
2027 case ReadMode:
2028 default:
2029 {
2030 protection=PROT_READ;
2031 flags|=MAP_PRIVATE;
2032 map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
2033 (off_t) offset);
2034 break;
2035 }
2036 case WriteMode:
2037 {
2038 protection=PROT_WRITE;
2039 flags|=MAP_SHARED;
2040 map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
2041 (off_t) offset);
2042 break;
2043 }
2044 case IOMode:
2045 {
2046 protection=PROT_READ | PROT_WRITE;
2047 flags|=MAP_SHARED;
2048 map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
2049 (off_t) offset);
2050 break;
2051 }
2052 }
2053 if (map == (unsigned char *) MAP_FAILED)
2054 return((unsigned char *) NULL);
2055 return(map);
2056#else
2057 (void) file;
2058 (void) mode;
2059 (void) offset;
2060 (void) length;
2061 return((unsigned char *) NULL);
2062#endif
2063}
2064
2065/*
2066%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2067% %
2068% %
2069% %
2070+ M S B O r d e r L o n g %
2071% %
2072% %
2073% %
2074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2075%
2076% MSBOrderLong() converts a least-significant byte first buffer of integers to
2077% most-significant byte first.
2078%
2079% The format of the MSBOrderLong method is:
2080%
2081% void MSBOrderLong(unsigned char *buffer,const size_t length)
2082%
2083% A description of each parameter follows.
2084%
2085% o buffer: Specifies a pointer to a buffer of integers.
2086%
2087% o length: Specifies the length of the buffer.
2088%
2089*/
2090MagickExport void MSBOrderLong(unsigned char *buffer,const size_t length)
2091{
2092 int
2093 c;
2094
2095 register unsigned char
2096 *p,
2097 *q;
2098
2099 assert(buffer != (unsigned char *) NULL);
2100 q=buffer+length;
2101 while (buffer < q)
2102 {
2103 p=buffer+3;
2104 c=(int) (*p);
2105 *p=(*buffer);
2106 *buffer++=(unsigned char) c;
2107 p=buffer+1;
2108 c=(int) (*p);
2109 *p=(*buffer);
2110 *buffer++=(unsigned char) c;
2111 buffer+=2;
2112 }
2113}
2114
2115/*
2116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2117% %
2118% %
2119% %
2120+ M S B O r d e r S h o r t %
2121% %
2122% %
2123% %
2124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125%
2126% MSBOrderShort() converts a least-significant byte first buffer of integers
2127% to most-significant byte first.
2128%
2129% The format of the MSBOrderShort method is:
2130%
2131% void MSBOrderShort(unsigned char *p,const size_t length)
2132%
2133% A description of each parameter follows.
2134%
2135% o p: Specifies a pointer to a buffer of integers.
2136%
2137% o length: Specifies the length of the buffer.
2138%
2139*/
2140MagickExport void MSBOrderShort(unsigned char *p,const size_t length)
2141{
2142 int
2143 c;
2144
2145 register unsigned char
2146 *q;
2147
2148 assert(p != (unsigned char *) NULL);
2149 q=p+length;
2150 while (p < q)
2151 {
2152 c=(int) (*p);
2153 *p=(*(p+1));
2154 p++;
2155 *p++=(unsigned char) c;
2156 }
2157}
2158
2159/*
2160%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2161% %
2162% %
2163% %
2164+ O p e n B l o b %
2165% %
2166% %
2167% %
2168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2169%
2170% OpenBlob() opens a file associated with the image. A file name of '-' sets
2171% the file to stdin for type 'r' and stdout for type 'w'. If the filename
2172% suffix is '.gz' or '.Z', the image is decompressed for type 'r' and
2173% compressed for type 'w'. If the filename prefix is '|', it is piped to or
2174% from a system command.
2175%
2176% The format of the OpenBlob method is:
2177%
2178% MagickBooleanType OpenBlob(const ImageInfo *image_info,Image *image,
2179% const BlobMode mode,ExceptionInfo *exception)
2180%
2181% A description of each parameter follows:
2182%
2183% o image_info: the image info.
2184%
2185% o image: the image.
2186%
2187% o mode: the mode for opening the file.
2188%
2189*/
2190MagickExport MagickBooleanType OpenBlob(const ImageInfo *image_info,
2191 Image *image,const BlobMode mode,ExceptionInfo *exception)
2192{
2193 char
2194 filename[MaxTextExtent];
2195
2196 const char
2197 *type;
2198
2199 MagickBooleanType
2200 status;
2201
2202 PolicyRights
2203 rights;
2204
2205 assert(image_info != (ImageInfo *) NULL);
2206 assert(image_info->signature == MagickSignature);
2207 if (image_info->debug != MagickFalse)
2208 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2209 image_info->filename);
2210 assert(image != (Image *) NULL);
2211 assert(image->signature == MagickSignature);
2212 if (image_info->blob != (void *) NULL)
2213 {
2214 if (image_info->stream != (StreamHandler) NULL)
2215 image->blob->stream=(StreamHandler) image_info->stream;
2216 AttachBlob(image->blob,image_info->blob,image_info->length);
2217 return(MagickTrue);
2218 }
2219 (void) DetachBlob(image->blob);
2220 switch (mode)
2221 {
2222 default: type="r"; break;
2223 case ReadBlobMode: type="r"; break;
2224 case ReadBinaryBlobMode: type="rb"; break;
2225 case WriteBlobMode: type="w"; break;
2226 case WriteBinaryBlobMode: type="w+b"; break;
2227 case AppendBlobMode: type="a"; break;
2228 case AppendBinaryBlobMode: type="a+b"; break;
2229 }
2230 if (*type != 'r')
2231 image->blob->synchronize=image_info->synchronize;
2232 if (image_info->stream != (StreamHandler) NULL)
2233 {
2234 image->blob->stream=(StreamHandler) image_info->stream;
2235 if (*type == 'w')
2236 {
2237 image->blob->type=FifoStream;
2238 return(MagickTrue);
2239 }
2240 }
2241 /*
2242 Open image file.
2243 */
2244 *filename='\0';
2245 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
2246 rights=ReadPolicyRights;
2247 if (*type == 'w')
2248 rights=WritePolicyRights;
2249 if (IsRightsAuthorized(PathPolicyDomain,rights,filename) == MagickFalse)
2250 {
cristya9197f62010-01-12 02:23:34 +00002251 errno=EPERM;
cristy3ed852e2009-09-05 21:47:34 +00002252 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
2253 "NotAuthorized","`%s'",filename);
2254 return(MagickFalse);
2255 }
2256 if ((LocaleCompare(filename,"-") == 0) ||
2257 ((*filename == '\0') && (image_info->file == (FILE *) NULL)))
2258 {
2259 image->blob->file=(*type == 'r') ? stdin : stdout;
2260#if defined(__WINDOWS__) || defined(__OS2__)
2261 if (strchr(type,'b') != (char *) NULL)
2262 setmode(_fileno(image->blob->file),_O_BINARY);
2263#endif
2264 image->blob->type=StandardStream;
2265 image->blob->exempt=MagickTrue;
2266 return(MagickTrue);
2267 }
2268 if (LocaleNCompare(filename,"fd:",3) == 0)
2269 {
2270 char
2271 mode[MaxTextExtent];
2272
2273 *mode=(*type);
2274 mode[1]='\0';
cristyf2f27272009-12-17 14:48:46 +00002275 image->blob->file=fdopen(StringToLong(filename+3),mode);
cristy3ed852e2009-09-05 21:47:34 +00002276#if defined(__WINDOWS__) || defined(__OS2__)
2277 if (strchr(type,'b') != (char *) NULL)
2278 setmode(_fileno(image->blob->file),_O_BINARY);
2279#endif
2280 image->blob->type=StandardStream;
2281 image->blob->exempt=MagickTrue;
2282 return(MagickTrue);
2283 }
2284#if defined(MAGICKCORE_HAVE_POPEN)
2285 if (*filename == '|')
2286 {
2287 char
2288 mode[MaxTextExtent];
2289
2290 /*
2291 Pipe image to or from a system command.
2292 */
2293#if defined(SIGPIPE)
2294 if (*type == 'w')
2295 (void) signal(SIGPIPE,SIG_IGN);
2296#endif
2297 *mode=(*type);
2298 mode[1]='\0';
2299 image->blob->file=(FILE *) popen(filename+1,mode);
2300 if (image->blob->file == (FILE *) NULL)
2301 {
2302 ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
2303 return(MagickFalse);
2304 }
2305 image->blob->type=PipeStream;
2306 image->blob->exempt=MagickTrue;
2307 return(MagickTrue);
2308 }
2309#endif
2310 status=GetPathAttributes(filename,&image->blob->properties);
2311#if defined(S_ISFIFO)
2312 if ((status == MagickTrue) && S_ISFIFO(image->blob->properties.st_mode))
2313 {
2314 image->blob->file=(FILE *) OpenMagickStream(filename,type);
2315 if (image->blob->file == (FILE *) NULL)
2316 {
2317 ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
2318 return(MagickFalse);
2319 }
2320 image->blob->type=FileStream;
2321 image->blob->exempt=MagickTrue;
2322 return(MagickTrue);
2323 }
2324#endif
2325 if (*type == 'w')
2326 {
cristye8939e72010-02-03 17:05:25 +00002327 (void) CopyMagickString(filename,image->filename,MaxTextExtent);
cristy40a08ad2010-02-09 02:27:44 +00002328 if (image_info->adjoin == MagickFalse)
cristye8939e72010-02-03 17:05:25 +00002329 {
2330 /*
2331 Form filename for multi-part images.
2332 */
2333 (void) InterpretImageFilename(image_info,image,image->filename,(int)
2334 image->scene,filename);
cristybf7fa0d2010-02-04 00:51:10 +00002335 if (LocaleCompare(filename,image->filename) == 0)
cristye8939e72010-02-03 17:05:25 +00002336 {
cristybf7fa0d2010-02-04 00:51:10 +00002337 char
2338 extension[MaxTextExtent],
2339 path[MaxTextExtent];
cristy3ed852e2009-09-05 21:47:34 +00002340
cristybf7fa0d2010-02-04 00:51:10 +00002341 GetPathComponent(image->filename,RootPath,path);
2342 GetPathComponent(image->filename,ExtensionPath,extension);
2343 if (*extension == '\0')
2344 (void) FormatMagickString(filename,MaxTextExtent,"%s-%lu",
2345 path,image->scene);
2346 else
2347 (void) FormatMagickString(filename,MaxTextExtent,
2348 "%s-%lu.%s",path,image->scene,extension);
cristye8939e72010-02-03 17:05:25 +00002349 }
2350 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00002351#if defined(macintosh)
cristye8939e72010-02-03 17:05:25 +00002352 SetApplicationType(filename,image_info->magick,'8BIM');
cristy3ed852e2009-09-05 21:47:34 +00002353#endif
cristye8939e72010-02-03 17:05:25 +00002354 }
cristy3ed852e2009-09-05 21:47:34 +00002355 }
2356#if defined(MAGICKCORE_ZLIB_DELEGATE)
2357 if (((strlen(filename) > 2) &&
2358 (LocaleCompare(filename+strlen(filename)-2,".Z") == 0)) ||
2359 ((strlen(filename) > 3) &&
2360 (LocaleCompare(filename+strlen(filename)-3,".gz") == 0)) ||
2361 ((strlen(filename) > 4) &&
2362 (LocaleCompare(filename+strlen(filename)-4,".wmz") == 0)) ||
2363 ((strlen(filename) > 5) &&
2364 (LocaleCompare(filename+strlen(filename)-5,".svgz") == 0)))
2365 {
2366 image->blob->file=(FILE *) gzopen(filename,type);
2367 if (image->blob->file != (FILE *) NULL)
2368 image->blob->type=ZipStream;
2369 }
2370 else
2371#endif
2372#if defined(MAGICKCORE_BZLIB_DELEGATE)
2373 if ((strlen(filename) > 4) &&
2374 (LocaleCompare(filename+strlen(filename)-4,".bz2") == 0))
2375 {
2376 image->blob->file=(FILE *) BZ2_bzopen(filename,type);
2377 if (image->blob->file != (FILE *) NULL)
2378 image->blob->type=BZipStream;
2379 }
2380 else
2381#endif
2382 if (image_info->file != (FILE *) NULL)
2383 {
2384 image->blob->file=image_info->file;
2385 image->blob->type=FileStream;
2386 image->blob->exempt=MagickTrue;
2387 }
2388 else
2389 {
2390 image->blob->file=(FILE *) OpenMagickStream(filename,type);
2391 if (image->blob->file != (FILE *) NULL)
2392 {
2393 image->blob->type=FileStream;
2394#if defined(MAGICKCORE_HAVE_SETVBUF)
2395 (void) setvbuf(image->blob->file,(char *) NULL,(int) _IOFBF,
2396 16384);
2397#endif
2398 if (*type == 'r')
2399 {
2400 size_t
2401 count;
2402
2403 unsigned char
2404 magick[3];
2405
2406 (void) ResetMagickMemory(magick,0,sizeof(magick));
2407 count=fread(magick,1,sizeof(magick),image->blob->file);
2408 (void) rewind(image->blob->file);
2409 (void) LogMagickEvent(BlobEvent,GetMagickModule(),
2410 " read %ld magic header bytes",(long) count);
2411#if defined(MAGICKCORE_ZLIB_DELEGATE)
2412 if (((int) magick[0] == 0x1F) && ((int) magick[1] == 0x8B) &&
2413 ((int) magick[2] == 0x08))
2414 {
2415 (void) fclose(image->blob->file);
2416 image->blob->file=(FILE *) gzopen(filename,type);
2417 if (image->blob->file != (FILE *) NULL)
2418 image->blob->type=ZipStream;
2419 }
2420#endif
2421#if defined(MAGICKCORE_BZLIB_DELEGATE)
2422 if (strncmp((char *) magick,"BZh",3) == 0)
2423 {
2424 (void) fclose(image->blob->file);
2425 image->blob->file=(FILE *) BZ2_bzopen(filename,type);
2426 if (image->blob->file != (FILE *) NULL)
2427 image->blob->type=BZipStream;
2428 }
2429#endif
2430 }
2431 }
2432 }
2433 if ((image->blob->type == FileStream) && (*type == 'r'))
2434 {
2435 const MagickInfo
2436 *magick_info;
2437
2438 ExceptionInfo
2439 *sans_exception;
2440
2441 struct stat
2442 *properties;
2443
2444 sans_exception=AcquireExceptionInfo();
2445 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2446 sans_exception=DestroyExceptionInfo(sans_exception);
2447 properties=(&image->blob->properties);
2448 if ((magick_info != (const MagickInfo *) NULL) &&
2449 (GetMagickBlobSupport(magick_info) != MagickFalse) &&
2450 (properties->st_size <= MagickMaxBufferExtent))
2451 {
2452 size_t
2453 length;
2454
2455 void
2456 *blob;
2457
2458 length=(size_t) properties->st_size;
2459 blob=MapBlob(fileno(image->blob->file),ReadMode,0,length);
2460 if (blob != (void *) NULL)
2461 {
2462 /*
2463 Format supports blobs-- use memory-mapped I/O.
2464 */
2465 if (image_info->file != (FILE *) NULL)
2466 image->blob->exempt=MagickFalse;
2467 else
2468 {
2469 (void) fclose(image->blob->file);
2470 image->blob->file=(FILE *) NULL;
2471 }
2472 AttachBlob(image->blob,blob,length);
2473 image->blob->mapped=MagickTrue;
2474 }
2475 }
2476 }
2477 image->blob->status=MagickFalse;
2478 if (image->blob->type != UndefinedStream)
2479 image->blob->size=GetBlobSize(image);
2480 else
2481 {
2482 ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
2483 return(MagickFalse);
2484 }
2485 return(MagickTrue);
2486}
2487
2488/*
2489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2490% %
2491% %
2492% %
2493+ P i n g B l o b %
2494% %
2495% %
2496% %
2497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498%
2499% PingBlob() returns all the attributes of an image or image sequence except
2500% for the pixels. It is much faster and consumes far less memory than
2501% BlobToImage(). On failure, a NULL image is returned and exception
2502% describes the reason for the failure.
2503%
2504% The format of the PingBlob method is:
2505%
2506% Image *PingBlob(const ImageInfo *image_info,const void *blob,
2507% const size_t length,ExceptionInfo *exception)
2508%
2509% A description of each parameter follows:
2510%
2511% o image_info: the image info.
2512%
2513% o blob: the address of a character stream in one of the image formats
2514% understood by ImageMagick.
2515%
2516% o length: This size_t integer reflects the length in bytes of the blob.
2517%
2518% o exception: return any errors or warnings in this structure.
2519%
2520*/
2521
2522#if defined(__cplusplus) || defined(c_plusplus)
2523extern "C" {
2524#endif
2525
2526static size_t PingStream(const Image *magick_unused(image),
2527 const void *magick_unused(pixels),const size_t columns)
2528{
2529 return(columns);
2530}
2531
2532#if defined(__cplusplus) || defined(c_plusplus)
2533}
2534#endif
2535
2536MagickExport Image *PingBlob(const ImageInfo *image_info,const void *blob,
2537 const size_t length,ExceptionInfo *exception)
2538{
2539 Image
2540 *image;
2541
2542 ImageInfo
2543 *ping_info;
2544
2545 assert(image_info != (ImageInfo *) NULL);
2546 assert(image_info->signature == MagickSignature);
2547 if (image_info->debug != MagickFalse)
2548 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2549 image_info->filename);
2550 assert(exception != (ExceptionInfo *) NULL);
2551 if ((blob == (const void *) NULL) || (length == 0))
2552 {
2553 (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
2554 "UnrecognizedImageFormat","`%s'",image_info->magick);
2555 return((Image *) NULL);
2556 }
2557 ping_info=CloneImageInfo(image_info);
2558 ping_info->blob=(void *) AcquireQuantumMemory(length,sizeof(unsigned char));
2559 if (ping_info->blob == (const void *) NULL)
2560 {
2561 (void) ThrowMagickException(exception,GetMagickModule(),
2562 ResourceLimitFatalError,"MemoryAllocationFailed","`%s'","");
2563 return((Image *) NULL);
2564 }
2565 (void) CopyMagickMemory(ping_info->blob,blob,length);
2566 ping_info->length=length;
2567 ping_info->ping=MagickTrue;
2568 image=ReadStream(ping_info,&PingStream,exception);
2569 ping_info->blob=(void *) RelinquishMagickMemory(ping_info->blob);
2570 ping_info=DestroyImageInfo(ping_info);
2571 return(image);
2572}
2573
2574/*
2575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2576% %
2577% %
2578% %
2579+ R e a d B l o b %
2580% %
2581% %
2582% %
2583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584%
2585% ReadBlob() reads data from the blob or image file and returns it. It
2586% returns the number of bytes read.
2587%
2588% The format of the ReadBlob method is:
2589%
2590% ssize_t ReadBlob(Image *image,const size_t length,unsigned char *data)
2591%
2592% A description of each parameter follows:
2593%
2594% o image: the image.
2595%
2596% o length: Specifies an integer representing the number of bytes to read
2597% from the file.
2598%
2599% o data: Specifies an area to place the information requested from the
2600% file.
2601%
2602*/
2603MagickExport ssize_t ReadBlob(Image *image,const size_t length,
2604 unsigned char *data)
2605{
2606 int
2607 c;
2608
2609 register unsigned char
2610 *q;
2611
2612 ssize_t
2613 count;
2614
2615 assert(image != (Image *) NULL);
2616 assert(image->signature == MagickSignature);
2617 assert(image->blob != (BlobInfo *) NULL);
2618 assert(image->blob->type != UndefinedStream);
2619 if (length == 0)
2620 return(0);
2621 assert(data != (void *) NULL);
2622 count=0;
2623 q=data;
2624 switch (image->blob->type)
2625 {
2626 case UndefinedStream:
2627 break;
2628 case FileStream:
2629 case StandardStream:
2630 case PipeStream:
2631 {
2632 switch (length)
2633 {
2634 default:
2635 {
2636 count=(ssize_t) fread(q,1,length,image->blob->file);
2637 break;
2638 }
2639 case 2:
2640 {
2641 c=getc(image->blob->file);
2642 if (c == EOF)
2643 break;
2644 *q++=(unsigned char) c;
2645 count++;
2646 }
2647 case 1:
2648 {
2649 c=getc(image->blob->file);
2650 if (c == EOF)
2651 break;
2652 *q++=(unsigned char) c;
2653 count++;
2654 }
2655 case 0:
2656 break;
2657 }
2658 break;
2659 }
2660 case ZipStream:
2661 {
2662#if defined(MAGICKCORE_ZLIB_DELEGATE)
2663 switch (length)
2664 {
2665 default:
2666 {
2667 count=(ssize_t) gzread(image->blob->file,q,(unsigned int) length);
2668 break;
2669 }
2670 case 2:
2671 {
2672 c=gzgetc(image->blob->file);
2673 if (c == EOF)
2674 break;
2675 *q++=(unsigned char) c;
2676 count++;
2677 }
2678 case 1:
2679 {
2680 c=gzgetc(image->blob->file);
2681 if (c == EOF)
2682 break;
2683 *q++=(unsigned char) c;
2684 count++;
2685 }
2686 case 0:
2687 break;
2688 }
2689#endif
2690 break;
2691 }
2692 case BZipStream:
2693 {
2694#if defined(MAGICKCORE_BZLIB_DELEGATE)
2695 count=(ssize_t) BZ2_bzread((BZFILE *) image->blob->file,q,(int) length);
2696#endif
2697 break;
2698 }
2699 case FifoStream:
2700 break;
2701 case BlobStream:
2702 {
2703 register const unsigned char
2704 *p;
2705
2706 if (image->blob->offset >= (MagickOffsetType) image->blob->length)
2707 {
2708 image->blob->eof=MagickTrue;
2709 break;
2710 }
2711 p=image->blob->data+image->blob->offset;
2712 count=(ssize_t) MagickMin(length,(size_t) (image->blob->length-
2713 image->blob->offset));
2714 image->blob->offset+=count;
2715 if (count != (ssize_t) length)
2716 image->blob->eof=MagickTrue;
2717 (void) CopyMagickMemory(q,p,(size_t) count);
2718 break;
2719 }
2720 }
2721 return(count);
2722}
2723
2724/*
2725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2726% %
2727% %
2728% %
2729+ R e a d B l o b B y t e %
2730% %
2731% %
2732% %
2733%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2734%
2735% ReadBlobByte() reads a single byte from the image file and returns it.
2736%
2737% The format of the ReadBlobByte method is:
2738%
2739% int ReadBlobByte(Image *image)
2740%
2741% A description of each parameter follows.
2742%
2743% o image: the image.
2744%
2745*/
2746MagickExport int ReadBlobByte(Image *image)
2747{
2748 register const unsigned char
2749 *p;
2750
2751 ssize_t
2752 count;
2753
2754 unsigned char
2755 buffer[1];
2756
2757 assert(image != (Image *) NULL);
2758 assert(image->signature == MagickSignature);
2759 p=ReadBlobStream(image,1,buffer,&count);
2760 if (count != 1)
2761 return(EOF);
2762 return((int) (*p));
2763}
2764
2765/*
2766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2767% %
2768% %
2769% %
2770+ R e a d B l o b D o u b l e %
2771% %
2772% %
2773% %
2774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2775%
2776% ReadBlobDouble() reads a double value as a 64-bit quantity in the byte-order
2777% specified by the endian member of the image structure.
2778%
2779% The format of the ReadBlobDouble method is:
2780%
2781% double ReadBlobDouble(Image *image)
2782%
2783% A description of each parameter follows.
2784%
2785% o image: the image.
2786%
2787*/
2788MagickExport double ReadBlobDouble(Image *image)
2789{
2790 union
2791 {
2792 MagickSizeType
2793 unsigned_value;
2794
2795 double
2796 double_value;
2797 } quantum;
2798
2799 quantum.double_value=0.0;
2800 quantum.unsigned_value=ReadBlobLongLong(image);
2801 return(quantum.double_value);
2802}
2803
2804/*
2805%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806% %
2807% %
2808% %
2809+ R e a d B l o b F l o a t %
2810% %
2811% %
2812% %
2813%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2814%
2815% ReadBlobFloat() reads a float value as a 32-bit quantity in the byte-order
2816% specified by the endian member of the image structure.
2817%
2818% The format of the ReadBlobFloat method is:
2819%
2820% float ReadBlobFloat(Image *image)
2821%
2822% A description of each parameter follows.
2823%
2824% o image: the image.
2825%
2826*/
2827MagickExport float ReadBlobFloat(Image *image)
2828{
2829 union
2830 {
2831 unsigned int
2832 unsigned_value;
2833
2834 float
2835 float_value;
2836 } quantum;
2837
2838 quantum.float_value=0.0;
2839 quantum.unsigned_value=ReadBlobLong(image);
2840 return(quantum.float_value);
2841}
2842
2843/*
2844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2845% %
2846% %
2847% %
2848+ R e a d B l o b L o n g %
2849% %
2850% %
2851% %
2852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853%
2854% ReadBlobLong() reads a long value as a 32-bit quantity in the byte-order
2855% specified by the endian member of the image structure.
2856%
2857% The format of the ReadBlobLong method is:
2858%
2859% unsigned int ReadBlobLong(Image *image)
2860%
2861% A description of each parameter follows.
2862%
2863% o image: the image.
2864%
2865*/
2866MagickExport unsigned int ReadBlobLong(Image *image)
2867{
2868 register const unsigned char
2869 *p;
2870
2871 ssize_t
2872 count;
2873
2874 unsigned char
2875 buffer[4];
2876
2877 unsigned int
2878 value;
2879
2880 assert(image != (Image *) NULL);
2881 assert(image->signature == MagickSignature);
2882 *buffer='\0';
2883 p=ReadBlobStream(image,4,buffer,&count);
2884 if (count != 4)
2885 return(0UL);
2886 if (image->endian == LSBEndian)
2887 {
2888 value=(unsigned int) (*p++);
2889 value|=((unsigned int) (*p++)) << 8;
2890 value|=((unsigned int) (*p++)) << 16;
2891 value|=((unsigned int) (*p++)) << 24;
2892 return(value);
2893 }
2894 value=((unsigned int) (*p++)) << 24;
2895 value|=((unsigned int) (*p++)) << 16;
2896 value|=((unsigned int) (*p++)) << 8;
2897 value|=((unsigned int) (*p++));
2898 return(value);
2899}
2900
2901/*
2902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903% %
2904% %
2905% %
2906+ R e a d B l o b L o n g L o n g %
2907% %
2908% %
2909% %
2910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911%
2912% ReadBlobLongLong() reads a long value as a 64-bit quantity in the byte-order
2913% specified by the endian member of the image structure.
2914%
2915% The format of the ReadBlobLong method is:
2916%
2917% MagickSizeType ReadBlobLong(Image *image)
2918%
2919% A description of each parameter follows.
2920%
2921% o image: the image.
2922%
2923*/
2924MagickExport MagickSizeType ReadBlobLongLong(Image *image)
2925{
2926 register const unsigned char
2927 *p;
2928
2929 ssize_t
2930 count;
2931
2932 unsigned char
2933 buffer[8];
2934
2935 MagickSizeType
2936 value;
2937
2938 assert(image != (Image *) NULL);
2939 assert(image->signature == MagickSignature);
2940 *buffer='\0';
2941 p=ReadBlobStream(image,8,buffer,&count);
2942 if (count != 8)
2943 return(MagickULLConstant(0));
2944 if (image->endian == LSBEndian)
2945 {
2946 value=(MagickSizeType) (*p++);
2947 value|=((MagickSizeType) (*p++)) << 8;
2948 value|=((MagickSizeType) (*p++)) << 16;
2949 value|=((MagickSizeType) (*p++)) << 24;
2950 value|=((MagickSizeType) (*p++)) << 32;
2951 value|=((MagickSizeType) (*p++)) << 40;
2952 value|=((MagickSizeType) (*p++)) << 48;
2953 value|=((MagickSizeType) (*p++)) << 56;
2954 return(value & MagickULLConstant(0xffffffffffffffff));
2955 }
2956 value=((MagickSizeType) (*p++)) << 56;
2957 value|=((MagickSizeType) (*p++)) << 48;
2958 value|=((MagickSizeType) (*p++)) << 40;
2959 value|=((MagickSizeType) (*p++)) << 32;
2960 value|=((MagickSizeType) (*p++)) << 24;
2961 value|=((MagickSizeType) (*p++)) << 16;
2962 value|=((MagickSizeType) (*p++)) << 8;
2963 value|=((MagickSizeType) (*p++));
2964 return(value & MagickULLConstant(0xffffffffffffffff));
2965}
2966
2967/*
2968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2969% %
2970% %
2971% %
2972+ R e a d B l o b S h o r t %
2973% %
2974% %
2975% %
2976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2977%
2978% ReadBlobShort() reads a short value as a 16-bit quantity in the byte-order
2979% specified by the endian member of the image structure.
2980%
2981% The format of the ReadBlobShort method is:
2982%
2983% unsigned short ReadBlobShort(Image *image)
2984%
2985% A description of each parameter follows.
2986%
2987% o image: the image.
2988%
2989*/
2990MagickExport unsigned short ReadBlobShort(Image *image)
2991{
2992 register const unsigned char
2993 *p;
2994
2995 register unsigned int
2996 value;
2997
2998 ssize_t
2999 count;
3000
3001 unsigned char
3002 buffer[2];
3003
3004 assert(image != (Image *) NULL);
3005 assert(image->signature == MagickSignature);
3006 *buffer='\0';
3007 p=ReadBlobStream(image,2,buffer,&count);
3008 if (count != 2)
3009 return((unsigned short) 0U);
3010 if (image->endian == LSBEndian)
3011 {
3012 value=(unsigned int) (*p++);
3013 value|=((unsigned int) (*p++)) << 8;
3014 return((unsigned short) (value & 0xffff));
3015 }
3016 value=(unsigned int) ((*p++) << 8);
3017 value|=(unsigned int) (*p++);
3018 return((unsigned short) (value & 0xffff));
3019}
3020
3021/*
3022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3023% %
3024% %
3025% %
3026+ R e a d B l o b L S B L o n g %
3027% %
3028% %
3029% %
3030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3031%
3032% ReadBlobLSBLong() reads a long value as a 32-bit quantity in
3033% least-significant byte first order.
3034%
3035% The format of the ReadBlobLSBLong method is:
3036%
3037% unsigned int ReadBlobLSBLong(Image *image)
3038%
3039% A description of each parameter follows.
3040%
3041% o image: the image.
3042%
3043*/
3044MagickExport unsigned int ReadBlobLSBLong(Image *image)
3045{
3046 register const unsigned char
3047 *p;
3048
3049 register unsigned int
3050 value;
3051
3052 ssize_t
3053 count;
3054
3055 unsigned char
3056 buffer[4];
3057
3058 assert(image != (Image *) NULL);
3059 assert(image->signature == MagickSignature);
3060 *buffer='\0';
3061 p=ReadBlobStream(image,4,buffer,&count);
3062 if (count != 4)
3063 return(0U);
3064 value=(unsigned int) (*p++);
3065 value|=((unsigned int) (*p++)) << 8;
3066 value|=((unsigned int) (*p++)) << 16;
3067 value|=((unsigned int) (*p++)) << 24;
3068 return(value);
3069}
3070
3071/*
3072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3073% %
3074% %
3075% %
3076+ R e a d B l o b L S B S h o r t %
3077% %
3078% %
3079% %
3080%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3081%
3082% ReadBlobLSBShort() reads a short value as a 16-bit quantity in
3083% least-significant byte first order.
3084%
3085% The format of the ReadBlobLSBShort method is:
3086%
3087% unsigned short ReadBlobLSBShort(Image *image)
3088%
3089% A description of each parameter follows.
3090%
3091% o image: the image.
3092%
3093*/
3094MagickExport unsigned short ReadBlobLSBShort(Image *image)
3095{
3096 register const unsigned char
3097 *p;
3098
3099 register unsigned int
3100 value;
3101
3102 ssize_t
3103 count;
3104
3105 unsigned char
3106 buffer[2];
3107
3108 assert(image != (Image *) NULL);
3109 assert(image->signature == MagickSignature);
3110 *buffer='\0';
3111 p=ReadBlobStream(image,2,buffer,&count);
3112 if (count != 2)
3113 return((unsigned short) 0U);
3114 value=(unsigned int) (*p++);
3115 value|=((unsigned int) ((*p++)) << 8);
3116 return((unsigned short) (value & 0xffff));
3117}
3118
3119/*
3120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3121% %
3122% %
3123% %
3124+ R e a d B l o b M S B L o n g %
3125% %
3126% %
3127% %
3128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3129%
3130% ReadBlobMSBLong() reads a long value as a 32-bit quantity in
3131% most-significant byte first order.
3132%
3133% The format of the ReadBlobMSBLong method is:
3134%
3135% unsigned int ReadBlobMSBLong(Image *image)
3136%
3137% A description of each parameter follows.
3138%
3139% o image: the image.
3140%
3141*/
3142MagickExport unsigned int ReadBlobMSBLong(Image *image)
3143{
3144 register const unsigned char
3145 *p;
3146
3147 register unsigned int
3148 value;
3149
3150 ssize_t
3151 count;
3152
3153 unsigned char
3154 buffer[4];
3155
3156 assert(image != (Image *) NULL);
3157 assert(image->signature == MagickSignature);
3158 *buffer='\0';
3159 p=ReadBlobStream(image,4,buffer,&count);
3160 if (count != 4)
3161 return(0UL);
3162 value=((unsigned int) (*p++) << 24);
3163 value|=((unsigned int) (*p++) << 16);
3164 value|=((unsigned int) (*p++) << 8);
3165 value|=(unsigned int) (*p++);
3166 return(value);
3167}
3168
3169/*
3170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3171% %
3172% %
3173% %
3174+ R e a d B l o b M S B S h o r t %
3175% %
3176% %
3177% %
3178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3179%
3180% ReadBlobMSBShort() reads a short value as a 16-bit quantity in
3181% most-significant byte first order.
3182%
3183% The format of the ReadBlobMSBShort method is:
3184%
3185% unsigned short ReadBlobMSBShort(Image *image)
3186%
3187% A description of each parameter follows.
3188%
3189% o image: the image.
3190%
3191*/
3192MagickExport unsigned short ReadBlobMSBShort(Image *image)
3193{
3194 register const unsigned char
3195 *p;
3196
3197 register unsigned int
3198 value;
3199
3200 ssize_t
3201 count;
3202
3203 unsigned char
3204 buffer[2];
3205
3206 assert(image != (Image *) NULL);
3207 assert(image->signature == MagickSignature);
3208 *buffer='\0';
3209 p=ReadBlobStream(image,2,buffer,&count);
3210 if (count != 2)
3211 return((unsigned short) 0U);
3212 value=(unsigned int) ((*p++) << 8);
3213 value|=(unsigned int) (*p++);
3214 return((unsigned short) (value & 0xffff));
3215}
3216
3217/*
3218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3219% %
3220% %
3221% %
3222+ R e a d B l o b S t r i n g %
3223% %
3224% %
3225% %
3226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3227%
3228% ReadBlobString() reads characters from a blob or file until a newline
3229% character is read or an end-of-file condition is encountered.
3230%
3231% The format of the ReadBlobString method is:
3232%
3233% char *ReadBlobString(Image *image,char *string)
3234%
3235% A description of each parameter follows:
3236%
3237% o image: the image.
3238%
3239% o string: the address of a character buffer.
3240%
3241*/
3242MagickExport char *ReadBlobString(Image *image,char *string)
3243{
3244 register const unsigned char
3245 *p;
3246
3247 register long
3248 i;
3249
3250 ssize_t
3251 count;
3252
3253 unsigned char
3254 buffer[1];
3255
3256 assert(image != (Image *) NULL);
3257 assert(image->signature == MagickSignature);
3258 for (i=0; i < (MaxTextExtent-1L); i++)
3259 {
3260 p=ReadBlobStream(image,1,buffer,&count);
3261 if (count != 1)
3262 {
3263 if (i == 0)
3264 return((char *) NULL);
3265 break;
3266 }
3267 string[i]=(char) (*p);
3268 if ((string[i] == '\n') || (string[i] == '\r'))
3269 break;
3270 }
3271 string[i]='\0';
3272 return(string);
3273}
3274
3275/*
3276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3277% %
3278% %
3279% %
3280+ R e f e r e n c e B l o b %
3281% %
3282% %
3283% %
3284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3285%
3286% ReferenceBlob() increments the reference count associated with the pixel
3287% blob returning a pointer to the blob.
3288%
3289% The format of the ReferenceBlob method is:
3290%
3291% BlobInfo ReferenceBlob(BlobInfo *blob_info)
3292%
3293% A description of each parameter follows:
3294%
3295% o blob_info: the blob_info.
3296%
3297*/
3298MagickExport BlobInfo *ReferenceBlob(BlobInfo *blob)
3299{
3300 assert(blob != (BlobInfo *) NULL);
3301 assert(blob->signature == MagickSignature);
3302 if (blob->debug != MagickFalse)
3303 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +00003304 LockSemaphoreInfo(blob->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00003305 blob->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00003306 UnlockSemaphoreInfo(blob->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00003307 return(blob);
3308}
3309
3310/*
3311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3312% %
3313% %
3314% %
3315+ S e e k B l o b %
3316% %
3317% %
3318% %
3319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3320%
3321% SeekBlob() sets the offset in bytes from the beginning of a blob or file
3322% and returns the resulting offset.
3323%
3324% The format of the SeekBlob method is:
3325%
3326% MagickOffsetType SeekBlob(Image *image,const MagickOffsetType offset,
3327% const int whence)
3328%
3329% A description of each parameter follows:
3330%
3331% o image: the image.
3332%
3333% o offset: Specifies an integer representing the offset in bytes.
3334%
3335% o whence: Specifies an integer representing how the offset is
3336% treated relative to the beginning of the blob as follows:
3337%
3338% SEEK_SET Set position equal to offset bytes.
3339% SEEK_CUR Set position to current location plus offset.
3340% SEEK_END Set position to EOF plus offset.
3341%
3342*/
3343MagickExport MagickOffsetType SeekBlob(Image *image,
3344 const MagickOffsetType offset,const int whence)
3345{
3346 assert(image != (Image *) NULL);
3347 assert(image->signature == MagickSignature);
3348 if (image->debug != MagickFalse)
3349 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3350 assert(image->blob != (BlobInfo *) NULL);
3351 assert(image->blob->type != UndefinedStream);
3352 switch (image->blob->type)
3353 {
3354 case UndefinedStream:
3355 break;
3356 case FileStream:
3357 {
3358 if (fseek(image->blob->file,offset,whence) < 0)
3359 return(-1);
3360 image->blob->offset=TellBlob(image);
3361 break;
3362 }
3363 case StandardStream:
3364 case PipeStream:
3365 case ZipStream:
3366 {
3367#if defined(MAGICKCORE_ZLIB_DELEGATE)
3368 if (gzseek(image->blob->file,(off_t) offset,whence) < 0)
3369 return(-1);
3370#endif
3371 image->blob->offset=TellBlob(image);
3372 break;
3373 }
3374 case BZipStream:
3375 return(-1);
3376 case FifoStream:
3377 return(-1);
3378 case BlobStream:
3379 {
3380 switch (whence)
3381 {
3382 case SEEK_SET:
3383 default:
3384 {
3385 if (offset < 0)
3386 return(-1);
3387 image->blob->offset=offset;
3388 break;
3389 }
3390 case SEEK_CUR:
3391 {
3392 if ((image->blob->offset+offset) < 0)
3393 return(-1);
3394 image->blob->offset+=offset;
3395 break;
3396 }
3397 case SEEK_END:
3398 {
3399 if (((MagickOffsetType) image->blob->length+offset) < 0)
3400 return(-1);
3401 image->blob->offset=image->blob->length+offset;
3402 break;
3403 }
3404 }
3405 if (image->blob->offset <= (MagickOffsetType)
3406 ((off_t) image->blob->length))
3407 image->blob->eof=MagickFalse;
3408 else
3409 if (image->blob->mapped != MagickFalse)
3410 return(-1);
3411 else
3412 {
3413 image->blob->extent=(size_t) (image->blob->offset+
3414 image->blob->quantum);
3415 image->blob->data=(unsigned char *) ResizeQuantumMemory(
3416 image->blob->data,image->blob->extent+1,
3417 sizeof(*image->blob->data));
3418 (void) SyncBlob(image);
3419 if (image->blob->data == (unsigned char *) NULL)
3420 {
3421 (void) DetachBlob(image->blob);
3422 return(-1);
3423 }
3424 }
3425 break;
3426 }
3427 }
3428 return(image->blob->offset);
3429}
3430
3431/*
3432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3433% %
3434% %
3435% %
3436+ S e t B l o b E x e m p t %
3437% %
3438% %
3439% %
3440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3441%
3442% SetBlobExempt() sets the blob exempt status.
3443%
3444% The format of the SetBlobExempt method is:
3445%
3446% MagickBooleanType SetBlobExempt(const Image *image,
3447% const MagickBooleanType exempt)
3448%
3449% A description of each parameter follows:
3450%
3451% o image: the image.
3452%
3453% o exempt: Set to true if this blob is exempt from being closed.
3454%
3455*/
3456MagickExport void SetBlobExempt(Image *image,const MagickBooleanType exempt)
3457{
3458 assert(image != (const Image *) NULL);
3459 assert(image->signature == MagickSignature);
3460 if (image->debug != MagickFalse)
3461 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3462 image->blob->exempt=exempt;
3463}
3464
3465/*
3466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3467% %
3468% %
3469% %
3470+ S e t B l o b E x t e n t %
3471% %
3472% %
3473% %
3474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3475%
3476% SetBlobExtent() ensures enough space is allocated for the blob. If the
3477% method is successful, subsequent writes to bytes in the specified range are
3478% guaranteed not to fail.
3479%
3480% The format of the SetBlobExtent method is:
3481%
3482% MagickBooleanType SetBlobExtent(Image *image,const MagickSizeType extent)
3483%
3484% A description of each parameter follows:
3485%
3486% o image: the image.
3487%
3488% o extent: the blob maximum extent.
3489%
3490*/
3491MagickExport MagickBooleanType SetBlobExtent(Image *image,
3492 const MagickSizeType extent)
3493{
3494 assert(image != (Image *) NULL);
3495 assert(image->signature == MagickSignature);
3496 if (image->debug != MagickFalse)
3497 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3498 assert(image->blob != (BlobInfo *) NULL);
3499 assert(image->blob->type != UndefinedStream);
3500 switch (image->blob->type)
3501 {
3502 case UndefinedStream:
3503 break;
3504 case FileStream:
3505 {
3506 if (extent != (MagickSizeType) ((off_t) extent))
3507 return(MagickFalse);
3508#if !defined(MAGICKCORE_POSIX_FALLOCATE)
3509 return(MagickFalse);
3510#else
3511 {
3512 int
3513 status;
3514
3515 MagickOffsetType
3516 offset;
3517
3518 offset=TellBlob(image);
3519 status=posix_fallocate(fileno(image->blob->file),(off_t) offset,
3520 (off_t) (extent-offset));
3521 if (status != 0)
3522 return(MagickFalse);
3523 }
3524#endif
3525 break;
3526 }
3527 case StandardStream:
3528 case PipeStream:
3529 case ZipStream:
3530 return(MagickFalse);
3531 case BZipStream:
3532 return(MagickFalse);
3533 case FifoStream:
3534 return(MagickFalse);
3535 case BlobStream:
3536 {
3537 if (image->blob->mapped != MagickFalse)
3538 {
3539 if (image->blob->file == (FILE *) NULL)
3540 return(MagickFalse);
3541 (void) UnmapBlob(image->blob->data,image->blob->length);
3542#if !defined(MAGICKCORE_POSIX_FALLOCATE)
3543 return(MagickFalse);
3544#else
3545 {
3546 int
3547 status;
3548
3549 MagickOffsetType
3550 offset;
3551
3552 offset=TellBlob(image);
3553 status=posix_fallocate(fileno(image->blob->file),(off_t) offset,
3554 (off_t) (extent-offset));
3555 if (status != 0)
3556 return(MagickFalse);
3557 }
3558 image->blob->data=(unsigned char*) MapBlob(fileno(image->blob->file),
3559 WriteMode,0,(size_t) extent);
3560 image->blob->extent=(size_t) extent;
3561 image->blob->length=(size_t) extent;
3562 (void) SyncBlob(image);
3563 break;
3564#endif
3565 }
3566 if (extent != (MagickSizeType) ((size_t) extent))
3567 return(MagickFalse);
3568 image->blob->extent=(size_t) extent;
3569 image->blob->data=(unsigned char *) ResizeQuantumMemory(image->blob->data,
3570 image->blob->extent+1,sizeof(*image->blob->data));
3571 (void) SyncBlob(image);
3572 if (image->blob->data == (unsigned char *) NULL)
3573 {
3574 (void) DetachBlob(image->blob);
3575 return(MagickFalse);
3576 }
3577 break;
3578 }
3579 }
3580 return(MagickTrue);
3581}
3582
3583/*
3584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3585% %
3586% %
3587% %
3588+ S y n c B l o b %
3589% %
3590% %
3591% %
3592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3593%
3594% SyncBlob() flushes the datastream if it is a file or synchronizes the data
3595% attributes if it is an blob.
3596%
3597% The format of the SyncBlob method is:
3598%
3599% int SyncBlob(Image *image)
3600%
3601% A description of each parameter follows:
3602%
3603% o image: the image.
3604%
3605*/
3606static int SyncBlob(Image *image)
3607{
3608 int
3609 status;
3610
3611 assert(image != (Image *) NULL);
3612 assert(image->signature == MagickSignature);
3613 if (image->debug != MagickFalse)
3614 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3615 assert(image->blob != (BlobInfo *) NULL);
3616 assert(image->blob->type != UndefinedStream);
3617 status=0;
3618 switch (image->blob->type)
3619 {
3620 case UndefinedStream:
3621 break;
3622 case FileStream:
3623 case StandardStream:
3624 case PipeStream:
3625 {
3626 status=fflush(image->blob->file);
3627 break;
3628 }
3629 case ZipStream:
3630 {
3631#if defined(MAGICKCORE_ZLIB_DELEGATE)
3632 status=gzflush(image->blob->file,Z_SYNC_FLUSH);
3633#endif
3634 break;
3635 }
3636 case BZipStream:
3637 {
3638#if defined(MAGICKCORE_BZLIB_DELEGATE)
3639 status=BZ2_bzflush((BZFILE *) image->blob->file);
3640#endif
3641 break;
3642 }
3643 case FifoStream:
3644 break;
3645 case BlobStream:
3646 {
3647#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
3648 if (image->blob->mapped != MagickFalse)
3649 status=msync(image->blob->data,image->blob->length,MS_SYNC);
3650#endif
3651 break;
3652 }
3653 }
3654 return(status);
3655}
3656
3657/*
3658%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3659% %
3660% %
3661% %
3662+ T e l l B l o b %
3663% %
3664% %
3665% %
3666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3667%
3668% TellBlob() obtains the current value of the blob or file position.
3669%
3670% The format of the TellBlob method is:
3671%
3672% MagickOffsetType TellBlob(const Image *image)
3673%
3674% A description of each parameter follows:
3675%
3676% o image: the image.
3677%
3678*/
3679MagickExport MagickOffsetType TellBlob(const Image *image)
3680{
3681 MagickOffsetType
3682 offset;
3683
3684 assert(image != (Image *) NULL);
3685 assert(image->signature == MagickSignature);
3686 if (image->debug != MagickFalse)
3687 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3688 assert(image->blob != (BlobInfo *) NULL);
3689 assert(image->blob->type != UndefinedStream);
3690 offset=(-1);
3691 switch (image->blob->type)
3692 {
3693 case UndefinedStream:
3694 break;
3695 case FileStream:
3696 {
3697 offset=ftell(image->blob->file);
3698 break;
3699 }
3700 case StandardStream:
3701 case PipeStream:
3702 break;
3703 case ZipStream:
3704 {
3705#if defined(MAGICKCORE_ZLIB_DELEGATE)
3706 offset=(MagickOffsetType) gztell(image->blob->file);
3707#endif
3708 break;
3709 }
3710 case BZipStream:
3711 break;
3712 case FifoStream:
3713 break;
3714 case BlobStream:
3715 {
3716 offset=image->blob->offset;
3717 break;
3718 }
3719 }
3720 return(offset);
3721}
3722
3723/*
3724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3725% %
3726% %
3727% %
3728+ U n m a p B l o b %
3729% %
3730% %
3731% %
3732%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3733%
3734% UnmapBlob() deallocates the binary large object previously allocated with
3735% the MapBlob method.
3736%
3737% The format of the UnmapBlob method is:
3738%
3739% MagickBooleanType UnmapBlob(void *map,const size_t length)
3740%
3741% A description of each parameter follows:
3742%
3743% o map: the address of the binary large object.
3744%
3745% o length: the length of the binary large object.
3746%
3747*/
3748MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
3749{
3750#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
3751 int
3752 status;
3753
3754 status=munmap(map,length);
3755 return(status == -1 ? MagickFalse : MagickTrue);
3756#else
3757 (void) map;
3758 (void) length;
3759 return(MagickFalse);
3760#endif
3761}
3762
3763/*
3764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765% %
3766% %
3767% %
3768+ W r i t e B l o b %
3769% %
3770% %
3771% %
3772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773%
3774% WriteBlob() writes data to a blob or image file. It returns the number of
3775% bytes written.
3776%
3777% The format of the WriteBlob method is:
3778%
3779% ssize_t WriteBlob(Image *image,const size_t length,
3780% const unsigned char *data)
3781%
3782% A description of each parameter follows:
3783%
3784% o image: the image.
3785%
3786% o length: Specifies an integer representing the number of bytes to
3787% write to the file.
3788%
3789% o data: The address of the data to write to the blob or file.
3790%
3791*/
3792MagickExport ssize_t WriteBlob(Image *image,const size_t length,
3793 const unsigned char *data)
3794{
3795 int
3796 c;
3797
3798 register const unsigned char
3799 *p;
3800
3801 ssize_t
3802 count;
3803
3804 assert(image != (Image *) NULL);
3805 assert(image->signature == MagickSignature);
3806 assert(data != (const unsigned char *) NULL);
3807 assert(image->blob != (BlobInfo *) NULL);
3808 assert(image->blob->type != UndefinedStream);
3809 if (length == 0)
3810 return(0);
3811 count=0;
3812 p=data;
3813 switch (image->blob->type)
3814 {
3815 case UndefinedStream:
3816 break;
3817 case FileStream:
3818 case StandardStream:
3819 case PipeStream:
3820 {
3821 switch (length)
3822 {
3823 default:
3824 {
3825 count=(ssize_t) fwrite((const char *) data,1,length,
3826 image->blob->file);
3827 break;
3828 }
3829 case 2:
3830 {
3831 c=putc((int) *p++,image->blob->file);
3832 if (c == EOF)
3833 break;
3834 count++;
3835 }
3836 case 1:
3837 {
3838 c=putc((int) *p++,image->blob->file);
3839 if (c == EOF)
3840 break;
3841 count++;
3842 }
3843 case 0:
3844 break;
3845 }
3846 break;
3847 }
3848 case ZipStream:
3849 {
3850#if defined(MAGICKCORE_ZLIB_DELEGATE)
3851 switch (length)
3852 {
3853 default:
3854 {
3855 count=(ssize_t) gzwrite(image->blob->file,(void *) data,
3856 (unsigned int) length);
3857 break;
3858 }
3859 case 2:
3860 {
3861 c=gzputc(image->blob->file,(int) *p++);
3862 if (c == EOF)
3863 break;
3864 count++;
3865 }
3866 case 1:
3867 {
3868 c=gzputc(image->blob->file,(int) *p++);
3869 if (c == EOF)
3870 break;
3871 count++;
3872 }
3873 case 0:
3874 break;
3875 }
3876#endif
3877 break;
3878 }
3879 case BZipStream:
3880 {
3881#if defined(MAGICKCORE_BZLIB_DELEGATE)
3882 count=(ssize_t) BZ2_bzwrite((BZFILE *) image->blob->file,(void *) data,
3883 (int) length);
3884#endif
3885 break;
3886 }
3887 case FifoStream:
3888 {
3889 count=(ssize_t) image->blob->stream(image,data,length);
3890 break;
3891 }
3892 case BlobStream:
3893 {
3894 register unsigned char
3895 *q;
3896
3897 if ((image->blob->offset+(MagickOffsetType) length) >=
3898 (MagickOffsetType) image->blob->extent)
3899 {
3900 if (image->blob->mapped != MagickFalse)
3901 return(0);
3902 image->blob->quantum<<=1;
3903 image->blob->extent+=length+image->blob->quantum;
3904 image->blob->data=(unsigned char *) ResizeQuantumMemory(
3905 image->blob->data,image->blob->extent+1,sizeof(*image->blob->data));
3906 (void) SyncBlob(image);
3907 if (image->blob->data == (unsigned char *) NULL)
3908 {
3909 (void) DetachBlob(image->blob);
3910 return(0);
3911 }
3912 }
3913 q=image->blob->data+image->blob->offset;
3914 (void) CopyMagickMemory(q,p,length);
3915 image->blob->offset+=length;
3916 if (image->blob->offset >= (MagickOffsetType) image->blob->length)
3917 image->blob->length=(size_t) image->blob->offset;
3918 count=(ssize_t) length;
3919 }
3920 }
3921 return(count);
3922}
3923
3924/*
3925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3926% %
3927% %
3928% %
3929+ W r i t e B l o b B y t e %
3930% %
3931% %
3932% %
3933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3934%
3935% WriteBlobByte() write an integer to a blob. It returns the number of bytes
3936% written (either 0 or 1);
3937%
3938% The format of the WriteBlobByte method is:
3939%
3940% ssize_t WriteBlobByte(Image *image,const unsigned char value)
3941%
3942% A description of each parameter follows.
3943%
3944% o image: the image.
3945%
3946% o value: Specifies the value to write.
3947%
3948*/
3949MagickExport ssize_t WriteBlobByte(Image *image,const unsigned char value)
3950{
3951 assert(image != (Image *) NULL);
3952 assert(image->signature == MagickSignature);
3953 return(WriteBlobStream(image,1,&value));
3954}
3955
3956/*
3957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3958% %
3959% %
3960% %
3961+ W r i t e B l o b F l o a t %
3962% %
3963% %
3964% %
3965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3966%
3967% WriteBlobFloat() writes a float value as a 32-bit quantity in the byte-order
3968% specified by the endian member of the image structure.
3969%
3970% The format of the WriteBlobFloat method is:
3971%
3972% ssize_t WriteBlobFloat(Image *image,const float value)
3973%
3974% A description of each parameter follows.
3975%
3976% o image: the image.
3977%
3978% o value: Specifies the value to write.
3979%
3980*/
3981MagickExport ssize_t WriteBlobFloat(Image *image,const float value)
3982{
3983 union
3984 {
3985 unsigned int
3986 unsigned_value;
3987
3988 float
3989 float_value;
3990 } quantum;
3991
3992 quantum.unsigned_value=0U;
3993 quantum.float_value=value;
3994 return(WriteBlobLong(image,quantum.unsigned_value));
3995}
3996
3997/*
3998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3999% %
4000% %
4001% %
4002+ W r i t e B l o b L o n g %
4003% %
4004% %
4005% %
4006%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4007%
4008% WriteBlobLong() writes a long value as a 32-bit quantity in the byte-order
4009% specified by the endian member of the image structure.
4010%
4011% The format of the WriteBlobLong method is:
4012%
4013% ssize_t WriteBlobLong(Image *image,const unsigned int value)
4014%
4015% A description of each parameter follows.
4016%
4017% o image: the image.
4018%
4019% o value: Specifies the value to write.
4020%
4021*/
4022MagickExport ssize_t WriteBlobLong(Image *image,const unsigned int value)
4023{
4024 unsigned char
4025 buffer[4];
4026
4027 assert(image != (Image *) NULL);
4028 assert(image->signature == MagickSignature);
4029 if (image->endian == LSBEndian)
4030 {
4031 buffer[0]=(unsigned char) value;
4032 buffer[1]=(unsigned char) (value >> 8);
4033 buffer[2]=(unsigned char) (value >> 16);
4034 buffer[3]=(unsigned char) (value >> 24);
4035 return(WriteBlobStream(image,4,buffer));
4036 }
4037 buffer[0]=(unsigned char) (value >> 24);
4038 buffer[1]=(unsigned char) (value >> 16);
4039 buffer[2]=(unsigned char) (value >> 8);
4040 buffer[3]=(unsigned char) value;
4041 return(WriteBlobStream(image,4,buffer));
4042}
4043
4044/*
4045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4046% %
4047% %
4048% %
4049+ W r i t e B l o b S h o r t %
4050% %
4051% %
4052% %
4053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4054%
4055% WriteBlobShort() writes a short value as a 16-bit quantity in the
4056% byte-order specified by the endian member of the image structure.
4057%
4058% The format of the WriteBlobShort method is:
4059%
4060% ssize_t WriteBlobShort(Image *image,const unsigned short value)
4061%
4062% A description of each parameter follows.
4063%
4064% o image: the image.
4065%
4066% o value: Specifies the value to write.
4067%
4068*/
4069MagickExport ssize_t WriteBlobShort(Image *image,const unsigned short value)
4070{
4071 unsigned char
4072 buffer[2];
4073
4074 assert(image != (Image *) NULL);
4075 assert(image->signature == MagickSignature);
4076 if (image->endian == LSBEndian)
4077 {
4078 buffer[0]=(unsigned char) value;
4079 buffer[1]=(unsigned char) (value >> 8);
4080 return(WriteBlobStream(image,2,buffer));
4081 }
4082 buffer[0]=(unsigned char) (value >> 8);
4083 buffer[1]=(unsigned char) value;
4084 return(WriteBlobStream(image,2,buffer));
4085}
4086
4087/*
4088%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4089% %
4090% %
4091% %
4092+ W r i t e B l o b L S B L o n g %
4093% %
4094% %
4095% %
4096%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4097%
4098% WriteBlobLSBLong() writes a long value as a 32-bit quantity in
4099% least-significant byte first order.
4100%
4101% The format of the WriteBlobLSBLong method is:
4102%
4103% ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
4104%
4105% A description of each parameter follows.
4106%
4107% o image: the image.
4108%
4109% o value: Specifies the value to write.
4110%
4111*/
4112MagickExport ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
4113{
4114 unsigned char
4115 buffer[4];
4116
4117 assert(image != (Image *) NULL);
4118 assert(image->signature == MagickSignature);
4119 buffer[0]=(unsigned char) value;
4120 buffer[1]=(unsigned char) (value >> 8);
4121 buffer[2]=(unsigned char) (value >> 16);
4122 buffer[3]=(unsigned char) (value >> 24);
4123 return(WriteBlobStream(image,4,buffer));
4124}
4125
4126/*
4127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4128% %
4129% %
4130% %
4131+ W r i t e B l o b L S B S h o r t %
4132% %
4133% %
4134% %
4135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4136%
4137% WriteBlobLSBShort() writes a long value as a 16-bit quantity in
4138% least-significant byte first order.
4139%
4140% The format of the WriteBlobLSBShort method is:
4141%
4142% ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
4143%
4144% A description of each parameter follows.
4145%
4146% o image: the image.
4147%
4148% o value: Specifies the value to write.
4149%
4150*/
4151MagickExport ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
4152{
4153 unsigned char
4154 buffer[2];
4155
4156 assert(image != (Image *) NULL);
4157 assert(image->signature == MagickSignature);
4158 buffer[0]=(unsigned char) value;
4159 buffer[1]=(unsigned char) (value >> 8);
4160 return(WriteBlobStream(image,2,buffer));
4161}
4162
4163/*
4164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4165% %
4166% %
4167% %
4168+ W r i t e B l o b M S B L o n g %
4169% %
4170% %
4171% %
4172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4173%
4174% WriteBlobMSBLong() writes a long value as a 32-bit quantity in
4175% most-significant byte first order.
4176%
4177% The format of the WriteBlobMSBLong method is:
4178%
4179% ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
4180%
4181% A description of each parameter follows.
4182%
4183% o value: Specifies the value to write.
4184%
4185% o image: the image.
4186%
4187*/
4188MagickExport ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
4189{
4190 unsigned char
4191 buffer[4];
4192
4193 assert(image != (Image *) NULL);
4194 assert(image->signature == MagickSignature);
4195 buffer[0]=(unsigned char) (value >> 24);
4196 buffer[1]=(unsigned char) (value >> 16);
4197 buffer[2]=(unsigned char) (value >> 8);
4198 buffer[3]=(unsigned char) value;
4199 return(WriteBlobStream(image,4,buffer));
4200}
4201
4202/*
4203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4204% %
4205% %
4206% %
4207+ W r i t e B l o b M S B S h o r t %
4208% %
4209% %
4210% %
4211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4212%
4213% WriteBlobMSBShort() writes a long value as a 16-bit quantity in
4214% most-significant byte first order.
4215%
4216% The format of the WriteBlobMSBShort method is:
4217%
4218% ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
4219%
4220% A description of each parameter follows.
4221%
4222% o value: Specifies the value to write.
4223%
4224% o file: Specifies the file to write the data to.
4225%
4226*/
4227MagickExport ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
4228{
4229 unsigned char
4230 buffer[2];
4231
4232 assert(image != (Image *) NULL);
4233 assert(image->signature == MagickSignature);
4234 buffer[0]=(unsigned char) (value >> 8);
4235 buffer[1]=(unsigned char) value;
4236 return(WriteBlobStream(image,2,buffer));
4237}
4238
4239/*
4240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4241% %
4242% %
4243% %
4244+ W r i t e B l o b S t r i n g %
4245% %
4246% %
4247% %
4248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4249%
4250% WriteBlobString() write a string to a blob. It returns the number of
4251% characters written.
4252%
4253% The format of the WriteBlobString method is:
4254%
4255% ssize_t WriteBlobString(Image *image,const char *string)
4256%
4257% A description of each parameter follows.
4258%
4259% o image: the image.
4260%
4261% o string: Specifies the string to write.
4262%
4263*/
4264MagickExport ssize_t WriteBlobString(Image *image,const char *string)
4265{
4266 assert(image != (Image *) NULL);
4267 assert(image->signature == MagickSignature);
4268 assert(string != (const char *) NULL);
4269 return(WriteBlobStream(image,strlen(string),(const unsigned char *) string));
4270}