root/WizardsToolkit/trunk/wizard/blob.c

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