blob: 23b0a00de4e3a370e29a9b706ab23c25311c11a8 [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);
cristybf7fa0d2010-02-04 00:51:10 +00002328 if ((image_info->adjoin == MagickFalse) &&
cristyef84ade2010-02-04 00:55:57 +00002329 ((GetPreviousImageInList(image) != (Image *) NULL) ||
cristybf7fa0d2010-02-04 00:51:10 +00002330 (GetNextImageInList(image) != (Image *) NULL)))
cristye8939e72010-02-03 17:05:25 +00002331 {
2332 /*
2333 Form filename for multi-part images.
2334 */
2335 (void) InterpretImageFilename(image_info,image,image->filename,(int)
2336 image->scene,filename);
cristybf7fa0d2010-02-04 00:51:10 +00002337 if (LocaleCompare(filename,image->filename) == 0)
cristye8939e72010-02-03 17:05:25 +00002338 {
cristybf7fa0d2010-02-04 00:51:10 +00002339 char
2340 extension[MaxTextExtent],
2341 path[MaxTextExtent];
cristy3ed852e2009-09-05 21:47:34 +00002342
cristybf7fa0d2010-02-04 00:51:10 +00002343 GetPathComponent(image->filename,RootPath,path);
2344 GetPathComponent(image->filename,ExtensionPath,extension);
2345 if (*extension == '\0')
2346 (void) FormatMagickString(filename,MaxTextExtent,"%s-%lu",
2347 path,image->scene);
2348 else
2349 (void) FormatMagickString(filename,MaxTextExtent,
2350 "%s-%lu.%s",path,image->scene,extension);
cristye8939e72010-02-03 17:05:25 +00002351 }
2352 (void) CopyMagickString(image->filename,filename,MaxTextExtent);
cristy3ed852e2009-09-05 21:47:34 +00002353#if defined(macintosh)
cristye8939e72010-02-03 17:05:25 +00002354 SetApplicationType(filename,image_info->magick,'8BIM');
cristy3ed852e2009-09-05 21:47:34 +00002355#endif
cristye8939e72010-02-03 17:05:25 +00002356 }
cristy3ed852e2009-09-05 21:47:34 +00002357 }
2358#if defined(MAGICKCORE_ZLIB_DELEGATE)
2359 if (((strlen(filename) > 2) &&
2360 (LocaleCompare(filename+strlen(filename)-2,".Z") == 0)) ||
2361 ((strlen(filename) > 3) &&
2362 (LocaleCompare(filename+strlen(filename)-3,".gz") == 0)) ||
2363 ((strlen(filename) > 4) &&
2364 (LocaleCompare(filename+strlen(filename)-4,".wmz") == 0)) ||
2365 ((strlen(filename) > 5) &&
2366 (LocaleCompare(filename+strlen(filename)-5,".svgz") == 0)))
2367 {
2368 image->blob->file=(FILE *) gzopen(filename,type);
2369 if (image->blob->file != (FILE *) NULL)
2370 image->blob->type=ZipStream;
2371 }
2372 else
2373#endif
2374#if defined(MAGICKCORE_BZLIB_DELEGATE)
2375 if ((strlen(filename) > 4) &&
2376 (LocaleCompare(filename+strlen(filename)-4,".bz2") == 0))
2377 {
2378 image->blob->file=(FILE *) BZ2_bzopen(filename,type);
2379 if (image->blob->file != (FILE *) NULL)
2380 image->blob->type=BZipStream;
2381 }
2382 else
2383#endif
2384 if (image_info->file != (FILE *) NULL)
2385 {
2386 image->blob->file=image_info->file;
2387 image->blob->type=FileStream;
2388 image->blob->exempt=MagickTrue;
2389 }
2390 else
2391 {
2392 image->blob->file=(FILE *) OpenMagickStream(filename,type);
2393 if (image->blob->file != (FILE *) NULL)
2394 {
2395 image->blob->type=FileStream;
2396#if defined(MAGICKCORE_HAVE_SETVBUF)
2397 (void) setvbuf(image->blob->file,(char *) NULL,(int) _IOFBF,
2398 16384);
2399#endif
2400 if (*type == 'r')
2401 {
2402 size_t
2403 count;
2404
2405 unsigned char
2406 magick[3];
2407
2408 (void) ResetMagickMemory(magick,0,sizeof(magick));
2409 count=fread(magick,1,sizeof(magick),image->blob->file);
2410 (void) rewind(image->blob->file);
2411 (void) LogMagickEvent(BlobEvent,GetMagickModule(),
2412 " read %ld magic header bytes",(long) count);
2413#if defined(MAGICKCORE_ZLIB_DELEGATE)
2414 if (((int) magick[0] == 0x1F) && ((int) magick[1] == 0x8B) &&
2415 ((int) magick[2] == 0x08))
2416 {
2417 (void) fclose(image->blob->file);
2418 image->blob->file=(FILE *) gzopen(filename,type);
2419 if (image->blob->file != (FILE *) NULL)
2420 image->blob->type=ZipStream;
2421 }
2422#endif
2423#if defined(MAGICKCORE_BZLIB_DELEGATE)
2424 if (strncmp((char *) magick,"BZh",3) == 0)
2425 {
2426 (void) fclose(image->blob->file);
2427 image->blob->file=(FILE *) BZ2_bzopen(filename,type);
2428 if (image->blob->file != (FILE *) NULL)
2429 image->blob->type=BZipStream;
2430 }
2431#endif
2432 }
2433 }
2434 }
2435 if ((image->blob->type == FileStream) && (*type == 'r'))
2436 {
2437 const MagickInfo
2438 *magick_info;
2439
2440 ExceptionInfo
2441 *sans_exception;
2442
2443 struct stat
2444 *properties;
2445
2446 sans_exception=AcquireExceptionInfo();
2447 magick_info=GetMagickInfo(image_info->magick,sans_exception);
2448 sans_exception=DestroyExceptionInfo(sans_exception);
2449 properties=(&image->blob->properties);
2450 if ((magick_info != (const MagickInfo *) NULL) &&
2451 (GetMagickBlobSupport(magick_info) != MagickFalse) &&
2452 (properties->st_size <= MagickMaxBufferExtent))
2453 {
2454 size_t
2455 length;
2456
2457 void
2458 *blob;
2459
2460 length=(size_t) properties->st_size;
2461 blob=MapBlob(fileno(image->blob->file),ReadMode,0,length);
2462 if (blob != (void *) NULL)
2463 {
2464 /*
2465 Format supports blobs-- use memory-mapped I/O.
2466 */
2467 if (image_info->file != (FILE *) NULL)
2468 image->blob->exempt=MagickFalse;
2469 else
2470 {
2471 (void) fclose(image->blob->file);
2472 image->blob->file=(FILE *) NULL;
2473 }
2474 AttachBlob(image->blob,blob,length);
2475 image->blob->mapped=MagickTrue;
2476 }
2477 }
2478 }
2479 image->blob->status=MagickFalse;
2480 if (image->blob->type != UndefinedStream)
2481 image->blob->size=GetBlobSize(image);
2482 else
2483 {
2484 ThrowFileException(exception,BlobError,"UnableToOpenBlob",filename);
2485 return(MagickFalse);
2486 }
2487 return(MagickTrue);
2488}
2489
2490/*
2491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2492% %
2493% %
2494% %
2495+ P i n g B l o b %
2496% %
2497% %
2498% %
2499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500%
2501% PingBlob() returns all the attributes of an image or image sequence except
2502% for the pixels. It is much faster and consumes far less memory than
2503% BlobToImage(). On failure, a NULL image is returned and exception
2504% describes the reason for the failure.
2505%
2506% The format of the PingBlob method is:
2507%
2508% Image *PingBlob(const ImageInfo *image_info,const void *blob,
2509% const size_t length,ExceptionInfo *exception)
2510%
2511% A description of each parameter follows:
2512%
2513% o image_info: the image info.
2514%
2515% o blob: the address of a character stream in one of the image formats
2516% understood by ImageMagick.
2517%
2518% o length: This size_t integer reflects the length in bytes of the blob.
2519%
2520% o exception: return any errors or warnings in this structure.
2521%
2522*/
2523
2524#if defined(__cplusplus) || defined(c_plusplus)
2525extern "C" {
2526#endif
2527
2528static size_t PingStream(const Image *magick_unused(image),
2529 const void *magick_unused(pixels),const size_t columns)
2530{
2531 return(columns);
2532}
2533
2534#if defined(__cplusplus) || defined(c_plusplus)
2535}
2536#endif
2537
2538MagickExport Image *PingBlob(const ImageInfo *image_info,const void *blob,
2539 const size_t length,ExceptionInfo *exception)
2540{
2541 Image
2542 *image;
2543
2544 ImageInfo
2545 *ping_info;
2546
2547 assert(image_info != (ImageInfo *) NULL);
2548 assert(image_info->signature == MagickSignature);
2549 if (image_info->debug != MagickFalse)
2550 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2551 image_info->filename);
2552 assert(exception != (ExceptionInfo *) NULL);
2553 if ((blob == (const void *) NULL) || (length == 0))
2554 {
2555 (void) ThrowMagickException(exception,GetMagickModule(),BlobError,
2556 "UnrecognizedImageFormat","`%s'",image_info->magick);
2557 return((Image *) NULL);
2558 }
2559 ping_info=CloneImageInfo(image_info);
2560 ping_info->blob=(void *) AcquireQuantumMemory(length,sizeof(unsigned char));
2561 if (ping_info->blob == (const void *) NULL)
2562 {
2563 (void) ThrowMagickException(exception,GetMagickModule(),
2564 ResourceLimitFatalError,"MemoryAllocationFailed","`%s'","");
2565 return((Image *) NULL);
2566 }
2567 (void) CopyMagickMemory(ping_info->blob,blob,length);
2568 ping_info->length=length;
2569 ping_info->ping=MagickTrue;
2570 image=ReadStream(ping_info,&PingStream,exception);
2571 ping_info->blob=(void *) RelinquishMagickMemory(ping_info->blob);
2572 ping_info=DestroyImageInfo(ping_info);
2573 return(image);
2574}
2575
2576/*
2577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578% %
2579% %
2580% %
2581+ R e a d B l o b %
2582% %
2583% %
2584% %
2585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586%
2587% ReadBlob() reads data from the blob or image file and returns it. It
2588% returns the number of bytes read.
2589%
2590% The format of the ReadBlob method is:
2591%
2592% ssize_t ReadBlob(Image *image,const size_t length,unsigned char *data)
2593%
2594% A description of each parameter follows:
2595%
2596% o image: the image.
2597%
2598% o length: Specifies an integer representing the number of bytes to read
2599% from the file.
2600%
2601% o data: Specifies an area to place the information requested from the
2602% file.
2603%
2604*/
2605MagickExport ssize_t ReadBlob(Image *image,const size_t length,
2606 unsigned char *data)
2607{
2608 int
2609 c;
2610
2611 register unsigned char
2612 *q;
2613
2614 ssize_t
2615 count;
2616
2617 assert(image != (Image *) NULL);
2618 assert(image->signature == MagickSignature);
2619 assert(image->blob != (BlobInfo *) NULL);
2620 assert(image->blob->type != UndefinedStream);
2621 if (length == 0)
2622 return(0);
2623 assert(data != (void *) NULL);
2624 count=0;
2625 q=data;
2626 switch (image->blob->type)
2627 {
2628 case UndefinedStream:
2629 break;
2630 case FileStream:
2631 case StandardStream:
2632 case PipeStream:
2633 {
2634 switch (length)
2635 {
2636 default:
2637 {
2638 count=(ssize_t) fread(q,1,length,image->blob->file);
2639 break;
2640 }
2641 case 2:
2642 {
2643 c=getc(image->blob->file);
2644 if (c == EOF)
2645 break;
2646 *q++=(unsigned char) c;
2647 count++;
2648 }
2649 case 1:
2650 {
2651 c=getc(image->blob->file);
2652 if (c == EOF)
2653 break;
2654 *q++=(unsigned char) c;
2655 count++;
2656 }
2657 case 0:
2658 break;
2659 }
2660 break;
2661 }
2662 case ZipStream:
2663 {
2664#if defined(MAGICKCORE_ZLIB_DELEGATE)
2665 switch (length)
2666 {
2667 default:
2668 {
2669 count=(ssize_t) gzread(image->blob->file,q,(unsigned int) length);
2670 break;
2671 }
2672 case 2:
2673 {
2674 c=gzgetc(image->blob->file);
2675 if (c == EOF)
2676 break;
2677 *q++=(unsigned char) c;
2678 count++;
2679 }
2680 case 1:
2681 {
2682 c=gzgetc(image->blob->file);
2683 if (c == EOF)
2684 break;
2685 *q++=(unsigned char) c;
2686 count++;
2687 }
2688 case 0:
2689 break;
2690 }
2691#endif
2692 break;
2693 }
2694 case BZipStream:
2695 {
2696#if defined(MAGICKCORE_BZLIB_DELEGATE)
2697 count=(ssize_t) BZ2_bzread((BZFILE *) image->blob->file,q,(int) length);
2698#endif
2699 break;
2700 }
2701 case FifoStream:
2702 break;
2703 case BlobStream:
2704 {
2705 register const unsigned char
2706 *p;
2707
2708 if (image->blob->offset >= (MagickOffsetType) image->blob->length)
2709 {
2710 image->blob->eof=MagickTrue;
2711 break;
2712 }
2713 p=image->blob->data+image->blob->offset;
2714 count=(ssize_t) MagickMin(length,(size_t) (image->blob->length-
2715 image->blob->offset));
2716 image->blob->offset+=count;
2717 if (count != (ssize_t) length)
2718 image->blob->eof=MagickTrue;
2719 (void) CopyMagickMemory(q,p,(size_t) count);
2720 break;
2721 }
2722 }
2723 return(count);
2724}
2725
2726/*
2727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2728% %
2729% %
2730% %
2731+ R e a d B l o b B y t e %
2732% %
2733% %
2734% %
2735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736%
2737% ReadBlobByte() reads a single byte from the image file and returns it.
2738%
2739% The format of the ReadBlobByte method is:
2740%
2741% int ReadBlobByte(Image *image)
2742%
2743% A description of each parameter follows.
2744%
2745% o image: the image.
2746%
2747*/
2748MagickExport int ReadBlobByte(Image *image)
2749{
2750 register const unsigned char
2751 *p;
2752
2753 ssize_t
2754 count;
2755
2756 unsigned char
2757 buffer[1];
2758
2759 assert(image != (Image *) NULL);
2760 assert(image->signature == MagickSignature);
2761 p=ReadBlobStream(image,1,buffer,&count);
2762 if (count != 1)
2763 return(EOF);
2764 return((int) (*p));
2765}
2766
2767/*
2768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2769% %
2770% %
2771% %
2772+ R e a d B l o b D o u b l e %
2773% %
2774% %
2775% %
2776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777%
2778% ReadBlobDouble() reads a double value as a 64-bit quantity in the byte-order
2779% specified by the endian member of the image structure.
2780%
2781% The format of the ReadBlobDouble method is:
2782%
2783% double ReadBlobDouble(Image *image)
2784%
2785% A description of each parameter follows.
2786%
2787% o image: the image.
2788%
2789*/
2790MagickExport double ReadBlobDouble(Image *image)
2791{
2792 union
2793 {
2794 MagickSizeType
2795 unsigned_value;
2796
2797 double
2798 double_value;
2799 } quantum;
2800
2801 quantum.double_value=0.0;
2802 quantum.unsigned_value=ReadBlobLongLong(image);
2803 return(quantum.double_value);
2804}
2805
2806/*
2807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2808% %
2809% %
2810% %
2811+ R e a d B l o b F l o a t %
2812% %
2813% %
2814% %
2815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2816%
2817% ReadBlobFloat() reads a float value as a 32-bit quantity in the byte-order
2818% specified by the endian member of the image structure.
2819%
2820% The format of the ReadBlobFloat method is:
2821%
2822% float ReadBlobFloat(Image *image)
2823%
2824% A description of each parameter follows.
2825%
2826% o image: the image.
2827%
2828*/
2829MagickExport float ReadBlobFloat(Image *image)
2830{
2831 union
2832 {
2833 unsigned int
2834 unsigned_value;
2835
2836 float
2837 float_value;
2838 } quantum;
2839
2840 quantum.float_value=0.0;
2841 quantum.unsigned_value=ReadBlobLong(image);
2842 return(quantum.float_value);
2843}
2844
2845/*
2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847% %
2848% %
2849% %
2850+ R e a d B l o b L o n g %
2851% %
2852% %
2853% %
2854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2855%
2856% ReadBlobLong() reads a long value as a 32-bit quantity in the byte-order
2857% specified by the endian member of the image structure.
2858%
2859% The format of the ReadBlobLong method is:
2860%
2861% unsigned int ReadBlobLong(Image *image)
2862%
2863% A description of each parameter follows.
2864%
2865% o image: the image.
2866%
2867*/
2868MagickExport unsigned int ReadBlobLong(Image *image)
2869{
2870 register const unsigned char
2871 *p;
2872
2873 ssize_t
2874 count;
2875
2876 unsigned char
2877 buffer[4];
2878
2879 unsigned int
2880 value;
2881
2882 assert(image != (Image *) NULL);
2883 assert(image->signature == MagickSignature);
2884 *buffer='\0';
2885 p=ReadBlobStream(image,4,buffer,&count);
2886 if (count != 4)
2887 return(0UL);
2888 if (image->endian == LSBEndian)
2889 {
2890 value=(unsigned int) (*p++);
2891 value|=((unsigned int) (*p++)) << 8;
2892 value|=((unsigned int) (*p++)) << 16;
2893 value|=((unsigned int) (*p++)) << 24;
2894 return(value);
2895 }
2896 value=((unsigned int) (*p++)) << 24;
2897 value|=((unsigned int) (*p++)) << 16;
2898 value|=((unsigned int) (*p++)) << 8;
2899 value|=((unsigned int) (*p++));
2900 return(value);
2901}
2902
2903/*
2904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2905% %
2906% %
2907% %
2908+ R e a d B l o b L o n g L o n g %
2909% %
2910% %
2911% %
2912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913%
2914% ReadBlobLongLong() reads a long value as a 64-bit quantity in the byte-order
2915% specified by the endian member of the image structure.
2916%
2917% The format of the ReadBlobLong method is:
2918%
2919% MagickSizeType ReadBlobLong(Image *image)
2920%
2921% A description of each parameter follows.
2922%
2923% o image: the image.
2924%
2925*/
2926MagickExport MagickSizeType ReadBlobLongLong(Image *image)
2927{
2928 register const unsigned char
2929 *p;
2930
2931 ssize_t
2932 count;
2933
2934 unsigned char
2935 buffer[8];
2936
2937 MagickSizeType
2938 value;
2939
2940 assert(image != (Image *) NULL);
2941 assert(image->signature == MagickSignature);
2942 *buffer='\0';
2943 p=ReadBlobStream(image,8,buffer,&count);
2944 if (count != 8)
2945 return(MagickULLConstant(0));
2946 if (image->endian == LSBEndian)
2947 {
2948 value=(MagickSizeType) (*p++);
2949 value|=((MagickSizeType) (*p++)) << 8;
2950 value|=((MagickSizeType) (*p++)) << 16;
2951 value|=((MagickSizeType) (*p++)) << 24;
2952 value|=((MagickSizeType) (*p++)) << 32;
2953 value|=((MagickSizeType) (*p++)) << 40;
2954 value|=((MagickSizeType) (*p++)) << 48;
2955 value|=((MagickSizeType) (*p++)) << 56;
2956 return(value & MagickULLConstant(0xffffffffffffffff));
2957 }
2958 value=((MagickSizeType) (*p++)) << 56;
2959 value|=((MagickSizeType) (*p++)) << 48;
2960 value|=((MagickSizeType) (*p++)) << 40;
2961 value|=((MagickSizeType) (*p++)) << 32;
2962 value|=((MagickSizeType) (*p++)) << 24;
2963 value|=((MagickSizeType) (*p++)) << 16;
2964 value|=((MagickSizeType) (*p++)) << 8;
2965 value|=((MagickSizeType) (*p++));
2966 return(value & MagickULLConstant(0xffffffffffffffff));
2967}
2968
2969/*
2970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971% %
2972% %
2973% %
2974+ R e a d B l o b S h o r t %
2975% %
2976% %
2977% %
2978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2979%
2980% ReadBlobShort() reads a short value as a 16-bit quantity in the byte-order
2981% specified by the endian member of the image structure.
2982%
2983% The format of the ReadBlobShort method is:
2984%
2985% unsigned short ReadBlobShort(Image *image)
2986%
2987% A description of each parameter follows.
2988%
2989% o image: the image.
2990%
2991*/
2992MagickExport unsigned short ReadBlobShort(Image *image)
2993{
2994 register const unsigned char
2995 *p;
2996
2997 register unsigned int
2998 value;
2999
3000 ssize_t
3001 count;
3002
3003 unsigned char
3004 buffer[2];
3005
3006 assert(image != (Image *) NULL);
3007 assert(image->signature == MagickSignature);
3008 *buffer='\0';
3009 p=ReadBlobStream(image,2,buffer,&count);
3010 if (count != 2)
3011 return((unsigned short) 0U);
3012 if (image->endian == LSBEndian)
3013 {
3014 value=(unsigned int) (*p++);
3015 value|=((unsigned int) (*p++)) << 8;
3016 return((unsigned short) (value & 0xffff));
3017 }
3018 value=(unsigned int) ((*p++) << 8);
3019 value|=(unsigned int) (*p++);
3020 return((unsigned short) (value & 0xffff));
3021}
3022
3023/*
3024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3025% %
3026% %
3027% %
3028+ R e a d B l o b L S B L o n g %
3029% %
3030% %
3031% %
3032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3033%
3034% ReadBlobLSBLong() reads a long value as a 32-bit quantity in
3035% least-significant byte first order.
3036%
3037% The format of the ReadBlobLSBLong method is:
3038%
3039% unsigned int ReadBlobLSBLong(Image *image)
3040%
3041% A description of each parameter follows.
3042%
3043% o image: the image.
3044%
3045*/
3046MagickExport unsigned int ReadBlobLSBLong(Image *image)
3047{
3048 register const unsigned char
3049 *p;
3050
3051 register unsigned int
3052 value;
3053
3054 ssize_t
3055 count;
3056
3057 unsigned char
3058 buffer[4];
3059
3060 assert(image != (Image *) NULL);
3061 assert(image->signature == MagickSignature);
3062 *buffer='\0';
3063 p=ReadBlobStream(image,4,buffer,&count);
3064 if (count != 4)
3065 return(0U);
3066 value=(unsigned int) (*p++);
3067 value|=((unsigned int) (*p++)) << 8;
3068 value|=((unsigned int) (*p++)) << 16;
3069 value|=((unsigned int) (*p++)) << 24;
3070 return(value);
3071}
3072
3073/*
3074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3075% %
3076% %
3077% %
3078+ R e a d B l o b L S B S h o r t %
3079% %
3080% %
3081% %
3082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3083%
3084% ReadBlobLSBShort() reads a short value as a 16-bit quantity in
3085% least-significant byte first order.
3086%
3087% The format of the ReadBlobLSBShort method is:
3088%
3089% unsigned short ReadBlobLSBShort(Image *image)
3090%
3091% A description of each parameter follows.
3092%
3093% o image: the image.
3094%
3095*/
3096MagickExport unsigned short ReadBlobLSBShort(Image *image)
3097{
3098 register const unsigned char
3099 *p;
3100
3101 register unsigned int
3102 value;
3103
3104 ssize_t
3105 count;
3106
3107 unsigned char
3108 buffer[2];
3109
3110 assert(image != (Image *) NULL);
3111 assert(image->signature == MagickSignature);
3112 *buffer='\0';
3113 p=ReadBlobStream(image,2,buffer,&count);
3114 if (count != 2)
3115 return((unsigned short) 0U);
3116 value=(unsigned int) (*p++);
3117 value|=((unsigned int) ((*p++)) << 8);
3118 return((unsigned short) (value & 0xffff));
3119}
3120
3121/*
3122%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3123% %
3124% %
3125% %
3126+ R e a d B l o b M S B L o n g %
3127% %
3128% %
3129% %
3130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3131%
3132% ReadBlobMSBLong() reads a long value as a 32-bit quantity in
3133% most-significant byte first order.
3134%
3135% The format of the ReadBlobMSBLong method is:
3136%
3137% unsigned int ReadBlobMSBLong(Image *image)
3138%
3139% A description of each parameter follows.
3140%
3141% o image: the image.
3142%
3143*/
3144MagickExport unsigned int ReadBlobMSBLong(Image *image)
3145{
3146 register const unsigned char
3147 *p;
3148
3149 register unsigned int
3150 value;
3151
3152 ssize_t
3153 count;
3154
3155 unsigned char
3156 buffer[4];
3157
3158 assert(image != (Image *) NULL);
3159 assert(image->signature == MagickSignature);
3160 *buffer='\0';
3161 p=ReadBlobStream(image,4,buffer,&count);
3162 if (count != 4)
3163 return(0UL);
3164 value=((unsigned int) (*p++) << 24);
3165 value|=((unsigned int) (*p++) << 16);
3166 value|=((unsigned int) (*p++) << 8);
3167 value|=(unsigned int) (*p++);
3168 return(value);
3169}
3170
3171/*
3172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3173% %
3174% %
3175% %
3176+ R e a d B l o b M S B S h o r t %
3177% %
3178% %
3179% %
3180%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3181%
3182% ReadBlobMSBShort() reads a short value as a 16-bit quantity in
3183% most-significant byte first order.
3184%
3185% The format of the ReadBlobMSBShort method is:
3186%
3187% unsigned short ReadBlobMSBShort(Image *image)
3188%
3189% A description of each parameter follows.
3190%
3191% o image: the image.
3192%
3193*/
3194MagickExport unsigned short ReadBlobMSBShort(Image *image)
3195{
3196 register const unsigned char
3197 *p;
3198
3199 register unsigned int
3200 value;
3201
3202 ssize_t
3203 count;
3204
3205 unsigned char
3206 buffer[2];
3207
3208 assert(image != (Image *) NULL);
3209 assert(image->signature == MagickSignature);
3210 *buffer='\0';
3211 p=ReadBlobStream(image,2,buffer,&count);
3212 if (count != 2)
3213 return((unsigned short) 0U);
3214 value=(unsigned int) ((*p++) << 8);
3215 value|=(unsigned int) (*p++);
3216 return((unsigned short) (value & 0xffff));
3217}
3218
3219/*
3220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3221% %
3222% %
3223% %
3224+ R e a d B l o b S t r i n g %
3225% %
3226% %
3227% %
3228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3229%
3230% ReadBlobString() reads characters from a blob or file until a newline
3231% character is read or an end-of-file condition is encountered.
3232%
3233% The format of the ReadBlobString method is:
3234%
3235% char *ReadBlobString(Image *image,char *string)
3236%
3237% A description of each parameter follows:
3238%
3239% o image: the image.
3240%
3241% o string: the address of a character buffer.
3242%
3243*/
3244MagickExport char *ReadBlobString(Image *image,char *string)
3245{
3246 register const unsigned char
3247 *p;
3248
3249 register long
3250 i;
3251
3252 ssize_t
3253 count;
3254
3255 unsigned char
3256 buffer[1];
3257
3258 assert(image != (Image *) NULL);
3259 assert(image->signature == MagickSignature);
3260 for (i=0; i < (MaxTextExtent-1L); i++)
3261 {
3262 p=ReadBlobStream(image,1,buffer,&count);
3263 if (count != 1)
3264 {
3265 if (i == 0)
3266 return((char *) NULL);
3267 break;
3268 }
3269 string[i]=(char) (*p);
3270 if ((string[i] == '\n') || (string[i] == '\r'))
3271 break;
3272 }
3273 string[i]='\0';
3274 return(string);
3275}
3276
3277/*
3278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3279% %
3280% %
3281% %
3282+ R e f e r e n c e B l o b %
3283% %
3284% %
3285% %
3286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3287%
3288% ReferenceBlob() increments the reference count associated with the pixel
3289% blob returning a pointer to the blob.
3290%
3291% The format of the ReferenceBlob method is:
3292%
3293% BlobInfo ReferenceBlob(BlobInfo *blob_info)
3294%
3295% A description of each parameter follows:
3296%
3297% o blob_info: the blob_info.
3298%
3299*/
3300MagickExport BlobInfo *ReferenceBlob(BlobInfo *blob)
3301{
3302 assert(blob != (BlobInfo *) NULL);
3303 assert(blob->signature == MagickSignature);
3304 if (blob->debug != MagickFalse)
3305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +00003306 LockSemaphoreInfo(blob->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00003307 blob->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00003308 UnlockSemaphoreInfo(blob->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00003309 return(blob);
3310}
3311
3312/*
3313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3314% %
3315% %
3316% %
3317+ S e e k B l o b %
3318% %
3319% %
3320% %
3321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3322%
3323% SeekBlob() sets the offset in bytes from the beginning of a blob or file
3324% and returns the resulting offset.
3325%
3326% The format of the SeekBlob method is:
3327%
3328% MagickOffsetType SeekBlob(Image *image,const MagickOffsetType offset,
3329% const int whence)
3330%
3331% A description of each parameter follows:
3332%
3333% o image: the image.
3334%
3335% o offset: Specifies an integer representing the offset in bytes.
3336%
3337% o whence: Specifies an integer representing how the offset is
3338% treated relative to the beginning of the blob as follows:
3339%
3340% SEEK_SET Set position equal to offset bytes.
3341% SEEK_CUR Set position to current location plus offset.
3342% SEEK_END Set position to EOF plus offset.
3343%
3344*/
3345MagickExport MagickOffsetType SeekBlob(Image *image,
3346 const MagickOffsetType offset,const int whence)
3347{
3348 assert(image != (Image *) NULL);
3349 assert(image->signature == MagickSignature);
3350 if (image->debug != MagickFalse)
3351 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3352 assert(image->blob != (BlobInfo *) NULL);
3353 assert(image->blob->type != UndefinedStream);
3354 switch (image->blob->type)
3355 {
3356 case UndefinedStream:
3357 break;
3358 case FileStream:
3359 {
3360 if (fseek(image->blob->file,offset,whence) < 0)
3361 return(-1);
3362 image->blob->offset=TellBlob(image);
3363 break;
3364 }
3365 case StandardStream:
3366 case PipeStream:
3367 case ZipStream:
3368 {
3369#if defined(MAGICKCORE_ZLIB_DELEGATE)
3370 if (gzseek(image->blob->file,(off_t) offset,whence) < 0)
3371 return(-1);
3372#endif
3373 image->blob->offset=TellBlob(image);
3374 break;
3375 }
3376 case BZipStream:
3377 return(-1);
3378 case FifoStream:
3379 return(-1);
3380 case BlobStream:
3381 {
3382 switch (whence)
3383 {
3384 case SEEK_SET:
3385 default:
3386 {
3387 if (offset < 0)
3388 return(-1);
3389 image->blob->offset=offset;
3390 break;
3391 }
3392 case SEEK_CUR:
3393 {
3394 if ((image->blob->offset+offset) < 0)
3395 return(-1);
3396 image->blob->offset+=offset;
3397 break;
3398 }
3399 case SEEK_END:
3400 {
3401 if (((MagickOffsetType) image->blob->length+offset) < 0)
3402 return(-1);
3403 image->blob->offset=image->blob->length+offset;
3404 break;
3405 }
3406 }
3407 if (image->blob->offset <= (MagickOffsetType)
3408 ((off_t) image->blob->length))
3409 image->blob->eof=MagickFalse;
3410 else
3411 if (image->blob->mapped != MagickFalse)
3412 return(-1);
3413 else
3414 {
3415 image->blob->extent=(size_t) (image->blob->offset+
3416 image->blob->quantum);
3417 image->blob->data=(unsigned char *) ResizeQuantumMemory(
3418 image->blob->data,image->blob->extent+1,
3419 sizeof(*image->blob->data));
3420 (void) SyncBlob(image);
3421 if (image->blob->data == (unsigned char *) NULL)
3422 {
3423 (void) DetachBlob(image->blob);
3424 return(-1);
3425 }
3426 }
3427 break;
3428 }
3429 }
3430 return(image->blob->offset);
3431}
3432
3433/*
3434%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3435% %
3436% %
3437% %
3438+ S e t B l o b E x e m p t %
3439% %
3440% %
3441% %
3442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3443%
3444% SetBlobExempt() sets the blob exempt status.
3445%
3446% The format of the SetBlobExempt method is:
3447%
3448% MagickBooleanType SetBlobExempt(const Image *image,
3449% const MagickBooleanType exempt)
3450%
3451% A description of each parameter follows:
3452%
3453% o image: the image.
3454%
3455% o exempt: Set to true if this blob is exempt from being closed.
3456%
3457*/
3458MagickExport void SetBlobExempt(Image *image,const MagickBooleanType exempt)
3459{
3460 assert(image != (const Image *) NULL);
3461 assert(image->signature == MagickSignature);
3462 if (image->debug != MagickFalse)
3463 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3464 image->blob->exempt=exempt;
3465}
3466
3467/*
3468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3469% %
3470% %
3471% %
3472+ S e t B l o b E x t e n t %
3473% %
3474% %
3475% %
3476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3477%
3478% SetBlobExtent() ensures enough space is allocated for the blob. If the
3479% method is successful, subsequent writes to bytes in the specified range are
3480% guaranteed not to fail.
3481%
3482% The format of the SetBlobExtent method is:
3483%
3484% MagickBooleanType SetBlobExtent(Image *image,const MagickSizeType extent)
3485%
3486% A description of each parameter follows:
3487%
3488% o image: the image.
3489%
3490% o extent: the blob maximum extent.
3491%
3492*/
3493MagickExport MagickBooleanType SetBlobExtent(Image *image,
3494 const MagickSizeType extent)
3495{
3496 assert(image != (Image *) NULL);
3497 assert(image->signature == MagickSignature);
3498 if (image->debug != MagickFalse)
3499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3500 assert(image->blob != (BlobInfo *) NULL);
3501 assert(image->blob->type != UndefinedStream);
3502 switch (image->blob->type)
3503 {
3504 case UndefinedStream:
3505 break;
3506 case FileStream:
3507 {
3508 if (extent != (MagickSizeType) ((off_t) extent))
3509 return(MagickFalse);
3510#if !defined(MAGICKCORE_POSIX_FALLOCATE)
3511 return(MagickFalse);
3512#else
3513 {
3514 int
3515 status;
3516
3517 MagickOffsetType
3518 offset;
3519
3520 offset=TellBlob(image);
3521 status=posix_fallocate(fileno(image->blob->file),(off_t) offset,
3522 (off_t) (extent-offset));
3523 if (status != 0)
3524 return(MagickFalse);
3525 }
3526#endif
3527 break;
3528 }
3529 case StandardStream:
3530 case PipeStream:
3531 case ZipStream:
3532 return(MagickFalse);
3533 case BZipStream:
3534 return(MagickFalse);
3535 case FifoStream:
3536 return(MagickFalse);
3537 case BlobStream:
3538 {
3539 if (image->blob->mapped != MagickFalse)
3540 {
3541 if (image->blob->file == (FILE *) NULL)
3542 return(MagickFalse);
3543 (void) UnmapBlob(image->blob->data,image->blob->length);
3544#if !defined(MAGICKCORE_POSIX_FALLOCATE)
3545 return(MagickFalse);
3546#else
3547 {
3548 int
3549 status;
3550
3551 MagickOffsetType
3552 offset;
3553
3554 offset=TellBlob(image);
3555 status=posix_fallocate(fileno(image->blob->file),(off_t) offset,
3556 (off_t) (extent-offset));
3557 if (status != 0)
3558 return(MagickFalse);
3559 }
3560 image->blob->data=(unsigned char*) MapBlob(fileno(image->blob->file),
3561 WriteMode,0,(size_t) extent);
3562 image->blob->extent=(size_t) extent;
3563 image->blob->length=(size_t) extent;
3564 (void) SyncBlob(image);
3565 break;
3566#endif
3567 }
3568 if (extent != (MagickSizeType) ((size_t) extent))
3569 return(MagickFalse);
3570 image->blob->extent=(size_t) extent;
3571 image->blob->data=(unsigned char *) ResizeQuantumMemory(image->blob->data,
3572 image->blob->extent+1,sizeof(*image->blob->data));
3573 (void) SyncBlob(image);
3574 if (image->blob->data == (unsigned char *) NULL)
3575 {
3576 (void) DetachBlob(image->blob);
3577 return(MagickFalse);
3578 }
3579 break;
3580 }
3581 }
3582 return(MagickTrue);
3583}
3584
3585/*
3586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3587% %
3588% %
3589% %
3590+ S y n c B l o b %
3591% %
3592% %
3593% %
3594%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3595%
3596% SyncBlob() flushes the datastream if it is a file or synchronizes the data
3597% attributes if it is an blob.
3598%
3599% The format of the SyncBlob method is:
3600%
3601% int SyncBlob(Image *image)
3602%
3603% A description of each parameter follows:
3604%
3605% o image: the image.
3606%
3607*/
3608static int SyncBlob(Image *image)
3609{
3610 int
3611 status;
3612
3613 assert(image != (Image *) NULL);
3614 assert(image->signature == MagickSignature);
3615 if (image->debug != MagickFalse)
3616 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3617 assert(image->blob != (BlobInfo *) NULL);
3618 assert(image->blob->type != UndefinedStream);
3619 status=0;
3620 switch (image->blob->type)
3621 {
3622 case UndefinedStream:
3623 break;
3624 case FileStream:
3625 case StandardStream:
3626 case PipeStream:
3627 {
3628 status=fflush(image->blob->file);
3629 break;
3630 }
3631 case ZipStream:
3632 {
3633#if defined(MAGICKCORE_ZLIB_DELEGATE)
3634 status=gzflush(image->blob->file,Z_SYNC_FLUSH);
3635#endif
3636 break;
3637 }
3638 case BZipStream:
3639 {
3640#if defined(MAGICKCORE_BZLIB_DELEGATE)
3641 status=BZ2_bzflush((BZFILE *) image->blob->file);
3642#endif
3643 break;
3644 }
3645 case FifoStream:
3646 break;
3647 case BlobStream:
3648 {
3649#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
3650 if (image->blob->mapped != MagickFalse)
3651 status=msync(image->blob->data,image->blob->length,MS_SYNC);
3652#endif
3653 break;
3654 }
3655 }
3656 return(status);
3657}
3658
3659/*
3660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3661% %
3662% %
3663% %
3664+ T e l l B l o b %
3665% %
3666% %
3667% %
3668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3669%
3670% TellBlob() obtains the current value of the blob or file position.
3671%
3672% The format of the TellBlob method is:
3673%
3674% MagickOffsetType TellBlob(const Image *image)
3675%
3676% A description of each parameter follows:
3677%
3678% o image: the image.
3679%
3680*/
3681MagickExport MagickOffsetType TellBlob(const Image *image)
3682{
3683 MagickOffsetType
3684 offset;
3685
3686 assert(image != (Image *) NULL);
3687 assert(image->signature == MagickSignature);
3688 if (image->debug != MagickFalse)
3689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3690 assert(image->blob != (BlobInfo *) NULL);
3691 assert(image->blob->type != UndefinedStream);
3692 offset=(-1);
3693 switch (image->blob->type)
3694 {
3695 case UndefinedStream:
3696 break;
3697 case FileStream:
3698 {
3699 offset=ftell(image->blob->file);
3700 break;
3701 }
3702 case StandardStream:
3703 case PipeStream:
3704 break;
3705 case ZipStream:
3706 {
3707#if defined(MAGICKCORE_ZLIB_DELEGATE)
3708 offset=(MagickOffsetType) gztell(image->blob->file);
3709#endif
3710 break;
3711 }
3712 case BZipStream:
3713 break;
3714 case FifoStream:
3715 break;
3716 case BlobStream:
3717 {
3718 offset=image->blob->offset;
3719 break;
3720 }
3721 }
3722 return(offset);
3723}
3724
3725/*
3726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727% %
3728% %
3729% %
3730+ U n m a p B l o b %
3731% %
3732% %
3733% %
3734%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3735%
3736% UnmapBlob() deallocates the binary large object previously allocated with
3737% the MapBlob method.
3738%
3739% The format of the UnmapBlob method is:
3740%
3741% MagickBooleanType UnmapBlob(void *map,const size_t length)
3742%
3743% A description of each parameter follows:
3744%
3745% o map: the address of the binary large object.
3746%
3747% o length: the length of the binary large object.
3748%
3749*/
3750MagickExport MagickBooleanType UnmapBlob(void *map,const size_t length)
3751{
3752#if defined(MAGICKCORE_HAVE_MMAP_FILEIO)
3753 int
3754 status;
3755
3756 status=munmap(map,length);
3757 return(status == -1 ? MagickFalse : MagickTrue);
3758#else
3759 (void) map;
3760 (void) length;
3761 return(MagickFalse);
3762#endif
3763}
3764
3765/*
3766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767% %
3768% %
3769% %
3770+ W r i t e B l o b %
3771% %
3772% %
3773% %
3774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3775%
3776% WriteBlob() writes data to a blob or image file. It returns the number of
3777% bytes written.
3778%
3779% The format of the WriteBlob method is:
3780%
3781% ssize_t WriteBlob(Image *image,const size_t length,
3782% const unsigned char *data)
3783%
3784% A description of each parameter follows:
3785%
3786% o image: the image.
3787%
3788% o length: Specifies an integer representing the number of bytes to
3789% write to the file.
3790%
3791% o data: The address of the data to write to the blob or file.
3792%
3793*/
3794MagickExport ssize_t WriteBlob(Image *image,const size_t length,
3795 const unsigned char *data)
3796{
3797 int
3798 c;
3799
3800 register const unsigned char
3801 *p;
3802
3803 ssize_t
3804 count;
3805
3806 assert(image != (Image *) NULL);
3807 assert(image->signature == MagickSignature);
3808 assert(data != (const unsigned char *) NULL);
3809 assert(image->blob != (BlobInfo *) NULL);
3810 assert(image->blob->type != UndefinedStream);
3811 if (length == 0)
3812 return(0);
3813 count=0;
3814 p=data;
3815 switch (image->blob->type)
3816 {
3817 case UndefinedStream:
3818 break;
3819 case FileStream:
3820 case StandardStream:
3821 case PipeStream:
3822 {
3823 switch (length)
3824 {
3825 default:
3826 {
3827 count=(ssize_t) fwrite((const char *) data,1,length,
3828 image->blob->file);
3829 break;
3830 }
3831 case 2:
3832 {
3833 c=putc((int) *p++,image->blob->file);
3834 if (c == EOF)
3835 break;
3836 count++;
3837 }
3838 case 1:
3839 {
3840 c=putc((int) *p++,image->blob->file);
3841 if (c == EOF)
3842 break;
3843 count++;
3844 }
3845 case 0:
3846 break;
3847 }
3848 break;
3849 }
3850 case ZipStream:
3851 {
3852#if defined(MAGICKCORE_ZLIB_DELEGATE)
3853 switch (length)
3854 {
3855 default:
3856 {
3857 count=(ssize_t) gzwrite(image->blob->file,(void *) data,
3858 (unsigned int) length);
3859 break;
3860 }
3861 case 2:
3862 {
3863 c=gzputc(image->blob->file,(int) *p++);
3864 if (c == EOF)
3865 break;
3866 count++;
3867 }
3868 case 1:
3869 {
3870 c=gzputc(image->blob->file,(int) *p++);
3871 if (c == EOF)
3872 break;
3873 count++;
3874 }
3875 case 0:
3876 break;
3877 }
3878#endif
3879 break;
3880 }
3881 case BZipStream:
3882 {
3883#if defined(MAGICKCORE_BZLIB_DELEGATE)
3884 count=(ssize_t) BZ2_bzwrite((BZFILE *) image->blob->file,(void *) data,
3885 (int) length);
3886#endif
3887 break;
3888 }
3889 case FifoStream:
3890 {
3891 count=(ssize_t) image->blob->stream(image,data,length);
3892 break;
3893 }
3894 case BlobStream:
3895 {
3896 register unsigned char
3897 *q;
3898
3899 if ((image->blob->offset+(MagickOffsetType) length) >=
3900 (MagickOffsetType) image->blob->extent)
3901 {
3902 if (image->blob->mapped != MagickFalse)
3903 return(0);
3904 image->blob->quantum<<=1;
3905 image->blob->extent+=length+image->blob->quantum;
3906 image->blob->data=(unsigned char *) ResizeQuantumMemory(
3907 image->blob->data,image->blob->extent+1,sizeof(*image->blob->data));
3908 (void) SyncBlob(image);
3909 if (image->blob->data == (unsigned char *) NULL)
3910 {
3911 (void) DetachBlob(image->blob);
3912 return(0);
3913 }
3914 }
3915 q=image->blob->data+image->blob->offset;
3916 (void) CopyMagickMemory(q,p,length);
3917 image->blob->offset+=length;
3918 if (image->blob->offset >= (MagickOffsetType) image->blob->length)
3919 image->blob->length=(size_t) image->blob->offset;
3920 count=(ssize_t) length;
3921 }
3922 }
3923 return(count);
3924}
3925
3926/*
3927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3928% %
3929% %
3930% %
3931+ W r i t e B l o b B y t e %
3932% %
3933% %
3934% %
3935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3936%
3937% WriteBlobByte() write an integer to a blob. It returns the number of bytes
3938% written (either 0 or 1);
3939%
3940% The format of the WriteBlobByte method is:
3941%
3942% ssize_t WriteBlobByte(Image *image,const unsigned char value)
3943%
3944% A description of each parameter follows.
3945%
3946% o image: the image.
3947%
3948% o value: Specifies the value to write.
3949%
3950*/
3951MagickExport ssize_t WriteBlobByte(Image *image,const unsigned char value)
3952{
3953 assert(image != (Image *) NULL);
3954 assert(image->signature == MagickSignature);
3955 return(WriteBlobStream(image,1,&value));
3956}
3957
3958/*
3959%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3960% %
3961% %
3962% %
3963+ W r i t e B l o b F l o a t %
3964% %
3965% %
3966% %
3967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3968%
3969% WriteBlobFloat() writes a float value as a 32-bit quantity in the byte-order
3970% specified by the endian member of the image structure.
3971%
3972% The format of the WriteBlobFloat method is:
3973%
3974% ssize_t WriteBlobFloat(Image *image,const float value)
3975%
3976% A description of each parameter follows.
3977%
3978% o image: the image.
3979%
3980% o value: Specifies the value to write.
3981%
3982*/
3983MagickExport ssize_t WriteBlobFloat(Image *image,const float value)
3984{
3985 union
3986 {
3987 unsigned int
3988 unsigned_value;
3989
3990 float
3991 float_value;
3992 } quantum;
3993
3994 quantum.unsigned_value=0U;
3995 quantum.float_value=value;
3996 return(WriteBlobLong(image,quantum.unsigned_value));
3997}
3998
3999/*
4000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4001% %
4002% %
4003% %
4004+ W r i t e B l o b L o n g %
4005% %
4006% %
4007% %
4008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4009%
4010% WriteBlobLong() writes a long value as a 32-bit quantity in the byte-order
4011% specified by the endian member of the image structure.
4012%
4013% The format of the WriteBlobLong method is:
4014%
4015% ssize_t WriteBlobLong(Image *image,const unsigned int value)
4016%
4017% A description of each parameter follows.
4018%
4019% o image: the image.
4020%
4021% o value: Specifies the value to write.
4022%
4023*/
4024MagickExport ssize_t WriteBlobLong(Image *image,const unsigned int value)
4025{
4026 unsigned char
4027 buffer[4];
4028
4029 assert(image != (Image *) NULL);
4030 assert(image->signature == MagickSignature);
4031 if (image->endian == LSBEndian)
4032 {
4033 buffer[0]=(unsigned char) value;
4034 buffer[1]=(unsigned char) (value >> 8);
4035 buffer[2]=(unsigned char) (value >> 16);
4036 buffer[3]=(unsigned char) (value >> 24);
4037 return(WriteBlobStream(image,4,buffer));
4038 }
4039 buffer[0]=(unsigned char) (value >> 24);
4040 buffer[1]=(unsigned char) (value >> 16);
4041 buffer[2]=(unsigned char) (value >> 8);
4042 buffer[3]=(unsigned char) value;
4043 return(WriteBlobStream(image,4,buffer));
4044}
4045
4046/*
4047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4048% %
4049% %
4050% %
4051+ W r i t e B l o b S h o r t %
4052% %
4053% %
4054% %
4055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4056%
4057% WriteBlobShort() writes a short value as a 16-bit quantity in the
4058% byte-order specified by the endian member of the image structure.
4059%
4060% The format of the WriteBlobShort method is:
4061%
4062% ssize_t WriteBlobShort(Image *image,const unsigned short value)
4063%
4064% A description of each parameter follows.
4065%
4066% o image: the image.
4067%
4068% o value: Specifies the value to write.
4069%
4070*/
4071MagickExport ssize_t WriteBlobShort(Image *image,const unsigned short value)
4072{
4073 unsigned char
4074 buffer[2];
4075
4076 assert(image != (Image *) NULL);
4077 assert(image->signature == MagickSignature);
4078 if (image->endian == LSBEndian)
4079 {
4080 buffer[0]=(unsigned char) value;
4081 buffer[1]=(unsigned char) (value >> 8);
4082 return(WriteBlobStream(image,2,buffer));
4083 }
4084 buffer[0]=(unsigned char) (value >> 8);
4085 buffer[1]=(unsigned char) value;
4086 return(WriteBlobStream(image,2,buffer));
4087}
4088
4089/*
4090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4091% %
4092% %
4093% %
4094+ W r i t e B l o b L S B L o n g %
4095% %
4096% %
4097% %
4098%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4099%
4100% WriteBlobLSBLong() writes a long value as a 32-bit quantity in
4101% least-significant byte first order.
4102%
4103% The format of the WriteBlobLSBLong method is:
4104%
4105% ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
4106%
4107% A description of each parameter follows.
4108%
4109% o image: the image.
4110%
4111% o value: Specifies the value to write.
4112%
4113*/
4114MagickExport ssize_t WriteBlobLSBLong(Image *image,const unsigned int value)
4115{
4116 unsigned char
4117 buffer[4];
4118
4119 assert(image != (Image *) NULL);
4120 assert(image->signature == MagickSignature);
4121 buffer[0]=(unsigned char) value;
4122 buffer[1]=(unsigned char) (value >> 8);
4123 buffer[2]=(unsigned char) (value >> 16);
4124 buffer[3]=(unsigned char) (value >> 24);
4125 return(WriteBlobStream(image,4,buffer));
4126}
4127
4128/*
4129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4130% %
4131% %
4132% %
4133+ W r i t e B l o b L S B S h o r t %
4134% %
4135% %
4136% %
4137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4138%
4139% WriteBlobLSBShort() writes a long value as a 16-bit quantity in
4140% least-significant byte first order.
4141%
4142% The format of the WriteBlobLSBShort method is:
4143%
4144% ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
4145%
4146% A description of each parameter follows.
4147%
4148% o image: the image.
4149%
4150% o value: Specifies the value to write.
4151%
4152*/
4153MagickExport ssize_t WriteBlobLSBShort(Image *image,const unsigned short value)
4154{
4155 unsigned char
4156 buffer[2];
4157
4158 assert(image != (Image *) NULL);
4159 assert(image->signature == MagickSignature);
4160 buffer[0]=(unsigned char) value;
4161 buffer[1]=(unsigned char) (value >> 8);
4162 return(WriteBlobStream(image,2,buffer));
4163}
4164
4165/*
4166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4167% %
4168% %
4169% %
4170+ W r i t e B l o b M S B L o n g %
4171% %
4172% %
4173% %
4174%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4175%
4176% WriteBlobMSBLong() writes a long value as a 32-bit quantity in
4177% most-significant byte first order.
4178%
4179% The format of the WriteBlobMSBLong method is:
4180%
4181% ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
4182%
4183% A description of each parameter follows.
4184%
4185% o value: Specifies the value to write.
4186%
4187% o image: the image.
4188%
4189*/
4190MagickExport ssize_t WriteBlobMSBLong(Image *image,const unsigned int value)
4191{
4192 unsigned char
4193 buffer[4];
4194
4195 assert(image != (Image *) NULL);
4196 assert(image->signature == MagickSignature);
4197 buffer[0]=(unsigned char) (value >> 24);
4198 buffer[1]=(unsigned char) (value >> 16);
4199 buffer[2]=(unsigned char) (value >> 8);
4200 buffer[3]=(unsigned char) value;
4201 return(WriteBlobStream(image,4,buffer));
4202}
4203
4204/*
4205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4206% %
4207% %
4208% %
4209+ W r i t e B l o b M S B S h o r t %
4210% %
4211% %
4212% %
4213%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4214%
4215% WriteBlobMSBShort() writes a long value as a 16-bit quantity in
4216% most-significant byte first order.
4217%
4218% The format of the WriteBlobMSBShort method is:
4219%
4220% ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
4221%
4222% A description of each parameter follows.
4223%
4224% o value: Specifies the value to write.
4225%
4226% o file: Specifies the file to write the data to.
4227%
4228*/
4229MagickExport ssize_t WriteBlobMSBShort(Image *image,const unsigned short value)
4230{
4231 unsigned char
4232 buffer[2];
4233
4234 assert(image != (Image *) NULL);
4235 assert(image->signature == MagickSignature);
4236 buffer[0]=(unsigned char) (value >> 8);
4237 buffer[1]=(unsigned char) value;
4238 return(WriteBlobStream(image,2,buffer));
4239}
4240
4241/*
4242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4243% %
4244% %
4245% %
4246+ W r i t e B l o b S t r i n g %
4247% %
4248% %
4249% %
4250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4251%
4252% WriteBlobString() write a string to a blob. It returns the number of
4253% characters written.
4254%
4255% The format of the WriteBlobString method is:
4256%
4257% ssize_t WriteBlobString(Image *image,const char *string)
4258%
4259% A description of each parameter follows.
4260%
4261% o image: the image.
4262%
4263% o string: Specifies the string to write.
4264%
4265*/
4266MagickExport ssize_t WriteBlobString(Image *image,const char *string)
4267{
4268 assert(image != (Image *) NULL);
4269 assert(image->signature == MagickSignature);
4270 assert(string != (const char *) NULL);
4271 return(WriteBlobStream(image,strlen(string),(const unsigned char *) string));
4272}