root/WizardsToolkit/trunk/wizard/blob.c

Revision 462, 61.9 KB (checked in by cristy, 4 weeks ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                         BBBB   L       OOO   BBBB                           %
7%                         B   B  L      O   O  B   B                          %
8%                         BBBB   L      O   O  BBBB                           %
9%                         B   B  L      O   O  B   B                          %
10%                         BBBB   LLLLL   OOO   BBBB                           %
11%                                                                             %
12%                                                                             %
13%                  Wizard's Toolkit Binary Large OBjectS Methods              %
14%                                                                             %
15%                                                                             %
16%                              Software Design                                %
17%                                John Cristy                                  %
18%                                March 2003                                   %
19%                                                                             %
20%                                                                             %
21%  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
22%  dedicated to making software imaging solutions freely available.           %
23%                                                                             %
24%  You may not use this file except in compliance with the License.  You may  %
25%  obtain a copy of the License at                                            %
26%                                                                             %
27%    http://www.wizards-toolkit.org/script/license.php                        %
28%                                                                             %
29%  Unless required by applicable law or agreed to in writing, software        %
30%  distributed under the License is distributed on an "AS IS" BASIS,          %
31%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32%  See the License for the specific language governing permissions and        %
33%  limitations under the License.                                             %
34%                                                                             %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38%
39*/
40
41/*
42  Include declarations.
43*/
44#include "wizard/studio.h"
45#include "wizard/blob.h"
46#include "wizard/blob-private.h"
47#include "wizard/cipher.h"
48#include "wizard/exception.h"
49#include "wizard/exception-private.h"
50#include "wizard/memory_.h"
51#include "wizard/semaphore.h"
52#include "wizard/utility.h"
53#include "blob.h"
54#if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO) && !defined(__WINDOWS__)
55# include <sys/mman.h>
56#endif
57#include "bzlib.h"
58#include "zlib.h"
59
60/*
61  Define declarations.
62*/
63#define WizardMaxBlobExtent  65541
64# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
65define MAP_ANONYMOUS MAP_ANON
66# endif
67#if !defined(MAP_FAILED)
68#define MAP_FAILED      ((void *) -1)
69#endif
70#if !defined(MS_SYNC)
71#define MS_SYNC  0x04
72#endif
73
74/*
75  Typedef declarations.
76*/
77typedef enum
78{
79  UndefinedStream,
80  FileStream,
81  StandardStream,
82  PipeStream,
83  ZipStream,
84  BZipStream,
85  BlobStream
86} StreamType;
87
88struct _BlobInfo
89{
90  char
91    filename[MaxTextExtent];
92
93  size_t
94    length,
95    extent,
96    quantum;
97
98  WizardBooleanType
99    mapped,
100    eof;
101
102  WizardOffsetType
103    offset;
104
105  WizardSizeType
106    size;
107
108  WizardBooleanType
109    exempt,
110    status,
111    temporary;
112
113  StreamType
114    type;
115
116  FILE
117    *file;
118
119  struct stat
120    properties;
121
122  unsigned char
123    *data;
124
125  WizardBooleanType
126    debug;
127
128  SemaphoreInfo
129    *semaphore;
130
131  long
132    reference_count;
133
134  unsigned long
135    signature;
136};
137
138/*
139  Forward declarations.
140*/
141static unsigned char
142  *DetachBlob(BlobInfo *);
143
144/*
145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146%                                                                             %
147%                                                                             %
148%                                                                             %
149+   A t t a c h B l o b                                                       %
150%                                                                             %
151%                                                                             %
152%                                                                             %
153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154%
155%  AttachBlob() attaches a blob to the BlobInfo structure.
156%
157%  The format of the AttachBlob method is:
158%
159%      void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
160%
161%  A description of each parameter follows:
162%
163%    o blob_info: the blob info.
164%
165%    o blob: the character stream to attach.
166%
167%    o length: the length in bytes of the blob.
168%
169*/
170static void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
171{
172  assert(blob_info != (BlobInfo *) NULL);
173  if (blob_info->debug != WizardFalse)
174    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
175  blob_info->length=length;
176  blob_info->extent=length;
177  blob_info->quantum=(size_t) WizardMaxBlobExtent;
178  blob_info->offset=0;
179  blob_info->type=BlobStream;
180  blob_info->file=(FILE *) NULL;
181  blob_info->data=(unsigned char *) blob;
182  blob_info->mapped=WizardFalse;
183}
184
185/*
186%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187%                                                                             %
188%                                                                             %
189%                                                                             %
190+   C l o s e B l o b                                                         %
191%                                                                             %
192%                                                                             %
193%                                                                             %
194%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
195%
196%  CloseBlob() closes a stream associated with the blob_info.
197%
198%  The format of the CloseBlob method is:
199%
200%      WizardBooleanType CloseBlob(BlobInfo *blob_info)
201%
202%  A description of each parameter follows:
203%
204%    o blob_info: the blob info.
205%
206*/
207WizardExport WizardBooleanType CloseBlob(BlobInfo *blob_info)
208{
209  int
210    status;
211
212  /*
213    Close blob_info file.
214  */
215  assert(blob_info != (BlobInfo *) NULL);
216  assert(blob_info->signature == WizardSignature);
217  if (blob_info->debug != WizardFalse)
218    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
219      blob_info->filename);
220  if (blob_info->type == UndefinedStream)
221    return(WizardTrue);
222  (void) SyncBlob(blob_info);
223  blob_info->size=GetBlobSize(blob_info);
224  blob_info->eof=WizardFalse;
225  if (blob_info->exempt != WizardFalse)
226    {
227      blob_info->type=UndefinedStream;
228      return(WizardTrue);
229    }
230  status=0;
231  switch (blob_info->type)
232  {
233    case UndefinedStream:
234      break;
235    case FileStream:
236    case StandardStream:
237    case PipeStream:
238    {
239      status=ferror(blob_info->file);
240      break;
241    }
242    case ZipStream:
243    {
244#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
245      (void) gzerror(blob_info->file,&status);
246#endif
247      break;
248    }
249    case BZipStream:
250    {
251#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
252      (void) BZ2_bzerror((BZFILE *) blob_info->file,&status);
253#endif
254      break;
255    }
256    case BlobStream:
257      break;
258  }
259  blob_info->status=status < 0 ? WizardTrue : WizardFalse;
260  switch (blob_info->type)
261  {
262    case UndefinedStream:
263      break;
264    case FileStream:
265    case StandardStream:
266    {
267      status=fclose(blob_info->file);
268      break;
269    }
270    case PipeStream:
271    {
272#if defined(WIZARDSTOOLKIT_HAVE_POPEN)
273      status=pclose(blob_info->file);
274#endif
275      break;
276    }
277    case ZipStream:
278    {
279#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
280      status=gzclose(blob_info->file);
281#endif
282      break;
283    }
284    case BZipStream:
285    {
286#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
287      BZ2_bzclose((BZFILE *) blob_info->file);
288#endif
289      break;
290    }
291    case BlobStream:
292      break;
293  }
294  (void) DetachBlob(blob_info);
295  blob_info->status=status < 0 ? WizardTrue : WizardFalse;
296  return(blob_info->status);
297}
298
299/*
300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301%                                                                             %
302%                                                                             %
303%                                                                             %
304+   D e s t r o y B l o b                                                     %
305%                                                                             %
306%                                                                             %
307%                                                                             %
308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309%
310%  DestroyBlob() deallocates memory associated with a blob.
311%
312%  The format of the DestroyBlob method is:
313%
314%      BlobInfo *DestroyBlob(BlobInfo *blob_info)
315%
316%  A description of each parameter follows:
317%
318%    o blob_info: the blob info.
319%
320*/
321WizardExport BlobInfo *DestroyBlob(BlobInfo *blob_info)
322{
323  WizardBooleanType
324    destroy;
325
326  assert(blob_info != (BlobInfo *) NULL);
327  assert(blob_info->signature == WizardSignature);
328  if (blob_info->debug != WizardFalse)
329    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
330      blob_info->filename);
331  destroy=WizardFalse;
332  (void) LockSemaphoreInfo(blob_info->semaphore);
333  blob_info->reference_count--;
334  if (blob_info->reference_count == 0)
335    destroy=WizardTrue;
336  (void) UnlockSemaphoreInfo(blob_info->semaphore);
337  if (destroy == WizardFalse)
338    return(blob_info);
339  (void) CloseBlob(blob_info);
340  if (blob_info->mapped != WizardFalse)
341    (void) UnmapBlob(blob_info->data,blob_info->length);
342  if (blob_info->semaphore != (SemaphoreInfo *) NULL)
343    DestroySemaphoreInfo(&blob_info->semaphore);
344  blob_info->signature=(~WizardSignature);
345  blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
346  return(blob_info);
347}
348
349/*
350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351%                                                                             %
352%                                                                             %
353%                                                                             %
354+   D e t a c h B l o b                                                       %
355%                                                                             %
356%                                                                             %
357%                                                                             %
358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359%
360%  DetachBlob() detaches a blob from the BlobInfo structure.
361%
362%  The format of the DetachBlob method is:
363%
364%      unsigned char *DetachBlob(BlobInfo *blob_info)
365%
366%  A description of each parameter follows:
367%
368%    o blob_info: the blob info.
369%
370*/
371static unsigned char *DetachBlob(BlobInfo *blob_info)
372{
373  unsigned char
374    *data;
375
376  assert(blob_info != (BlobInfo *) NULL);
377  if (blob_info->debug != WizardFalse)
378    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
379  if (blob_info->mapped != WizardFalse)
380    (void) UnmapBlob(blob_info->data,blob_info->length);
381  blob_info->mapped=WizardFalse;
382  blob_info->length=0;
383  blob_info->offset=0;
384  blob_info->eof=WizardFalse;
385  blob_info->exempt=WizardFalse;
386  blob_info->type=UndefinedStream;
387  blob_info->file=(FILE *) NULL;
388  data=blob_info->data;
389  blob_info->data=(unsigned char *) NULL;
390  return(data);
391}
392
393/*
394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395%                                                                             %
396%                                                                             %
397%                                                                             %
398+  E O F B l o b                                                              %
399%                                                                             %
400%                                                                             %
401%                                                                             %
402%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403%
404%  EOFBlob() returns a non-zero value when EOF has been detected reading from
405%  a blob or file.
406%
407%  The format of the EOFBlob method is:
408%
409%      int EOFBlob(BlobInfo *blob_info)
410%
411%  A description of each parameter follows:
412%
413%    o blob_info: the blob info.
414%
415*/
416WizardExport int EOFBlob(BlobInfo *blob_info)
417{
418  assert(blob_info != (BlobInfo *) NULL);
419  assert(blob_info->signature == WizardSignature);
420  if (blob_info->debug != WizardFalse)
421    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
422  assert(blob_info->type != UndefinedStream);
423  switch (blob_info->type)
424  {
425    case UndefinedStream:
426      break;
427    case FileStream:
428    case StandardStream:
429    case PipeStream:
430    {
431      blob_info->eof=feof(blob_info->file) != 0 ? WizardTrue : WizardFalse;
432      break;
433    }
434    case ZipStream:
435    {
436      blob_info->eof=WizardFalse;
437      break;
438    }
439    case BZipStream:
440    {
441#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
442      int
443        status;
444
445      status=0;
446      (void) BZ2_bzerror((BZFILE *) blob_info->file,&status);
447      blob_info->eof=status == BZ_UNEXPECTED_EOF ? WizardTrue : WizardFalse;
448#endif
449      break;
450    }
451    case BlobStream:
452      break;
453  }
454  return((int) blob_info->eof);
455}
456
457/*
458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459%                                                                             %
460%                                                                             %
461%                                                                             %
462%   F i l e T o B l o b                                                       %
463%                                                                             %
464%                                                                             %
465%                                                                             %
466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467%
468%  FileToBlob() returns the contents of a file as a blob.  It returns the
469%  file as a blob and its length.  If an error occurs, NULL is returned.
470%
471%  The format of the FileToBlob method is:
472%
473%      void *FileToBlob(const char *filename,const size_t extent,size_t *length,
474%        ExceptionInfo *exception)
475%
476%  A description of each parameter follows:
477%
478%    o blob:  FileToBlob() returns the contents of a file as a blob.  If
479%      an error occurs NULL is returned.
480%
481%    o filename: The filename.
482%
483%    o extent:  The maximum length of the blob.
484%
485%    o length: On return, it reflects the actual length of the blob.
486%
487%    o exception: Return any errors or warnings in this structure.
488%
489*/
490WizardExport unsigned char *FileToBlob(const char *filename,const size_t extent,
491  size_t *length,ExceptionInfo *exception)
492{
493  int
494    file;
495
496  off_t
497    offset;
498
499  register size_t
500    i;
501
502  ssize_t
503    count;
504
505  unsigned char
506    *blob;
507
508  void
509    *map;
510
511  assert(filename != (const char *) NULL);
512  (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",filename);
513  assert(exception != (ExceptionInfo *) NULL);
514  *length=0;
515  file=fileno(stdin);
516  if (strcmp(filename,"-") != 0)
517    file=open(filename,O_RDONLY | O_BINARY);
518  if (file == -1)
519    {
520      (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
521        "unable to open file `%s': %s",filename,strerror(errno));
522      return((unsigned char *) NULL);
523    }
524  offset=WizardSeek(file,0,SEEK_END);
525  count=0;
526  if ((offset < 0) || (offset != (off_t) ((ssize_t) offset)))
527    {
528      size_t
529        quantum;
530
531      struct stat
532        file_info;
533
534      /*
535        Stream is not seekable.
536      */
537      quantum=(size_t) WizardMaxBufferExtent;
538      if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
539        quantum=Min((size_t) file_info.st_size,WizardMaxBufferExtent);
540      blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
541      for (i=0; blob != (unsigned char *) NULL; i+=count)
542      {
543        count=read(file,blob+i,quantum);
544        if (count <= 0)
545          {
546            count=0;
547            if (errno != EINTR)
548              break;
549          }
550        if (~(1UL*i) < (quantum+1))
551          {
552            blob=(unsigned char *) RelinquishWizardMemory(blob);
553            break;
554          }
555        blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
556          sizeof(*blob));
557        if ((size_t) (i+count) >= extent)
558          break;
559      }
560      if (close(file) == -1)
561        (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
562          "unable to close file `%s': %s",filename,strerror(errno));
563      if (blob == (unsigned char *) NULL)
564        {
565          (void) ThrowWizardException(exception,GetWizardModule(),ResourceError,
566            "memory allocation failed: `%s'",filename);
567          return((unsigned char *) NULL);
568        }
569      *length=Min(i+count,extent);
570      blob[*length]='\0';
571      return(blob);
572    }
573  *length=Min((size_t) offset,extent);
574  blob=(unsigned char *) NULL;
575  if (~(*length) >= MaxCipherBlocksize)
576    blob=(unsigned char *) AcquireQuantumMemory(*length+MaxCipherBlocksize,
577      sizeof(*blob));
578  if (blob == (unsigned char *) NULL)
579    {
580      if (close(file) == -1)
581        {
582          (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
583            "unable to close file `%s': %s",filename,strerror(errno));
584          return((unsigned char *) NULL);
585        }
586      (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
587        "memory allocation failed `%s'",strerror(errno));
588      return((unsigned char *) NULL);
589    }
590  map=MapBlob(file,ReadMode,0,*length);
591  if (map != (void *) NULL)
592    {
593      (void) CopyWizardMemory(blob,map,*length);
594      if (UnmapBlob(map,*length) == WizardFalse)
595        (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
596          "unable to unmap blob `%s': %s",filename,strerror(errno));
597    }
598  else
599    {
600      register size_t
601        i;
602
603      ssize_t
604        count;
605
606      if (WizardSeek(file,0,SEEK_SET) < 0)
607        (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
608          "unable to seek blob `%s': %s",filename,strerror(errno));
609      for (i=0; i < *length; i+=count)
610      {
611        count=read(file,blob+i,Min(*length-i,(size_t) SSIZE_MAX));
612        if (count <= 0)
613          {
614            count=0;
615            if (errno != EINTR)
616              break;
617          }
618      }
619      if (i < *length)
620        {
621          if (close(file) == -1)
622            (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
623              "unable to close file `%s': %s",filename,strerror(errno));
624          blob=(unsigned char *) RelinquishWizardMemory(blob);
625          (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
626            "unable to read file `%s'",filename);
627          return((unsigned char *) NULL);
628        }
629    }
630  if (close(file) == -1)
631    (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
632      "unable to close file `%s': %s",filename,strerror(errno));
633  blob[*length]=(unsigned char) '\0';
634  return(blob);
635}
636
637/*
638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639%                                                                             %
640%                                                                             %
641%                                                                             %
642+  G e t B l o b F i l e n a m e                                              %
643%                                                                             %
644%                                                                             %
645%                                                                             %
646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647%
648%  GetBlobFilename() returns the blob filename.
649%
650%  The format of the GetBlobFilename method is:
651%
652%      const char *GetBlobFilename(const BlobInfo *blob_info)
653%
654%  A description of each parameter follows:
655%
656%    o blob_info: the blob info info.
657%
658*/
659WizardExport const char *GetBlobFilename(const BlobInfo *blob_info)
660{
661  assert(blob_info != (BlobInfo *) NULL);
662  if (blob_info->debug != WizardFalse)
663    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
664      blob_info->filename);
665  return(blob_info->filename);
666}
667
668/*
669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670%                                                                             %
671%                                                                             %
672%                                                                             %
673+   G e t B l o b I n f o                                                     %
674%                                                                             %
675%                                                                             %
676%                                                                             %
677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678%
679%  GetBlobInfo() initializes the BlobInfo structure.
680%
681%  The format of the GetBlobInfo method is:
682%
683%      void GetBlobInfo(BlobInfo *blob_info)
684%
685%  A description of each parameter follows:
686%
687%    o blob_info: Specifies a pointer to a BlobInfo structure.
688%
689*/
690WizardExport void GetBlobInfo(BlobInfo *blob_info)
691{
692  assert(blob_info != (BlobInfo *) NULL);
693  (void) ResetWizardMemory(blob_info,0,sizeof(*blob_info));
694  blob_info->type=UndefinedStream;
695  blob_info->quantum=(size_t) WizardMaxBlobExtent;
696  blob_info->debug=IsEventLogging();
697  blob_info->reference_count=1;
698  blob_info->semaphore=AllocateSemaphoreInfo();
699  blob_info->signature=WizardSignature;
700}
701
702/*
703%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704%                                                                             %
705%                                                                             %
706%                                                                             %
707+  G e t B l o b S i z e                                                      %
708%                                                                             %
709%                                                                             %
710%                                                                             %
711%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712%
713%  GetBlobSize() returns the current length of the blob; zero is returned if
714%  the size cannot be determined.
715%
716%  The format of the GetBlobSize method is:
717%
718%      WizardSizeType GetBlobSize(BlobInfo *blob_info)
719%
720%  A description of each parameter follows:
721%
722%    o blob_info: the blob info.
723%
724*/
725WizardExport WizardSizeType GetBlobSize(BlobInfo *blob_info)
726{
727  WizardSizeType
728    length;
729
730  assert(blob_info != (BlobInfo *) NULL);
731  if (blob_info->debug != WizardFalse)
732    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
733      blob_info->filename);
734  length=0;
735  switch (blob_info->type)
736  {
737    case UndefinedStream:
738    {
739      length=blob_info->size;
740      break;
741    }
742    case FileStream:
743    {
744      if (fstat(fileno(blob_info->file),&blob_info->properties) == 0)
745        length=(WizardSizeType) blob_info->properties.st_size;
746      break;
747    }
748    case StandardStream:
749    case PipeStream:
750    {
751      length=blob_info->size;
752      break;
753    }
754    case ZipStream:
755    {
756#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
757      if (fstat(fileno(blob_info->file),&blob_info->properties) == 0)
758        length=(WizardSizeType) blob_info->properties.st_size;
759#endif
760      break;
761    }
762    case BZipStream:
763    {
764#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
765      if (fstat(fileno(blob_info->file),&blob_info->properties) == 0)
766        length=(WizardSizeType) blob_info->properties.st_size;
767#endif
768      break;
769    }
770    case BlobStream:
771    {
772      length=(WizardSizeType) blob_info->length;
773      break;
774    }
775  }
776  return(length);
777}
778
779/*
780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781%                                                                             %
782%                                                                             %
783%                                                                             %
784%  G e t B l o b P r o p e r t i e s                                          %
785%                                                                             %
786%                                                                             %
787%                                                                             %
788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789%
790%  GetBlobProperties() returns information about a blob.
791%
792%  The format of the GetBlobProperties method is:
793%
794%      const struct stat *GetBlobProperties(const BlobInfo *blob_info)
795%
796%  A description of each parameter follows:
797%
798%    o blob_info: the blob info.
799%
800*/
801WizardExport const struct stat *GetBlobProperties(const BlobInfo *blob_info)
802{
803  assert(blob_info != (BlobInfo *) NULL);
804  if (blob_info->debug != WizardFalse)
805    (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
806      blob_info->filename);
807  return(&blob_info->properties);
808}
809
810/*
811%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
812%                                                                             %
813%                                                                             %
814%                                                                             %
815+  M a p B l o b                                                              %
816%                                                                             %
817%                                                                             %
818%                                                                             %
819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
820%
821%  MapBlob() creates a mapping from a file to a binary large object.
822%
823%  The format of the MapBlob method is:
824%
825%      void *MapBlob(int file,const MapMode mode,const WizardOffsetType offset,
826%        const size_t length)
827%
828%  A description of each parameter follows:
829%
830%    o file: map this file descriptor.
831%
832%    o mode: ReadMode, WriteMode, or IOMode.
833%
834%    o offset: starting at this offset within the file.
835%
836%    o length: the length of the mapping is returned in this pointer.
837%
838*/
839WizardExport void *MapBlob(int file,const MapMode mode,
840  const WizardOffsetType offset,const size_t length)
841{
842#if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO)
843  int
844    flags,
845    protection;
846
847  unsigned char
848    *map;
849
850  /*
851    Map file.
852  */
853  flags=0;
854  if (file == -1)
855#if defined(MAP_ANONYMOUS)
856    flags|=MAP_ANONYMOUS;
857#else
858    return((unsigned char *) NULL);
859#endif
860  flags|=MAP_PRIVATE;
861  switch (mode)
862  {
863    case ReadMode:
864    default:
865    {
866      protection=PROT_READ;
867      map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
868        (off_t) offset);
869      break;
870    }
871    case WriteMode:
872    {
873      protection=PROT_WRITE;
874      if (file != -1)
875        flags|=MAP_SHARED;
876      map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
877        (off_t) offset);
878      break;
879    }
880    case IOMode:
881    {
882      protection=PROT_READ | PROT_WRITE;
883      if (file != -1)
884        flags|=MAP_SHARED;
885      map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
886        (off_t) offset);
887      break;
888    }
889  }
890  if (map == (unsigned char *) MAP_FAILED)
891    return((unsigned char *) NULL);
892  return(map);
893#else
894  return((unsigned char *) NULL);
895#endif
896}
897
898/*
899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
900%                                                                             %
901%                                                                             %
902%                                                                             %
903+   O p e n B l o b                                                           %
904%                                                                             %
905%                                                                             %
906%                                                                             %
907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908%
909%  OpenBlob() opens a file associated with the blob.  A file name of '-' sets
910%  the file to stdin for type 'r' and stdout for type 'w'.  If the filename
911%  suffix is '.gz' or '.Z', the blob_info is decompressed for type 'r' and
912%  compressed for type 'w'.  If the filename prefix is '|', it is piped to or
913%  from a system command.
914%
915%  The format of the OpenBlob method is:
916%
917%       BlobInfo *OpenBlob(const char *filename,const BlobMode mode,
918%         const WizardBooleanType compress,ExceptionInfo *exception)
919%
920%  A description of each parameter follows:
921%
922%    o filename: the filename.
923%
924%    o mode: the mode for opening the file.
925%
926%    o compress: a value other than 0 (de)compresses BZIP or ZIP files.
927%
928%    o exception: return any errors or warnings in this structure.
929*/
930WizardExport BlobInfo *OpenBlob(const char *filename,const BlobMode mode,
931  const WizardBooleanType compress,ExceptionInfo *exception)
932{
933  BlobInfo
934    *blob_info;
935
936  const char
937    *type;
938
939  struct stat
940    *properties;
941
942  WizardBooleanType
943    status;
944
945  assert(filename != (const char *) NULL);
946  (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",filename);
947  assert(exception != (ExceptionInfo *) NULL);
948  blob_info=(BlobInfo *) AcquireWizardMemory(sizeof(*blob_info));
949  if (blob_info == (BlobInfo *) NULL)
950    {
951      (void) ThrowWizardException(exception,GetWizardModule(),ResourceError,
952        "memory allocation failed: `%s'",filename);
953      return((BlobInfo *) NULL);
954    }
955  GetBlobInfo(blob_info);
956  switch (mode)
957  {
958    default: type="r"; break;
959    case ReadBlobMode: type="r"; break;
960    case ReadBinaryBlobMode: type="rb"; break;
961    case WriteBlobMode: type="w"; break;
962    case WriteBinaryBlobMode: type="w+b"; break;
963  }
964  /*
965    Open file.
966  */
967  (void) CopyWizardString(blob_info->filename,filename,MaxTextExtent);
968  if (LocaleCompare(filename,"-") == 0)
969    {
970      blob_info->file=(*type == 'r') ? stdin : stdout;
971#if defined(__WINDOWS__)
972      if (strchr(type,'b') != (char *) NULL)
973        setmode(_fileno(blob_info->file),_O_BINARY);
974#endif
975      blob_info->type=StandardStream;
976      blob_info->exempt=WizardTrue;
977      return(blob_info);
978    }
979  if (LocaleNCompare(filename,"fd:",3) == 0)
980    {
981      char
982        mode[MaxTextExtent];
983
984      *mode=(*type);
985      mode[1]='\0';
986      blob_info->file=fdopen(atoi(filename+3),mode);
987#if defined(__WINDOWS__)
988      if (strchr(type,'b') != (char *) NULL)
989        setmode(_fileno(blob_info->file),_O_BINARY);
990#endif
991      blob_info->type=StandardStream;
992      blob_info->exempt=WizardTrue;
993      return(blob_info);
994    }
995#if defined(WIZARDSTOOLKIT_HAVE_POPEN)
996  if (*filename == '|')
997    {
998      char
999        mode[MaxTextExtent];
1000
1001      /*
1002        Pipe blob_info to or from a system command.
1003      */
1004#if defined(SIGPIPE)
1005      if (*type == 'w')
1006        (void) signal(SIGPIPE,SIG_IGN);
1007#endif
1008      *mode=(*type);
1009      mode[1]='\0';
1010      blob_info->file=(FILE *) popen(filename+1,mode);
1011      if (blob_info->file == (FILE *) NULL)
1012        {
1013          (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
1014            "unable to open file `%s': %s",filename,strerror(errno));
1015          blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
1016          return((BlobInfo *) NULL);
1017        }
1018      blob_info->type=PipeStream;
1019      blob_info->exempt=WizardTrue;
1020      return(blob_info);
1021    }
1022#endif
1023  status=stat(filename,&blob_info->properties) == 0 ? WizardTrue : WizardFalse;
1024#if defined(S_ISFIFO)
1025  if ((status == WizardTrue) && S_ISFIFO(blob_info->properties.st_mode))
1026    {
1027      blob_info->file=WizardOpenStream(filename,type);
1028      if (blob_info->file == (FILE *) NULL)
1029        {
1030          (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
1031            "unable to open file `%s': %s",filename,strerror(errno));
1032          blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
1033          return((BlobInfo *) NULL);
1034        }
1035      blob_info->type=FileStream;
1036      blob_info->exempt=WizardTrue;
1037      return(blob_info);
1038    }
1039#endif
1040#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
1041  if ((compress != WizardFalse) &&
1042      (((strlen(filename) > 2) &&
1043        (LocaleCompare(filename+strlen(filename)-2,".Z") == 0)) ||
1044       ((strlen(filename) > 3) &&
1045        (LocaleCompare(filename+strlen(filename)-3,".gz") == 0)) ||
1046       ((strlen(filename) > 4) &&
1047        (LocaleCompare(filename+strlen(filename)-4,".wmz") == 0)) ||
1048       ((strlen(filename) > 5) &&
1049        (LocaleCompare(filename+strlen(filename)-5,".svgz") == 0))))
1050    {
1051      blob_info->file=(FILE *) gzopen(filename,type);
1052      if (blob_info->file != (FILE *) NULL)
1053        blob_info->type=ZipStream;
1054    }
1055  else
1056#endif
1057#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
1058    if ((compress != WizardFalse) && (strlen(filename) > 4) &&
1059        (LocaleCompare(filename+strlen(filename)-4,".bz2") == 0))
1060      {
1061        blob_info->file=(FILE *) BZ2_bzopen(filename,type);
1062        if (blob_info->file != (FILE *) NULL)
1063          blob_info->type=BZipStream;
1064      }
1065    else
1066#endif
1067      {
1068        blob_info->file=WizardOpenStream(filename,type);
1069        if (blob_info->file != (FILE *) NULL)
1070          {
1071            blob_info->type=FileStream;
1072#if defined(WIZARDSTOOLKIT_HAVE_SETVBUF)
1073            (void) setvbuf(blob_info->file,(char *) NULL,(int) _IOFBF,16384);
1074#endif
1075            if (*type == 'r')
1076              {
1077                size_t
1078                  count;
1079
1080                unsigned char
1081                  magick[3];
1082
1083                (void) ResetWizardMemory(magick,0,sizeof(magick));
1084                count=fread(magick,1,sizeof(magick),blob_info->file);
1085                (void) rewind(blob_info->file);
1086                (void) LogWizardEvent(BlobEvent,GetWizardModule(),
1087                  "  read %ld magic header bytes",(long) count);
1088#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
1089                if ((compress != WizardFalse) && ((int) magick[0] == 0x1F) &&
1090                    ((int) magick[1] == 0x8B) && ((int) magick[2] == 0x08))
1091                  {
1092                    (void) fclose(blob_info->file);
1093                    blob_info->file=(FILE *) gzopen(filename,type);
1094                    if (blob_info->file != (FILE *) NULL)
1095                      blob_info->type=ZipStream;
1096                  }
1097#endif
1098#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
1099                if ((compress != WizardFalse) &&
1100                    (strncmp((char *) magick,"BZh",3) == 0))
1101                  {
1102                    (void) fclose(blob_info->file);
1103                    blob_info->file=(FILE *) BZ2_bzopen(filename,type);
1104                    if (blob_info->file != (FILE *) NULL)
1105                      blob_info->type=BZipStream;
1106                  }
1107#endif
1108              }
1109          }
1110        }
1111    properties=(&blob_info->properties);
1112    if ((blob_info->type == FileStream) && (*type == 'r') &&
1113        (properties->st_size <= WizardMaxBufferExtent))
1114      {
1115        size_t
1116          length;
1117
1118        void
1119          *blob;
1120
1121        length=(size_t) properties->st_size;
1122        blob=MapBlob(fileno(blob_info->file),ReadMode,0,length);
1123        if (blob != (void *) NULL)
1124          {
1125            /*
1126              Use memory-mapped I/O.
1127            */
1128            (void) fclose(blob_info->file);
1129            blob_info->file=(FILE *) NULL;
1130            AttachBlob(blob_info,blob,length);
1131            blob_info->mapped=WizardTrue;
1132          }
1133      }
1134  blob_info->status=WizardFalse;
1135  if (blob_info->type != UndefinedStream)
1136    blob_info->size=GetBlobSize(blob_info);
1137  else
1138    {
1139      (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
1140        "unable to open file `%s': %s",filename,strerror(errno));
1141      blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
1142      return((BlobInfo *) NULL);
1143    }
1144  return(blob_info);
1145}
1146
1147/*
1148%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149%                                                                             %
1150%                                                                             %
1151%                                                                             %
1152+  R e a d B l o b                                                            %
1153%                                                                             %
1154%                                                                             %
1155%                                                                             %
1156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1157%
1158%  ReadBlob() reads data from the blob and returns it.  It returns the number
1159%  of bytes read.
1160%
1161%  The format of the ReadBlob method is:
1162%
1163%      ssize_t ReadBlob(BlobInfo *blob_info,const size_t length,
1164%        unsigned char *data)
1165%
1166%  A description of each parameter follows:
1167%
1168%    o blob_info: the blob info.
1169%
1170%    o length: number of bytes to read from the blob.
1171%
1172%    o data: area to place the information requested from the blob.
1173%
1174*/
1175
1176static inline size_t WizardMin(const size_t x,const size_t y)
1177{
1178  if (x < y)
1179    return(x);
1180  return(y);
1181}
1182
1183WizardExport ssize_t ReadBlob(BlobInfo *blob_info,const size_t length,
1184  unsigned char *data)
1185{
1186  int
1187    c;
1188
1189  register unsigned char
1190    *q;
1191
1192  ssize_t
1193    count;
1194
1195  assert(blob_info != (BlobInfo *) NULL);
1196  assert(blob_info->signature == WizardSignature);
1197  assert(blob_info != (BlobInfo *) NULL);
1198  assert(blob_info->type != UndefinedStream);
1199  if (length == 0)
1200    return(0);
1201  assert(data != (void *) NULL);
1202  count=0;
1203  q=data;
1204  switch (blob_info->type)
1205  {
1206    case UndefinedStream:
1207      break;
1208    case FileStream:
1209    case StandardStream:
1210    case PipeStream:
1211    {
1212      switch (length)
1213      {
1214        default:
1215        {
1216          count=(ssize_t) fread(q,1,length,blob_info->file);
1217          break;
1218        }
1219        case 2:
1220        {
1221          c=getc(blob_info->file);
1222          if (c == EOF)
1223            break;
1224          *q++=(unsigned char) c;
1225          count++;
1226        }
1227        case 1:
1228        {
1229          c=getc(blob_info->file);
1230          if (c == EOF)
1231            break;
1232          *q++=(unsigned char) c;
1233          count++;
1234        }
1235        case 0:
1236          break;
1237      }
1238      break;
1239    }
1240    case ZipStream:
1241    {
1242#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
1243      switch (length)
1244      {
1245        default:
1246        {
1247          count=(ssize_t) gzread(blob_info->file,q,(unsigned int) length);
1248          break;
1249        }
1250        case 2:
1251        {
1252          c=gzgetc(blob_info->file);
1253          if (c == EOF)
1254            break;
1255          *q++=(unsigned char) c;
1256          count++;
1257        }
1258        case 1:
1259        {
1260          c=gzgetc(blob_info->file);
1261          if (c == EOF)
1262            break;
1263          *q++=(unsigned char) c;
1264          count++;
1265        }
1266        case 0:
1267          break;
1268      }
1269#endif
1270      break;
1271    }
1272    case BZipStream:
1273    {
1274#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
1275      count=(ssize_t) BZ2_bzread((BZFILE *) blob_info->file,q,(int) length);
1276#endif
1277      break;
1278    }
1279    case BlobStream:
1280    {
1281      register const unsigned char
1282        *p;
1283
1284      if (blob_info->offset >= (WizardOffsetType) blob_info->length)
1285        {
1286          blob_info->eof=WizardTrue;
1287          break;
1288        }
1289      p=blob_info->data+blob_info->offset;
1290      count=(ssize_t) WizardMin(length,(size_t) (blob_info->length-
1291        blob_info->offset));
1292      blob_info->offset+=count;
1293      if (count != (ssize_t) length)
1294        blob_info->eof=WizardTrue;
1295      (void) CopyWizardMemory(q,p,(size_t) count);
1296      break;
1297    }
1298  }
1299  return(count);
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304%                                                                             %
1305%                                                                             %
1306%                                                                             %
1307+  R e a d B l o b B y t e                                                    %
1308%                                                                             %
1309%                                                                             %
1310%                                                                             %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313%  ReadBlobByte() reads a single byte from the blob_info file and returns it.
1314%
1315%  The format of the ReadBlobByte method is:
1316%
1317%      int ReadBlobByte(BlobInfo *blob_info)
1318%
1319%  A description of each parameter follows.
1320%
1321%    o blob_info: the blob info.
1322%
1323*/
1324
1325static inline const unsigned char *ReadBlobStream(BlobInfo *blob_info,
1326  const size_t length,unsigned char *data,ssize_t *count)
1327{
1328  assert(count != (ssize_t *) NULL);
1329  assert(blob_info != (BlobInfo *) NULL);
1330  if (blob_info->type != BlobStream)
1331    {
1332      *count=ReadBlob(blob_info,length,data);
1333      return(data);
1334    }
1335  if (blob_info->offset >= (WizardOffsetType) blob_info->length)
1336    {
1337      *count=0;
1338      blob_info->eof=WizardTrue;
1339      return(data);
1340    }
1341  data=blob_info->data+blob_info->offset;
1342  *count=(ssize_t) WizardMin(length,(size_t) (blob_info->length-
1343    blob_info->offset));
1344  blob_info->offset+=(*count);
1345  if (*count != (ssize_t) length)
1346    blob_info->eof=WizardTrue;
1347  return(data);
1348}
1349
1350WizardExport int ReadBlobByte(BlobInfo *blob_info)
1351{
1352  register const unsigned char
1353    *p;
1354
1355  ssize_t
1356    count;
1357
1358  unsigned char
1359    buffer[1];
1360
1361  assert(blob_info != (BlobInfo *) NULL);
1362  assert(blob_info->signature == WizardSignature);
1363  p=ReadBlobStream(blob_info,1,buffer,&count);
1364  if (count != 1)
1365    return(EOF);
1366  return((int) (*p));
1367}
1368
1369/*
1370%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371%                                                                             %
1372%                                                                             %
1373%                                                                             %
1374+  R e a d B l o b C h u n k                                                  %
1375%                                                                             %
1376%                                                                             %
1377%                                                                             %
1378%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379%
1380%  ReadBlobChunk() reads data from the blob and returns it.  It returns the
1381%  number of bytes read.  ReadBlobChunk() differs from ReadBlob() by making an
1382%  effort to return the number of bytes that was requested except in the event
1383%  an EOF is encountered.
1384%
1385%  The format of the ReadBlobChunk method is:
1386%
1387%      ssize_t ReadBlobChunk(BlobInfo *blob_info,const size_t length,
1388%        unsigned char *data)
1389%
1390%  A description of each parameter follows:
1391%
1392%    o blob_info: the blob info.
1393%
1394%    o length: the number of bytes to read from the blob.
1395%
1396%    o data: the area to place the information requested from the blob.
1397%
1398*/
1399WizardExport ssize_t ReadBlobChunk(BlobInfo *blob_info,const size_t length,
1400  unsigned char *data)
1401{
1402  register ssize_t
1403    i;
1404
1405  ssize_t
1406    count;
1407
1408  assert(blob_info != (BlobInfo *) NULL);
1409  assert(blob_info->signature == WizardSignature);
1410  assert(blob_info->type != UndefinedStream);
1411  assert(data != (void *) NULL);
1412  if (blob_info->type == BlobStream)
1413    return(ReadBlob(blob_info,length,data));
1414  count=0;
1415  for (i=0; i < (ssize_t) length; i+=count)
1416  {
1417    count=ReadBlob(blob_info,WizardMin(length-i,(size_t) SSIZE_MAX),data+i);
1418    if (count <= 0)
1419      {
1420        count=0;
1421        if (errno != EINTR)
1422          break;
1423      }
1424  }
1425  return(i);
1426}
1427
1428/*
1429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430%                                                                             %
1431%                                                                             %
1432%                                                                             %
1433+  S e t B l o b E x t e n t                                                  %
1434%                                                                             %
1435%                                                                             %
1436%                                                                             %
1437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1438%
1439%  SetBlobExtent() ensures enough space is allocated for the blob.  If the
1440%  method is successful, subsequent writes to bytes in the specified range are
1441%  guaranteed not to fail.
1442%
1443%  The format of the SetBlobExtent method is:
1444%
1445%      WizardBooleanType SetBlobExtent(BlobInfo *blob_info,
1446%        const WizardSizeType extent)
1447%
1448%  A description of each parameter follows:
1449%
1450%    o blob_info: the blob info.
1451%
1452%    o extent:  the blob maximum extent.
1453%
1454*/
1455WizardExport WizardBooleanType SetBlobExtent(BlobInfo *blob_info,
1456  const WizardSizeType extent)
1457{
1458  assert(blob_info != (BlobInfo *) NULL);
1459  assert(blob_info->signature == WizardSignature);
1460  switch (blob_info->type)
1461  {
1462    case UndefinedStream:
1463      break;
1464    case FileStream:
1465    {
1466      if (extent != (WizardSizeType) ((off_t) extent))
1467        return(WizardFalse);
1468#if !defined(WIZARDSTOOLKIT_HAVE_POSIX_FALLOCATE)
1469        return(WizardFalse);
1470#else
1471      {
1472        int
1473          status;
1474
1475        WizardOffsetType
1476          offset;
1477
1478        offset=TellBlob(blob_info);
1479        status=posix_fallocate(fileno(blob_info->file),(off_t) offset,
1480          (off_t) (extent-offset));
1481        if (status != 0)
1482          return(WizardFalse);
1483      }
1484#endif
1485      break;
1486    }
1487    case StandardStream:
1488    case PipeStream:
1489    case ZipStream:
1490    {
1491      return(WizardFalse);
1492      break;
1493    }
1494    case BZipStream:
1495      return(WizardFalse);
1496    case BlobStream:
1497    {
1498      if (blob_info->mapped != WizardFalse)
1499        {
1500          if (blob_info->file == (FILE *) NULL)
1501            return(WizardFalse);
1502          (void) UnmapBlob(blob_info->data,blob_info->length);
1503#if !defined(WIZARDSTOOLKIT_HAVE_POSIX_FALLOCATE)
1504          return(WizardFalse);
1505#else
1506          {
1507            int
1508              status;
1509
1510            WizardOffsetType
1511              offset;
1512
1513            offset=TellBlob(blob_info);
1514            status=posix_fallocate(fileno(blob_info->file),(off_t) offset,
1515              (off_t) (extent-offset));
1516            if (status != 0)
1517              return(WizardFalse);
1518          }
1519          blob_info->data=(unsigned char*) MapBlob(fileno(blob_info->file),
1520            WriteMode,0,(size_t) extent);
1521          blob_info->extent=(size_t) extent;
1522          blob_info->length=(size_t) extent;
1523          (void) SyncBlob(blob_info);
1524          break;
1525#endif
1526        }
1527      if (extent != (WizardSizeType) ((size_t) extent))
1528        return(WizardFalse);
1529      blob_info->extent=(size_t) extent;
1530      blob_info->data=(unsigned char *) ResizeQuantumMemory(
1531        blob_info->data,blob_info->extent,sizeof(*blob_info->data));
1532      (void) SyncBlob(blob_info);
1533      if (blob_info->data == (unsigned char *) NULL)
1534        {
1535          (void) DetachBlob(blob_info);
1536          return(WizardFalse);
1537        }
1538      break;
1539    }
1540  }
1541  return(WizardTrue);
1542}
1543
1544/*
1545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546%                                                                             %
1547%                                                                             %
1548%                                                                             %
1549%  S y n c B l o b                                                            %
1550%                                                                             %
1551%                                                                             %
1552%                                                                             %
1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554%
1555%  SyncBlob() flushes the datastream if it is a file or synchonizes the data
1556%  attributes if it is an blob.
1557%
1558%  The format of the SyncBlob method is:
1559%
1560%      int SyncBlob(BlobInfo *blob_info)
1561%
1562%  A description of each parameter follows:
1563%
1564%    o blob_info: the blob info.
1565%
1566*/
1567WizardExport int SyncBlob(BlobInfo *blob_info)
1568{
1569  int
1570    status;
1571
1572  assert(blob_info != (BlobInfo *) NULL);
1573  assert(blob_info->signature == WizardSignature);
1574  (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",blob_info->filename);
1575  status=0;
1576  switch (blob_info->type)
1577  {
1578    case UndefinedStream:
1579      break;
1580    case FileStream:
1581    case StandardStream:
1582    case PipeStream:
1583    {
1584      status=fflush(blob_info->file);
1585      break;
1586    }
1587    case ZipStream:
1588    {
1589#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
1590      status=gzflush(blob_info->file,Z_SYNC_FLUSH);
1591#endif
1592      break;
1593    }
1594    case BZipStream:
1595    {
1596#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
1597      status=BZ2_bzflush((BZFILE *) blob_info->file);
1598#endif
1599      break;
1600    }
1601    case BlobStream:
1602    {
1603#if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO)
1604      if (blob_info->mapped != WizardFalse)
1605        status=msync(blob_info->data,blob_info->length,MS_SYNC);
1606#endif
1607      break;
1608    }
1609  }
1610  return(status);
1611}
1612
1613/*
1614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615%                                                                             %
1616%                                                                             %
1617%                                                                             %
1618+  T e l l B l o b                                                            %
1619%                                                                             %
1620%                                                                             %
1621%                                                                             %
1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623%
1624%  TellBlob() obtains the current value of the blob or file position.
1625%
1626%  The format of the TellBlob method is:
1627%
1628%      WizardOffsetType TellBlob(const BlobInfo *blob_info)
1629%
1630%  A description of each parameter follows:
1631%
1632%    o image: The image.
1633%
1634*/
1635WizardExport WizardOffsetType TellBlob(const BlobInfo *blob_info)
1636{
1637  WizardOffsetType
1638    offset;
1639
1640  assert(blob_info != (BlobInfo *) NULL);
1641  assert(blob_info->signature == WizardSignature);
1642  assert(blob_info->type != UndefinedStream);
1643  (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",blob_info->filename);
1644  offset=(-1);
1645  switch (blob_info->type)
1646  {
1647    case UndefinedStream:
1648      break;
1649    case FileStream:
1650    {
1651      offset=ftell(blob_info->file);
1652      break;
1653    }
1654    case StandardStream:
1655    case PipeStream:
1656      break;
1657    case ZipStream:
1658    {
1659#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
1660      offset=(WizardOffsetType) gztell(blob_info->file);
1661#endif
1662      break;
1663    }
1664    case BZipStream:
1665      break;
1666    case BlobStream:
1667    {
1668      offset=blob_info->offset;
1669      break;
1670    }
1671  }
1672  return(offset);
1673}
1674
1675/*
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677%                                                                             %
1678%                                                                             %
1679%                                                                             %
1680+  U n m a p B l o b                                                          %
1681%                                                                             %
1682%                                                                             %
1683%                                                                             %
1684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685%
1686%  UnmapBlob() deallocates the binary large object previously allocated with
1687%  the MapBlob method.
1688%
1689%  The format of the UnmapBlob method is:
1690%
1691%      WizardBooleanType UnmapBlob(void *map,const size_t length)
1692%
1693%  A description of each parameter follows:
1694%
1695%    o map: The address  of the binary large object.
1696%
1697%    o length: The length of the binary large object.
1698%
1699*/
1700WizardExport WizardBooleanType UnmapBlob(void *map,const size_t length)
1701{
1702#if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO)
1703  int
1704    status;
1705
1706  status=munmap(map,length);
1707  return(status == -1 ? WizardFalse : WizardTrue);
1708#else
1709  return(WizardFalse);
1710#endif
1711}
1712
1713/*
1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715%                                                                             %
1716%                                                                             %
1717%                                                                             %
1718+  W r i t e B l o b                                                          %
1719%                                                                             %
1720%                                                                             %
1721%                                                                             %
1722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1723%
1724%  WriteBlob() writes data to a blob or blob_info file.  It returns the number
1725%  of bytes written.
1726%
1727%  The format of the WriteBlob method is:
1728%
1729%      ssize_t WriteBlob(BlobInfo *blob_info,const size_t length,
1730%        const unsigned char *data)
1731%
1732%  A description of each parameter follows:
1733%
1734%    o blob_info: the blob.
1735%
1736%    o length: the number of bytes to write to the blob.
1737%
1738%    o data: the area to place the information requested from the blob.
1739%
1740*/
1741WizardExport ssize_t WriteBlob(BlobInfo *blob_info,const size_t length,
1742  const unsigned char *data)
1743{
1744  int
1745    c;
1746
1747  register const unsigned char
1748    *p;
1749
1750  ssize_t
1751    count;
1752
1753  assert(blob_info != (BlobInfo *) NULL);
1754  assert(blob_info->signature == WizardSignature);
1755  assert(data != (const unsigned char *) NULL);
1756  if (length == 0)
1757    return(0);
1758  count=0;
1759  p=data;
1760  switch (blob_info->type)
1761  {
1762    case UndefinedStream:
1763      break;
1764    case FileStream:
1765    case StandardStream:
1766    case PipeStream:
1767    {
1768      switch (length)
1769      {
1770        default:
1771        {
1772          count=(ssize_t) fwrite((const char *) data,1,length,
1773            blob_info->file);
1774          break;
1775        }
1776        case 2:
1777        {
1778          c=putc((int) *p++,blob_info->file);
1779          if (c == EOF)
1780            break;
1781          count++;
1782        }
1783        case 1:
1784        {
1785          c=putc((int) *p++,blob_info->file);
1786          if (c == EOF)
1787            break;
1788          count++;
1789        }
1790        case 0:
1791          break;
1792      }
1793      break;
1794    }
1795    case ZipStream:
1796    {
1797#if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
1798      switch (length)
1799      {
1800        default:
1801        {
1802          count=(ssize_t) gzwrite(blob_info->file,(void *) data,
1803            (unsigned int) length);
1804          break;
1805        }
1806        case 2:
1807        {
1808          c=gzputc(blob_info->file,(int) *p++);
1809          if (c == EOF)
1810            break;
1811          count++;
1812        }
1813        case 1:
1814        {
1815          c=gzputc(blob_info->file,(int) *p++);
1816          if (c == EOF)
1817            break;
1818          count++;
1819        }
1820        case 0:
1821          break;
1822      }
1823#endif
1824      break;
1825    }
1826    case BZipStream:
1827    {
1828#if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
1829      count=(ssize_t) BZ2_bzwrite((BZFILE *) blob_info->file,(void *) data,
1830        (int) length);
1831#endif
1832      break;
1833    }
1834    case BlobStream:
1835    {
1836      register unsigned char
1837        *q;
1838
1839      if ((blob_info->offset+(WizardOffsetType) length) >=
1840          (WizardOffsetType) blob_info->extent)
1841        {
1842          if (blob_info->mapped != WizardFalse)
1843            return(0);
1844          blob_info->quantum<<=1;
1845          blob_info->extent+=length+blob_info->quantum;
1846          blob_info->data=(unsigned char *) ResizeQuantumMemory(
1847            blob_info->data,blob_info->extent+1,
1848            sizeof(*blob_info->data));
1849          (void) SyncBlob(blob_info);
1850          if (blob_info->data == (unsigned char *) NULL)
1851            {
1852              (void) DetachBlob(blob_info);
1853              return(0);
1854            }
1855        }
1856      q=blob_info->data+blob_info->offset;
1857      (void) CopyWizardMemory(q,p,length);
1858      blob_info->offset+=length;
1859      if (blob_info->offset >= (WizardOffsetType) blob_info->length)
1860        blob_info->length=(size_t) blob_info->offset;
1861      count=(ssize_t) length;
1862    }
1863  }
1864  return(count);
1865}
1866
1867/*
1868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1869%                                                                             %
1870%                                                                             %
1871%                                                                             %
1872+  W r i t e B l o b B y t e                                                  %
1873%                                                                             %
1874%                                                                             %
1875%                                                                             %
1876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1877%
1878%  WriteBlobByte() write an integer to a blob.  It returns the number of bytes
1879%  written (either 0 or 1);
1880%
1881%  The format of the WriteBlobByte method is:
1882%
1883%      ssize_t WriteBlobByte(BlobInfo *blob_info,const unsigned char value)
1884%
1885%  A description of each parameter follows.
1886%
1887%    o blob_info: the blob info.
1888%
1889%    o value: the value to write.
1890%
1891*/
1892
1893static inline ssize_t WriteBlobStream(BlobInfo *blob_info,const size_t length,
1894  const unsigned char *data)
1895{
1896  register unsigned char
1897    *q;
1898
1899  WizardSizeType
1900    extent;
1901
1902  assert(blob_info != (BlobInfo *) NULL);
1903  if (blob_info->type != BlobStream)
1904    return(WriteBlob(blob_info,length,data));
1905  assert(blob_info->type != UndefinedStream);
1906  assert(data != (void *) NULL);
1907  extent=(WizardSizeType) (blob_info->offset+(WizardOffsetType) length);
1908  if (extent >= blob_info->extent)
1909    {
1910      blob_info->quantum<<=1;
1911      extent=blob_info->extent+blob_info->quantum+length;
1912      if (SetBlobExtent(blob_info,extent) == WizardFalse)
1913        return(0);
1914    }
1915  q=blob_info->data+blob_info->offset;
1916  (void) CopyWizardMemory(q,data,length);
1917  blob_info->offset+=length;
1918  if (blob_info->offset >= (WizardOffsetType) blob_info->length)
1919    blob_info->length=(size_t) blob_info->offset;
1920  return((ssize_t) length);
1921}
1922
1923WizardExport ssize_t WriteBlobByte(BlobInfo *blob_info,
1924  const unsigned char value)
1925{
1926  assert(blob_info != (BlobInfo *) NULL);
1927  assert(blob_info->signature == WizardSignature);
1928  return(WriteBlobStream(blob_info,1,&value));
1929}
1930
1931/*
1932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1933%                                                                             %
1934%                                                                             %
1935%                                                                             %
1936+  W r i t e B l o b C h u n k                                                %
1937%                                                                             %
1938%                                                                             %
1939%                                                                             %
1940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1941%
1942%  WriteBlobChunk() writes data to a blob or blob_info file.  It returns the
1943%  number of bytes written.  WriteBlobChunk() differs from WriteBlob() by
1944%  making an effort to write the number of bytes that was requested except in
1945%  the event an EOF is encountered.
1946%
1947%  The format of the WriteBlob method is:
1948%
1949%      ssize_t WriteBlobChunk(BlobInfo *blob_info,const size_t length,
1950%        const unsigned char *data)
1951%
1952%  A description of each parameter follows:
1953%
1954%    o blob_info: the blob.
1955%
1956%    o length: the number of bytes to write to the blob.
1957%
1958%    o data: the area to place the information requested from the blob.
1959%
1960*/
1961WizardExport ssize_t WriteBlobChunk(BlobInfo *blob_info,const size_t length,
1962  const unsigned char *data)
1963{
1964  register ssize_t
1965    i;
1966
1967  ssize_t
1968    count;
1969
1970  assert(blob_info != (BlobInfo *) NULL);
1971  assert(blob_info->signature == WizardSignature);
1972  assert(data != (const unsigned char *) NULL);
1973  if (blob_info->type == BlobStream)
1974    return(WriteBlob(blob_info,length,data));
1975  count=0;
1976  for (i=0; i < (ssize_t) length; i+=count)
1977  {
1978    count=WriteBlob(blob_info,WizardMin(length-i,(size_t) SSIZE_MAX),data+i);
1979    if (count <= 0)
1980      {
1981        count=0;
1982        if (errno != EINTR)
1983          break;
1984      }
1985  }
1986  return(i);
1987}
1988
1989/*
1990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1991%                                                                             %
1992%                                                                             %
1993%                                                                             %
1994+  W r i t e B l o b S t r i n g                                              %
1995%                                                                             %
1996%                                                                             %
1997%                                                                             %
1998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999%
2000%  WriteBlobString() write a string to a blob.  It returns the number of
2001%  characters written.
2002%
2003%  The format of the WriteBlobString method is:
2004%
2005%      ssize_t WriteBlobString(BlobInfo *blob_info,const char *string)
2006%
2007%  A description of each parameter follows.
2008%
2009%    o image: The image.
2010%
2011%    o string: Specifies the string to write.
2012%
2013*/
2014WizardExport ssize_t WriteBlobString(BlobInfo *blob_info,const char *string)
2015{
2016  ssize_t
2017    count;
2018
2019  assert(blob_info != (BlobInfo *) NULL);
2020  assert(blob_info->signature == WizardSignature);
2021  assert(string != (const char *) NULL);
2022  count=WriteBlobStream(blob_info,strlen(string),(const unsigned char *)
2023    string);
2024  return(count);
2025}
Note: See TracBrowser for help on using the browser.