blob.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                         BBBB   L       OOO   BBBB                           %
00007 %                         B   B  L      O   O  B   B                          %
00008 %                         BBBB   L      O   O  BBBB                           %
00009 %                         B   B  L      O   O  B   B                          %
00010 %                         BBBB   LLLLL   OOO   BBBB                           %
00011 %                                                                             %
00012 %                                                                             %
00013 %                  Wizard's Toolkit Binary Large OBjectS Methods              %
00014 %                                                                             %
00015 %                                                                             %
00016 %                              Software Design                                %
00017 %                                John Cristy                                  %
00018 %                                March 2003                                   %
00019 %                                                                             %
00020 %                                                                             %
00021 %  Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization      %
00022 %  dedicated to making software imaging solutions freely available.           %
00023 %                                                                             %
00024 %  You may not use this file except in compliance with the License.  You may  %
00025 %  obtain a copy of the License at                                            %
00026 %                                                                             %
00027 %    http://www.wizards-toolkit.org/script/license.php                        %
00028 %                                                                             %
00029 %  Unless required by applicable law or agreed to in writing, software        %
00030 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00031 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00032 %  See the License for the specific language governing permissions and        %
00033 %  limitations under the License.                                             %
00034 %                                                                             %
00035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00036 %
00037 %
00038 %
00039 */
00040 
00041 /*
00042   Include declarations.
00043 */
00044 #include "wizard/studio.h"
00045 #include "wizard/blob.h"
00046 #include "wizard/blob-private.h"
00047 #include "wizard/cipher.h"
00048 #include "wizard/exception.h"
00049 #include "wizard/exception-private.h"
00050 #include "wizard/memory_.h"
00051 #include "wizard/semaphore.h"
00052 #include "wizard/string-private.h"
00053 #include "wizard/utility.h"
00054 #include "blob.h"
00055 #if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO) && !defined(WIZARDSTOOLKIT_WINDOWS_SUPPORT)
00056 # include <sys/mman.h>
00057 #endif
00058 #include "bzlib.h"
00059 #include "zlib.h"
00060 
00061 /*
00062   Define declarations.
00063 */
00064 #define WizardMaxBlobExtent  65541
00065 # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
00066 #  define MAP_ANONYMOUS MAP_ANON
00067 # endif
00068 #if !defined(MAP_FAILED)
00069 #define MAP_FAILED      ((void *) -1)
00070 #endif
00071 #if !defined(MS_SYNC)
00072 #define MS_SYNC  0x04
00073 #endif
00074 
00075 /*
00076   Typedef declarations.
00077 */
00078 typedef enum
00079 {
00080   UndefinedStream,
00081   FileStream,
00082   StandardStream,
00083   PipeStream,
00084   ZipStream,
00085   BZipStream,
00086   BlobStream
00087 } StreamType;
00088 
00089 struct _BlobInfo
00090 {
00091   char
00092     filename[MaxTextExtent];
00093 
00094   size_t
00095     length,
00096     extent,
00097     quantum;
00098 
00099   WizardBooleanType
00100     mapped,
00101     eof;
00102 
00103   WizardOffsetType
00104     offset;
00105 
00106   WizardSizeType
00107     size;
00108 
00109   WizardBooleanType
00110     exempt,
00111     status,
00112     temporary;
00113 
00114   StreamType
00115     type;
00116 
00117   FILE
00118     *file;
00119 
00120   struct stat
00121     properties;
00122 
00123   unsigned char
00124     *data;
00125 
00126   WizardBooleanType
00127     debug;
00128 
00129   SemaphoreInfo
00130     *semaphore;
00131 
00132   ssize_t
00133     reference_count;
00134 
00135   size_t
00136     signature;
00137 };
00138 
00139 /*
00140   Forward declarations.
00141 */
00142 static unsigned char
00143   *DetachBlob(BlobInfo *);
00144 
00145 /*
00146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00147 %                                                                             %
00148 %                                                                             %
00149 %                                                                             %
00150 +   A t t a c h B l o b                                                       %
00151 %                                                                             %
00152 %                                                                             %
00153 %                                                                             %
00154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00155 %
00156 %  AttachBlob() attaches a blob to the BlobInfo structure.
00157 %
00158 %  The format of the AttachBlob method is:
00159 %
00160 %      void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
00161 %
00162 %  A description of each parameter follows:
00163 %
00164 %    o blob_info: the blob info.
00165 %
00166 %    o blob: the character stream to attach.
00167 %
00168 %    o length: the length in bytes of the blob.
00169 %
00170 */
00171 static void AttachBlob(BlobInfo *blob_info,const void *blob,const size_t length)
00172 {
00173   assert(blob_info != (BlobInfo *) NULL);
00174   if (blob_info->debug != WizardFalse)
00175     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
00176   blob_info->length=length;
00177   blob_info->extent=length;
00178   blob_info->quantum=(size_t) WizardMaxBlobExtent;
00179   blob_info->offset=0;
00180   blob_info->type=BlobStream;
00181   blob_info->file=(FILE *) NULL;
00182   blob_info->data=(unsigned char *) blob;
00183   blob_info->mapped=WizardFalse;
00184 }
00185 
00186 /*
00187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00188 %                                                                             %
00189 %                                                                             %
00190 %                                                                             %
00191 +   C l o s e B l o b                                                         %
00192 %                                                                             %
00193 %                                                                             %
00194 %                                                                             %
00195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00196 %
00197 %  CloseBlob() closes a stream associated with the blob_info.
00198 %
00199 %  The format of the CloseBlob method is:
00200 %
00201 %      WizardBooleanType CloseBlob(BlobInfo *blob_info)
00202 %
00203 %  A description of each parameter follows:
00204 %
00205 %    o blob_info: the blob info.
00206 %
00207 */
00208 WizardExport WizardBooleanType CloseBlob(BlobInfo *blob_info)
00209 {
00210   int
00211     status;
00212 
00213   /*
00214     Close blob_info file.
00215   */
00216   assert(blob_info != (BlobInfo *) NULL);
00217   assert(blob_info->signature == WizardSignature);
00218   if (blob_info->debug != WizardFalse)
00219     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
00220       blob_info->filename);
00221   if (blob_info->type == UndefinedStream)
00222     return(WizardTrue);
00223   (void) SyncBlob(blob_info);
00224   blob_info->size=GetBlobSize(blob_info);
00225   blob_info->eof=WizardFalse;
00226   if (blob_info->exempt != WizardFalse)
00227     {
00228       blob_info->type=UndefinedStream;
00229       return(WizardTrue);
00230     }
00231   status=0;
00232   switch (blob_info->type)
00233   {
00234     case UndefinedStream:
00235       break;
00236     case FileStream:
00237     case StandardStream:
00238     case PipeStream:
00239     {
00240       status=ferror(blob_info->file);
00241       break;
00242     }
00243     case ZipStream:
00244     {
00245 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
00246       (void) gzerror(blob_info->file,&status);
00247 #endif
00248       break;
00249     }
00250     case BZipStream:
00251     {
00252 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
00253       (void) BZ2_bzerror((BZFILE *) blob_info->file,&status);
00254 #endif
00255       break;
00256     }
00257     case BlobStream:
00258       break;
00259   }
00260   blob_info->status=status < 0 ? WizardTrue : WizardFalse;
00261   switch (blob_info->type)
00262   {
00263     case UndefinedStream:
00264       break;
00265     case FileStream:
00266     case StandardStream:
00267     {
00268       status=fclose(blob_info->file);
00269       break;
00270     }
00271     case PipeStream:
00272     {
00273 #if defined(WIZARDSTOOLKIT_HAVE_POPEN)
00274       status=pclose(blob_info->file);
00275 #endif
00276       break;
00277     }
00278     case ZipStream:
00279     {
00280 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
00281       status=gzclose(blob_info->file);
00282 #endif
00283       break;
00284     }
00285     case BZipStream:
00286     {
00287 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
00288       BZ2_bzclose((BZFILE *) blob_info->file);
00289 #endif
00290       break;
00291     }
00292     case BlobStream:
00293       break;
00294   }
00295   (void) DetachBlob(blob_info);
00296   blob_info->status=status < 0 ? WizardTrue : WizardFalse;
00297   return(blob_info->status);
00298 }
00299 
00300 /*
00301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00302 %                                                                             %
00303 %                                                                             %
00304 %                                                                             %
00305 +   D e s t r o y B l o b                                                     %
00306 %                                                                             %
00307 %                                                                             %
00308 %                                                                             %
00309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00310 %
00311 %  DestroyBlob() deallocates memory associated with a blob.
00312 %
00313 %  The format of the DestroyBlob method is:
00314 %
00315 %      BlobInfo *DestroyBlob(BlobInfo *blob_info)
00316 %
00317 %  A description of each parameter follows:
00318 %
00319 %    o blob_info: the blob info.
00320 %
00321 */
00322 WizardExport BlobInfo *DestroyBlob(BlobInfo *blob_info)
00323 {
00324   WizardBooleanType
00325     destroy;
00326 
00327   assert(blob_info != (BlobInfo *) NULL);
00328   assert(blob_info->signature == WizardSignature);
00329   if (blob_info->debug != WizardFalse)
00330     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
00331       blob_info->filename);
00332   destroy=WizardFalse;
00333   LockSemaphoreInfo(blob_info->semaphore);
00334   blob_info->reference_count--;
00335   if (blob_info->reference_count == 0)
00336     destroy=WizardTrue;
00337   UnlockSemaphoreInfo(blob_info->semaphore);
00338   if (destroy == WizardFalse)
00339     return(blob_info);
00340   (void) CloseBlob(blob_info);
00341   if (blob_info->mapped != WizardFalse)
00342     (void) UnmapBlob(blob_info->data,blob_info->length);
00343   if (blob_info->semaphore != (SemaphoreInfo *) NULL)
00344     DestroySemaphoreInfo(&blob_info->semaphore);
00345   blob_info->signature=(~WizardSignature);
00346   blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
00347   return(blob_info);
00348 }
00349 
00350 /*
00351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00352 %                                                                             %
00353 %                                                                             %
00354 %                                                                             %
00355 +   D e t a c h B l o b                                                       %
00356 %                                                                             %
00357 %                                                                             %
00358 %                                                                             %
00359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00360 %
00361 %  DetachBlob() detaches a blob from the BlobInfo structure.
00362 %
00363 %  The format of the DetachBlob method is:
00364 %
00365 %      unsigned char *DetachBlob(BlobInfo *blob_info)
00366 %
00367 %  A description of each parameter follows:
00368 %
00369 %    o blob_info: the blob info.
00370 %
00371 */
00372 static unsigned char *DetachBlob(BlobInfo *blob_info)
00373 {
00374   unsigned char
00375     *data;
00376 
00377   assert(blob_info != (BlobInfo *) NULL);
00378   if (blob_info->debug != WizardFalse)
00379     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
00380   if (blob_info->mapped != WizardFalse)
00381     (void) UnmapBlob(blob_info->data,blob_info->length);
00382   blob_info->mapped=WizardFalse;
00383   blob_info->length=0;
00384   blob_info->offset=0;
00385   blob_info->eof=WizardFalse;
00386   blob_info->exempt=WizardFalse;
00387   blob_info->type=UndefinedStream;
00388   blob_info->file=(FILE *) NULL;
00389   data=blob_info->data;
00390   blob_info->data=(unsigned char *) NULL;
00391   return(data);
00392 }
00393 
00394 /*
00395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00396 %                                                                             %
00397 %                                                                             %
00398 %                                                                             %
00399 +  E O F B l o b                                                              %
00400 %                                                                             %
00401 %                                                                             %
00402 %                                                                             %
00403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00404 %
00405 %  EOFBlob() returns a non-zero value when EOF has been detected reading from
00406 %  a blob or file.
00407 %
00408 %  The format of the EOFBlob method is:
00409 %
00410 %      int EOFBlob(BlobInfo *blob_info)
00411 %
00412 %  A description of each parameter follows:
00413 %
00414 %    o blob_info: the blob info.
00415 %
00416 */
00417 WizardExport int EOFBlob(BlobInfo *blob_info)
00418 {
00419   assert(blob_info != (BlobInfo *) NULL);
00420   assert(blob_info->signature == WizardSignature);
00421   if (blob_info->debug != WizardFalse)
00422     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"...");
00423   assert(blob_info->type != UndefinedStream);
00424   switch (blob_info->type)
00425   {
00426     case UndefinedStream:
00427       break;
00428     case FileStream:
00429     case StandardStream:
00430     case PipeStream:
00431     {
00432       blob_info->eof=feof(blob_info->file) != 0 ? WizardTrue : WizardFalse;
00433       break;
00434     }
00435     case ZipStream:
00436     {
00437       blob_info->eof=WizardFalse;
00438       break;
00439     }
00440     case BZipStream:
00441     {
00442 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
00443       int
00444         status;
00445 
00446       status=0;
00447       (void) BZ2_bzerror((BZFILE *) blob_info->file,&status);
00448       blob_info->eof=status == BZ_UNEXPECTED_EOF ? WizardTrue : WizardFalse;
00449 #endif
00450       break;
00451     }
00452     case BlobStream:
00453       break;
00454   }
00455   return((int) blob_info->eof);
00456 }
00457 
00458 /*
00459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00460 %                                                                             %
00461 %                                                                             %
00462 %                                                                             %
00463 %   F i l e T o B l o b                                                       %
00464 %                                                                             %
00465 %                                                                             %
00466 %                                                                             %
00467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00468 %
00469 %  FileToBlob() returns the contents of a file as a blob.  It returns the
00470 %  file as a blob and its length.  If an error occurs, NULL is returned.
00471 %
00472 %  The format of the FileToBlob method is:
00473 %
00474 %      void *FileToBlob(const char *filename,const size_t extent,size_t *length,
00475 %        ExceptionInfo *exception)
00476 %
00477 %  A description of each parameter follows:
00478 %
00479 %    o blob:  FileToBlob() returns the contents of a file as a blob.  If
00480 %      an error occurs NULL is returned.
00481 %
00482 %    o filename: The filename.
00483 %
00484 %    o extent:  The maximum length of the blob.
00485 %
00486 %    o length: On return, it reflects the actual length of the blob.
00487 %
00488 %    o exception: Return any errors or warnings in this structure.
00489 %
00490 */
00491 WizardExport unsigned char *FileToBlob(const char *filename,const size_t extent,
00492   size_t *length,ExceptionInfo *exception)
00493 {
00494   int
00495     file;
00496 
00497   off_t
00498     offset;
00499 
00500   register size_t
00501     i;
00502 
00503   ssize_t
00504     count;
00505 
00506   unsigned char
00507     *blob;
00508 
00509   void
00510     *map;
00511 
00512   assert(filename != (const char *) NULL);
00513   (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",filename);
00514   assert(exception != (ExceptionInfo *) NULL);
00515   *length=0;
00516   file=fileno(stdin);
00517   if (strcmp(filename,"-") != 0)
00518     file=open(filename,O_RDONLY | O_BINARY);
00519   if (file == -1)
00520     {
00521       (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00522         "unable to open file `%s': %s",filename,strerror(errno));
00523       return((unsigned char *) NULL);
00524     }
00525   offset=WizardSeek(file,0,SEEK_END);
00526   count=0;
00527   if ((offset < 0) || (offset != (off_t) ((ssize_t) offset)))
00528     {
00529       size_t
00530         quantum;
00531 
00532       struct stat
00533         file_info; 
00534 
00535       /*
00536         Stream is not seekable.
00537       */
00538       quantum=(size_t) WizardMaxBufferExtent;
00539       if ((fstat(file,&file_info) == 0) && (file_info.st_size != 0))
00540         quantum=Min((size_t) file_info.st_size,WizardMaxBufferExtent);
00541       blob=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*blob));
00542       for (i=0; blob != (unsigned char *) NULL; i+=count)
00543       {
00544         count=read(file,blob+i,quantum);
00545         if (count <= 0)
00546           {
00547             count=0;
00548             if (errno != EINTR)
00549               break;
00550           }
00551         if (~(1UL*i) < (quantum+1))
00552           {
00553             blob=(unsigned char *) RelinquishWizardMemory(blob);
00554             break;
00555           }
00556         blob=(unsigned char *) ResizeQuantumMemory(blob,i+quantum+1,
00557           sizeof(*blob));
00558         if ((size_t) (i+count) >= extent)
00559           break;
00560       }
00561       if (close(file) == -1)
00562         (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00563           "unable to close file `%s': %s",filename,strerror(errno));
00564       if (blob == (unsigned char *) NULL)
00565         {
00566           (void) ThrowWizardException(exception,GetWizardModule(),ResourceError,
00567             "memory allocation failed: `%s'",filename);
00568           return((unsigned char *) NULL);
00569         }
00570       *length=Min(i+count,extent);
00571       blob[*length]='\0';
00572       return(blob);
00573     }
00574   *length=Min((size_t) offset,extent);
00575   blob=(unsigned char *) NULL;
00576   if (~(*length) >= MaxCipherBlocksize)
00577     blob=(unsigned char *) AcquireQuantumMemory(*length+MaxCipherBlocksize,
00578       sizeof(*blob));
00579   if (blob == (unsigned char *) NULL)
00580     {
00581       if (close(file) == -1)
00582         {
00583           (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00584             "unable to close file `%s': %s",filename,strerror(errno));
00585           return((unsigned char *) NULL);
00586         }
00587       (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00588         "memory allocation failed `%s'",strerror(errno));
00589       return((unsigned char *) NULL);
00590     }
00591   map=MapBlob(file,ReadMode,0,*length);
00592   if (map != (void *) NULL)
00593     {
00594       (void) CopyWizardMemory(blob,map,*length);
00595       if (UnmapBlob(map,*length) == WizardFalse)
00596         (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00597           "unable to unmap blob `%s': %s",filename,strerror(errno));
00598     }
00599   else
00600     {
00601       register size_t
00602         i;
00603 
00604       ssize_t
00605         count;
00606 
00607       if (WizardSeek(file,0,SEEK_SET) < 0)
00608         (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00609           "unable to seek blob `%s': %s",filename,strerror(errno));
00610       for (i=0; i < *length; i+=count)
00611       {
00612         count=read(file,blob+i,Min(*length-i,(size_t) SSIZE_MAX));
00613         if (count <= 0)
00614           {
00615             count=0;
00616             if (errno != EINTR)
00617               break;
00618           }
00619       }
00620       if (i < *length)
00621         {
00622           if (close(file) == -1)
00623             (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00624               "unable to close file `%s': %s",filename,strerror(errno));
00625           blob=(unsigned char *) RelinquishWizardMemory(blob);
00626           (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00627             "unable to read file `%s'",filename);
00628           return((unsigned char *) NULL);
00629         }
00630     }
00631   if (close(file) == -1)
00632     (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
00633       "unable to close file `%s': %s",filename,strerror(errno));
00634   blob[*length]=(unsigned char) '\0';
00635   return(blob);
00636 }
00637 
00638 /*
00639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00640 %                                                                             %
00641 %                                                                             %
00642 %                                                                             %
00643 +  G e t B l o b F i l e n a m e                                              %
00644 %                                                                             %
00645 %                                                                             %
00646 %                                                                             %
00647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00648 %
00649 %  GetBlobFilename() returns the blob filename.
00650 %
00651 %  The format of the GetBlobFilename method is:
00652 %
00653 %      const char *GetBlobFilename(const BlobInfo *blob_info)
00654 %
00655 %  A description of each parameter follows:
00656 %
00657 %    o blob_info: the blob info info.
00658 %
00659 */
00660 WizardExport const char *GetBlobFilename(const BlobInfo *blob_info)
00661 {
00662   assert(blob_info != (BlobInfo *) NULL);
00663   if (blob_info->debug != WizardFalse)
00664     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
00665       blob_info->filename);
00666   return(blob_info->filename);
00667 }
00668 
00669 /*
00670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00671 %                                                                             %
00672 %                                                                             %
00673 %                                                                             %
00674 +   G e t B l o b I n f o                                                     %
00675 %                                                                             %
00676 %                                                                             %
00677 %                                                                             %
00678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00679 %
00680 %  GetBlobInfo() initializes the BlobInfo structure.
00681 %
00682 %  The format of the GetBlobInfo method is:
00683 %
00684 %      void GetBlobInfo(BlobInfo *blob_info)
00685 %
00686 %  A description of each parameter follows:
00687 %
00688 %    o blob_info: Specifies a pointer to a BlobInfo structure.
00689 %
00690 */
00691 WizardExport void GetBlobInfo(BlobInfo *blob_info)
00692 {
00693   assert(blob_info != (BlobInfo *) NULL);
00694   (void) ResetWizardMemory(blob_info,0,sizeof(*blob_info));
00695   blob_info->type=UndefinedStream;
00696   blob_info->quantum=(size_t) WizardMaxBlobExtent;
00697   blob_info->debug=IsEventLogging();
00698   blob_info->reference_count=1;
00699   blob_info->semaphore=AllocateSemaphoreInfo();
00700   blob_info->signature=WizardSignature;
00701 }
00702 
00703 /*
00704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00705 %                                                                             %
00706 %                                                                             %
00707 %                                                                             %
00708 +  G e t B l o b S i z e                                                      %
00709 %                                                                             %
00710 %                                                                             %
00711 %                                                                             %
00712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00713 %
00714 %  GetBlobSize() returns the current length of the blob; zero is returned if
00715 %  the size cannot be determined.
00716 %
00717 %  The format of the GetBlobSize method is:
00718 %
00719 %      WizardSizeType GetBlobSize(BlobInfo *blob_info)
00720 %
00721 %  A description of each parameter follows:
00722 %
00723 %    o blob_info: the blob info.
00724 %
00725 */
00726 WizardExport WizardSizeType GetBlobSize(BlobInfo *blob_info)
00727 {
00728   WizardSizeType
00729     length;
00730 
00731   assert(blob_info != (BlobInfo *) NULL);
00732   if (blob_info->debug != WizardFalse)
00733     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
00734       blob_info->filename);
00735   length=0;
00736   switch (blob_info->type)
00737   {
00738     case UndefinedStream:
00739     {
00740       length=blob_info->size;
00741       break;
00742     }
00743     case FileStream:
00744     {
00745       if (fstat(fileno(blob_info->file),&blob_info->properties) == 0)
00746         length=(WizardSizeType) blob_info->properties.st_size;
00747       break;
00748     }
00749     case StandardStream:
00750     case PipeStream:
00751     {
00752       length=blob_info->size;
00753       break;
00754     }
00755     case ZipStream:
00756     {
00757 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
00758       if (fstat(fileno(blob_info->file),&blob_info->properties) == 0)
00759         length=(WizardSizeType) blob_info->properties.st_size;
00760 #endif
00761       break;
00762     }
00763     case BZipStream:
00764     {
00765 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
00766       if (fstat(fileno(blob_info->file),&blob_info->properties) == 0)
00767         length=(WizardSizeType) blob_info->properties.st_size;
00768 #endif
00769       break;
00770     }
00771     case BlobStream:
00772     {
00773       length=(WizardSizeType) blob_info->length;
00774       break;
00775     }
00776   }
00777   return(length);
00778 }
00779 
00780 /*
00781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00782 %                                                                             %
00783 %                                                                             %
00784 %                                                                             %
00785 %  G e t B l o b P r o p e r t i e s                                          %
00786 %                                                                             %
00787 %                                                                             %
00788 %                                                                             %
00789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00790 %
00791 %  GetBlobProperties() returns information about a blob.
00792 %
00793 %  The format of the GetBlobProperties method is:
00794 %
00795 %      const struct stat *GetBlobProperties(const BlobInfo *blob_info)
00796 %
00797 %  A description of each parameter follows:
00798 %
00799 %    o blob_info: the blob info.
00800 %
00801 */
00802 WizardExport const struct stat *GetBlobProperties(const BlobInfo *blob_info)
00803 {
00804   assert(blob_info != (BlobInfo *) NULL);
00805   if (blob_info->debug != WizardFalse)
00806     (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",
00807       blob_info->filename);
00808   return(&blob_info->properties);
00809 }
00810 
00811 /*
00812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00813 %                                                                             %
00814 %                                                                             %
00815 %                                                                             %
00816 +  M a p B l o b                                                              %
00817 %                                                                             %
00818 %                                                                             %
00819 %                                                                             %
00820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00821 %
00822 %  MapBlob() creates a mapping from a file to a binary large object.
00823 %
00824 %  The format of the MapBlob method is:
00825 %
00826 %      void *MapBlob(int file,const MapMode mode,const WizardOffsetType offset,
00827 %        const size_t length)
00828 %
00829 %  A description of each parameter follows:
00830 %
00831 %    o file: map this file descriptor.
00832 %
00833 %    o mode: ReadMode, WriteMode, or IOMode.
00834 %
00835 %    o offset: starting at this offset within the file.
00836 %
00837 %    o length: the length of the mapping is returned in this pointer.
00838 %
00839 */
00840 WizardExport void *MapBlob(int file,const MapMode mode,
00841   const WizardOffsetType offset,const size_t length)
00842 {
00843 #if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO)
00844   int
00845     flags,
00846     protection;
00847 
00848   unsigned char
00849     *map;
00850 
00851   /*
00852     Map file.
00853   */
00854   flags=0;
00855   if (file == -1)
00856 #if defined(MAP_ANONYMOUS)
00857     flags|=MAP_ANONYMOUS;
00858 #else
00859     return((unsigned char *) NULL);
00860 #endif
00861   flags|=MAP_PRIVATE;
00862   switch (mode)
00863   {
00864     case ReadMode:
00865     default:
00866     {
00867       protection=PROT_READ;
00868       map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
00869         (off_t) offset);
00870       break;
00871     }
00872     case WriteMode:
00873     {
00874       protection=PROT_WRITE;
00875       if (file != -1)
00876         flags|=MAP_SHARED;
00877       map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
00878         (off_t) offset);
00879 #if defined(WIZARDTOOLKIT_HAVE_POSIX_MADVISE)
00880       (void) posix_madvise(map,length,POSIX_MADV_SEQUENTIAL |
00881         POSIX_MADV_WILLNEED);
00882 #endif
00883       break;
00884     }
00885     case IOMode:
00886     {
00887       protection=PROT_READ | PROT_WRITE;
00888       if (file != -1)
00889         flags|=MAP_SHARED;
00890       map=(unsigned char *) mmap((char *) NULL,length,protection,flags,file,
00891         (off_t) offset);
00892       break;
00893     }
00894   }
00895   if (map == (unsigned char *) MAP_FAILED)
00896     return((unsigned char *) NULL);
00897   return(map);
00898 #else
00899   return((unsigned char *) NULL);
00900 #endif
00901 }
00902 
00903 /*
00904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00905 %                                                                             %
00906 %                                                                             %
00907 %                                                                             %
00908 +   O p e n B l o b                                                           %
00909 %                                                                             %
00910 %                                                                             %
00911 %                                                                             %
00912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00913 %
00914 %  OpenBlob() opens a file associated with the blob.  A file name of '-' sets
00915 %  the file to stdin for type 'r' and stdout for type 'w'.  If the filename
00916 %  suffix is '.gz' or '.Z', the blob_info is decompressed for type 'r' and
00917 %  compressed for type 'w'.  If the filename prefix is '|', it is piped to or
00918 %  from a system command.
00919 %
00920 %  The format of the OpenBlob method is:
00921 %
00922 %       BlobInfo *OpenBlob(const char *filename,const BlobMode mode,
00923 %         const WizardBooleanType compress,ExceptionInfo *exception)
00924 %
00925 %  A description of each parameter follows:
00926 %
00927 %    o filename: the filename.
00928 %
00929 %    o mode: the mode for opening the file.
00930 %
00931 %    o compress: a value other than 0 (de)compresses BZIP or ZIP files.
00932 %
00933 %    o exception: return any errors or warnings in this structure.
00934 */
00935 WizardExport BlobInfo *OpenBlob(const char *filename,const BlobMode mode,
00936   const WizardBooleanType compress,ExceptionInfo *exception)
00937 {
00938   BlobInfo
00939     *blob_info;
00940 
00941   const char
00942     *type;
00943 
00944   struct stat
00945     *properties;
00946 
00947   WizardBooleanType
00948     status;
00949 
00950   assert(filename != (const char *) NULL);
00951   (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",filename);
00952   assert(exception != (ExceptionInfo *) NULL);
00953   blob_info=(BlobInfo *) AcquireAlignedMemory(1,sizeof(*blob_info));
00954   if (blob_info == (BlobInfo *) NULL)
00955     {
00956       (void) ThrowWizardException(exception,GetWizardModule(),ResourceError,
00957         "memory allocation failed: `%s'",filename);
00958       return((BlobInfo *) NULL);
00959     }
00960   GetBlobInfo(blob_info);
00961   switch (mode)
00962   {
00963     default: type="r"; break;
00964     case ReadBlobMode: type="r"; break;
00965     case ReadBinaryBlobMode: type="rb"; break;
00966     case WriteBlobMode: type="w"; break;
00967     case WriteBinaryBlobMode: type="w+b"; break;
00968   }
00969   /*
00970     Open file.
00971   */
00972   (void) CopyWizardString(blob_info->filename,filename,MaxTextExtent);
00973   if (LocaleCompare(filename,"-") == 0)
00974     {
00975       blob_info->file=(*type == 'r') ? stdin : stdout;
00976 #if defined(WIZARDSTOOLKIT_WINDOWS_SUPPORT)
00977       if (strchr(type,'b') != (char *) NULL)
00978         setmode(_fileno(blob_info->file),_O_BINARY);
00979 #endif
00980       blob_info->type=StandardStream;
00981       blob_info->exempt=WizardTrue;
00982       return(blob_info);
00983     }
00984   if (LocaleNCompare(filename,"fd:",3) == 0)
00985     {
00986       char
00987         mode[MaxTextExtent];
00988 
00989       *mode=(*type);
00990       mode[1]='\0';
00991       blob_info->file=fdopen((long) StringToLong(filename+3),mode);
00992 #if defined(WIZARDSTOOLKIT_WINDOWS_SUPPORT)
00993       if (strchr(type,'b') != (char *) NULL)
00994         setmode(_fileno(blob_info->file),_O_BINARY);
00995 #endif
00996       blob_info->type=StandardStream;
00997       blob_info->exempt=WizardTrue;
00998       return(blob_info);
00999     }
01000 #if defined(WIZARDSTOOLKIT_HAVE_POPEN)
01001   if (*filename == '|')
01002     {
01003       char
01004         mode[MaxTextExtent];
01005 
01006       /*
01007         Pipe blob_info to or from a system command.
01008       */
01009 #if defined(SIGPIPE)
01010       if (*type == 'w')
01011         (void) signal(SIGPIPE,SIG_IGN);
01012 #endif
01013       *mode=(*type);
01014       mode[1]='\0';
01015       blob_info->file=(FILE *) popen(filename+1,mode);
01016       if (blob_info->file == (FILE *) NULL)
01017         {
01018           (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
01019             "unable to open file `%s': %s",filename,strerror(errno));
01020           blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
01021           return((BlobInfo *) NULL);
01022         }
01023       blob_info->type=PipeStream;
01024       blob_info->exempt=WizardTrue;
01025       return(blob_info);
01026     }
01027 #endif
01028   status=stat(filename,&blob_info->properties) == 0 ? WizardTrue : WizardFalse;
01029 #if defined(S_ISFIFO)
01030   if ((status == WizardTrue) && S_ISFIFO(blob_info->properties.st_mode))
01031     {
01032       blob_info->file=WizardOpenStream(filename,type);
01033       if (blob_info->file == (FILE *) NULL)
01034         {
01035           (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
01036             "unable to open file `%s': %s",filename,strerror(errno));
01037           blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
01038           return((BlobInfo *) NULL);
01039         }
01040       blob_info->type=FileStream;
01041       blob_info->exempt=WizardTrue;
01042       return(blob_info);
01043     }
01044 #endif
01045 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
01046   if ((compress != WizardFalse) &&
01047       (((strlen(filename) > 2) &&
01048         (LocaleCompare(filename+strlen(filename)-2,".Z") == 0)) ||
01049        ((strlen(filename) > 3) &&
01050         (LocaleCompare(filename+strlen(filename)-3,".gz") == 0)) ||
01051        ((strlen(filename) > 4) &&
01052         (LocaleCompare(filename+strlen(filename)-4,".wmz") == 0)) ||
01053        ((strlen(filename) > 5) &&
01054         (LocaleCompare(filename+strlen(filename)-5,".svgz") == 0))))
01055     {
01056       blob_info->file=(FILE *) gzopen(filename,type);
01057       if (blob_info->file != (FILE *) NULL)
01058         blob_info->type=ZipStream;
01059     }
01060   else
01061 #endif
01062 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
01063     if ((compress != WizardFalse) && (strlen(filename) > 4) &&
01064         (LocaleCompare(filename+strlen(filename)-4,".bz2") == 0))
01065       {
01066         blob_info->file=(FILE *) BZ2_bzopen(filename,type);
01067         if (blob_info->file != (FILE *) NULL)
01068           blob_info->type=BZipStream;
01069       }
01070     else
01071 #endif
01072       {
01073         blob_info->file=WizardOpenStream(filename,type);
01074         if (blob_info->file != (FILE *) NULL)
01075           {
01076             blob_info->type=FileStream;
01077 #if defined(WIZARDSTOOLKIT_HAVE_SETVBUF)
01078             (void) setvbuf(blob_info->file,(char *) NULL,(int) _IOFBF,16384);
01079 #endif
01080             if (*type == 'r')
01081               {
01082                 size_t
01083                   count;
01084 
01085                 unsigned char
01086                   magick[3];
01087 
01088                 (void) ResetWizardMemory(magick,0,sizeof(magick));
01089                 count=fread(magick,1,sizeof(magick),blob_info->file);
01090                 (void) rewind(blob_info->file);
01091                 (void) LogWizardEvent(BlobEvent,GetWizardModule(),
01092                   "  read %.20g magic header bytes",(double) count);
01093 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
01094                 if ((compress != WizardFalse) && ((int) magick[0] == 0x1F) &&
01095                     ((int) magick[1] == 0x8B) && ((int) magick[2] == 0x08))
01096                   {
01097                     (void) fclose(blob_info->file);
01098                     blob_info->file=(FILE *) gzopen(filename,type);
01099                     if (blob_info->file != (FILE *) NULL)
01100                       blob_info->type=ZipStream;
01101                   }
01102 #endif
01103 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
01104                 if ((compress != WizardFalse) &&
01105                     (strncmp((char *) magick,"BZh",3) == 0))
01106                   {
01107                     (void) fclose(blob_info->file);
01108                     blob_info->file=(FILE *) BZ2_bzopen(filename,type);
01109                     if (blob_info->file != (FILE *) NULL)
01110                       blob_info->type=BZipStream;
01111                   }
01112 #endif
01113               }
01114           }
01115         }
01116     properties=(&blob_info->properties);
01117     if ((blob_info->type == FileStream) && (*type == 'r') &&
01118         (properties->st_size <= WizardMaxBufferExtent))
01119       {
01120         size_t
01121           length;
01122 
01123         void
01124           *blob;
01125 
01126         length=(size_t) properties->st_size;
01127         blob=MapBlob(fileno(blob_info->file),ReadMode,0,length);
01128         if (blob != (void *) NULL)
01129           {
01130             /*
01131               Use memory-mapped I/O.
01132             */
01133             (void) fclose(blob_info->file);
01134             blob_info->file=(FILE *) NULL;
01135             AttachBlob(blob_info,blob,length);
01136             blob_info->mapped=WizardTrue;
01137           }
01138       }
01139   blob_info->status=WizardFalse;
01140   if (blob_info->type != UndefinedStream)
01141     blob_info->size=GetBlobSize(blob_info);
01142   else
01143     {
01144       (void) ThrowWizardException(exception,GetWizardModule(),BlobError,
01145         "unable to open file `%s': %s",filename,strerror(errno));
01146       blob_info=(BlobInfo *) RelinquishWizardMemory(blob_info);
01147       return((BlobInfo *) NULL);
01148     }
01149   return(blob_info);
01150 }
01151 
01152 /*
01153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01154 %                                                                             %
01155 %                                                                             %
01156 %                                                                             %
01157 +  R e a d B l o b                                                            %
01158 %                                                                             %
01159 %                                                                             %
01160 %                                                                             %
01161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01162 %
01163 %  ReadBlob() reads data from the blob and returns it.  It returns the number
01164 %  of bytes read.
01165 %
01166 %  The format of the ReadBlob method is:
01167 %
01168 %      ssize_t ReadBlob(BlobInfo *blob_info,const size_t length,
01169 %        unsigned char *data)
01170 %
01171 %  A description of each parameter follows:
01172 %
01173 %    o blob_info: the blob info.
01174 %
01175 %    o length: number of bytes to read from the blob.
01176 %
01177 %    o data: area to place the information requested from the blob.
01178 %
01179 */
01180 
01181 static inline size_t WizardMin(const size_t x,const size_t y)
01182 {
01183   if (x < y)
01184     return(x);
01185   return(y);
01186 }
01187 
01188 WizardExport ssize_t ReadBlob(BlobInfo *blob_info,const size_t length,
01189   unsigned char *data)
01190 {
01191   int
01192     c;
01193 
01194   register unsigned char
01195     *q;
01196 
01197   ssize_t
01198     count;
01199 
01200   assert(blob_info != (BlobInfo *) NULL);
01201   assert(blob_info->signature == WizardSignature);
01202   assert(blob_info != (BlobInfo *) NULL);
01203   assert(blob_info->type != UndefinedStream);
01204   if (length == 0)
01205     return(0);
01206   assert(data != (void *) NULL);
01207   count=0;
01208   q=data;
01209   switch (blob_info->type)
01210   {
01211     case UndefinedStream:
01212       break;
01213     case FileStream:
01214     case StandardStream:
01215     case PipeStream:
01216     {
01217       switch (length)
01218       {
01219         default:
01220         {
01221           count=(ssize_t) fread(q,1,length,blob_info->file);
01222           break;
01223         }
01224         case 2:
01225         {
01226           c=getc(blob_info->file);
01227           if (c == EOF)
01228             break;
01229           *q++=(unsigned char) c;
01230           count++;
01231         }
01232         case 1:
01233         {
01234           c=getc(blob_info->file);
01235           if (c == EOF)
01236             break;
01237           *q++=(unsigned char) c;
01238           count++;
01239         }
01240         case 0:
01241           break;
01242       }
01243       break;
01244     }
01245     case ZipStream:
01246     {
01247 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
01248       switch (length)
01249       {
01250         default:
01251         {
01252           count=(ssize_t) gzread(blob_info->file,q,(unsigned int) length);
01253           break;
01254         }
01255         case 2:
01256         {
01257           c=gzgetc(blob_info->file);
01258           if (c == EOF)
01259             break;
01260           *q++=(unsigned char) c;
01261           count++;
01262         }
01263         case 1:
01264         {
01265           c=gzgetc(blob_info->file);
01266           if (c == EOF)
01267             break;
01268           *q++=(unsigned char) c;
01269           count++;
01270         }
01271         case 0:
01272           break;
01273       }
01274 #endif
01275       break;
01276     }
01277     case BZipStream:
01278     {
01279 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
01280       count=(ssize_t) BZ2_bzread((BZFILE *) blob_info->file,q,(int) length);
01281 #endif
01282       break;
01283     }
01284     case BlobStream:
01285     {
01286       register const unsigned char
01287         *p;
01288 
01289       if (blob_info->offset >= (WizardOffsetType) blob_info->length)
01290         {
01291           blob_info->eof=WizardTrue;
01292           break;
01293         }
01294       p=blob_info->data+blob_info->offset;
01295       count=(ssize_t) WizardMin(length,(size_t) (blob_info->length-
01296         blob_info->offset));
01297       blob_info->offset+=count;
01298       if (count != (ssize_t) length)
01299         blob_info->eof=WizardTrue;
01300       (void) CopyWizardMemory(q,p,(size_t) count);
01301       break;
01302     }
01303   }
01304   return(count);
01305 }
01306 
01307 /*
01308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01309 %                                                                             %
01310 %                                                                             %
01311 %                                                                             %
01312 +  R e a d B l o b B y t e                                                    %
01313 %                                                                             %
01314 %                                                                             %
01315 %                                                                             %
01316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01317 %
01318 %  ReadBlobByte() reads a single byte from the blob_info file and returns it.
01319 %
01320 %  The format of the ReadBlobByte method is:
01321 %
01322 %      int ReadBlobByte(BlobInfo *blob_info)
01323 %
01324 %  A description of each parameter follows.
01325 %
01326 %    o blob_info: the blob info.
01327 %
01328 */
01329 
01330 static inline const unsigned char *ReadBlobStream(BlobInfo *blob_info,
01331   const size_t length,unsigned char *data,ssize_t *count)
01332 {
01333   assert(count != (ssize_t *) NULL);
01334   assert(blob_info != (BlobInfo *) NULL);
01335   if (blob_info->type != BlobStream)
01336     {
01337       *count=ReadBlob(blob_info,length,data);
01338       return(data);
01339     }
01340   if (blob_info->offset >= (WizardOffsetType) blob_info->length)
01341     {
01342       *count=0;
01343       blob_info->eof=WizardTrue;
01344       return(data);
01345     }
01346   data=blob_info->data+blob_info->offset;
01347   *count=(ssize_t) WizardMin(length,(size_t) (blob_info->length-
01348     blob_info->offset));
01349   blob_info->offset+=(*count);
01350   if (*count != (ssize_t) length)
01351     blob_info->eof=WizardTrue;
01352   return(data);
01353 }
01354 
01355 WizardExport int ReadBlobByte(BlobInfo *blob_info)
01356 {
01357   register const unsigned char
01358     *p;
01359 
01360   ssize_t
01361     count;
01362 
01363   unsigned char
01364     buffer[1];
01365 
01366   assert(blob_info != (BlobInfo *) NULL);
01367   assert(blob_info->signature == WizardSignature);
01368   p=ReadBlobStream(blob_info,1,buffer,&count);
01369   if (count != 1)
01370     return(EOF);
01371   return((int) (*p));
01372 }
01373 
01374 /*
01375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01376 %                                                                             %
01377 %                                                                             %
01378 %                                                                             %
01379 +  R e a d B l o b C h u n k                                                  %
01380 %                                                                             %
01381 %                                                                             %
01382 %                                                                             %
01383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01384 %
01385 %  ReadBlobChunk() reads data from the blob and returns it.  It returns the
01386 %  number of bytes read.  ReadBlobChunk() differs from ReadBlob() by making an
01387 %  effort to return the number of bytes that was requested except in the event
01388 %  an EOF is encountered.
01389 %
01390 %  The format of the ReadBlobChunk method is:
01391 %
01392 %      ssize_t ReadBlobChunk(BlobInfo *blob_info,const size_t length,
01393 %        unsigned char *data)
01394 %
01395 %  A description of each parameter follows:
01396 %
01397 %    o blob_info: the blob info.
01398 %
01399 %    o length: the number of bytes to read from the blob.
01400 %
01401 %    o data: the area to place the information requested from the blob.
01402 %
01403 */
01404 WizardExport ssize_t ReadBlobChunk(BlobInfo *blob_info,const size_t length,
01405   unsigned char *data)
01406 {
01407   register ssize_t
01408     i;
01409 
01410   ssize_t
01411     count;
01412 
01413   assert(blob_info != (BlobInfo *) NULL);
01414   assert(blob_info->signature == WizardSignature);
01415   assert(blob_info->type != UndefinedStream);
01416   assert(data != (void *) NULL);
01417   if (blob_info->type == BlobStream)
01418     return(ReadBlob(blob_info,length,data));
01419   count=0;
01420   for (i=0; i < (ssize_t) length; i+=count)
01421   {
01422     count=ReadBlob(blob_info,WizardMin(length-i,(size_t) SSIZE_MAX),data+i);
01423     if (count <= 0)
01424       {
01425         count=0;
01426         if (errno != EINTR)
01427           break;
01428       }
01429   }
01430   return(i);
01431 }
01432 
01433 /*
01434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01435 %                                                                             %
01436 %                                                                             %
01437 %                                                                             %
01438 +  S e t B l o b E x t e n t                                                  %
01439 %                                                                             %
01440 %                                                                             %
01441 %                                                                             %
01442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01443 %
01444 %  SetBlobExtent() ensures enough space is allocated for the blob.  If the
01445 %  method is successful, subsequent writes to bytes in the specified range are
01446 %  guaranteed not to fail.
01447 %
01448 %  The format of the SetBlobExtent method is:
01449 %
01450 %      WizardBooleanType SetBlobExtent(BlobInfo *blob_info,
01451 %        const WizardSizeType extent)
01452 %
01453 %  A description of each parameter follows:
01454 %
01455 %    o blob_info: the blob info.
01456 %
01457 %    o extent:  the blob maximum extent.
01458 %
01459 */
01460 WizardExport WizardBooleanType SetBlobExtent(BlobInfo *blob_info,
01461   const WizardSizeType extent)
01462 {
01463   assert(blob_info != (BlobInfo *) NULL);
01464   assert(blob_info->signature == WizardSignature);
01465   switch (blob_info->type)
01466   {
01467     case UndefinedStream:
01468       break;
01469     case FileStream:
01470     {
01471       if (extent != (WizardSizeType) ((off_t) extent))
01472         return(WizardFalse);
01473 #if !defined(WIZARDSTOOLKIT_HAVE_POSIX_FALLOCATE)
01474         return(WizardFalse);
01475 #else
01476       {
01477         int
01478           status;
01479 
01480         WizardOffsetType
01481           offset;
01482 
01483         offset=TellBlob(blob_info);
01484         status=posix_fallocate(fileno(blob_info->file),(off_t) offset,
01485           (off_t) (extent-offset));
01486         if (status != 0)
01487           return(WizardFalse);
01488       }
01489 #endif
01490       break;
01491     }
01492     case StandardStream:
01493     case PipeStream:
01494     case ZipStream:
01495     {
01496       return(WizardFalse);
01497       break;
01498     }
01499     case BZipStream:
01500       return(WizardFalse);
01501     case BlobStream:
01502     {
01503       if (blob_info->mapped != WizardFalse)
01504         {
01505           if (blob_info->file == (FILE *) NULL)
01506             return(WizardFalse);
01507           (void) UnmapBlob(blob_info->data,blob_info->length);
01508 #if !defined(WIZARDSTOOLKIT_HAVE_POSIX_FALLOCATE)
01509           return(WizardFalse);
01510 #else
01511           {
01512             int
01513               status;
01514 
01515             WizardOffsetType
01516               offset;
01517 
01518             offset=TellBlob(blob_info);
01519             status=posix_fallocate(fileno(blob_info->file),(off_t) offset,
01520               (off_t) (extent-offset));
01521             if (status != 0)
01522               return(WizardFalse);
01523           }
01524           blob_info->data=(unsigned char*) MapBlob(fileno(blob_info->file),
01525             WriteMode,0,(size_t) extent);
01526           blob_info->extent=(size_t) extent;
01527           blob_info->length=(size_t) extent;
01528           (void) SyncBlob(blob_info);
01529           break;
01530 #endif
01531         }
01532       if (extent != (WizardSizeType) ((size_t) extent))
01533         return(WizardFalse);
01534       blob_info->extent=(size_t) extent;
01535       blob_info->data=(unsigned char *) ResizeQuantumMemory(
01536         blob_info->data,blob_info->extent,sizeof(*blob_info->data));
01537       (void) SyncBlob(blob_info);
01538       if (blob_info->data == (unsigned char *) NULL)
01539         {
01540           (void) DetachBlob(blob_info);
01541           return(WizardFalse);
01542         }
01543       break;
01544     }
01545   }
01546   return(WizardTrue);
01547 }
01548 
01549 /*
01550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01551 %                                                                             %
01552 %                                                                             %
01553 %                                                                             %
01554 %  S y n c B l o b                                                            %
01555 %                                                                             %
01556 %                                                                             %
01557 %                                                                             %
01558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01559 %
01560 %  SyncBlob() flushes the datastream if it is a file or synchonizes the data
01561 %  attributes if it is an blob.
01562 %
01563 %  The format of the SyncBlob method is:
01564 %
01565 %      int SyncBlob(BlobInfo *blob_info)
01566 %
01567 %  A description of each parameter follows:
01568 %
01569 %    o blob_info: the blob info.
01570 %
01571 */
01572 WizardExport int SyncBlob(BlobInfo *blob_info)
01573 {
01574   int
01575     status;
01576 
01577   assert(blob_info != (BlobInfo *) NULL);
01578   assert(blob_info->signature == WizardSignature);
01579   (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",blob_info->filename);
01580   status=0;
01581   switch (blob_info->type)
01582   {
01583     case UndefinedStream:
01584       break;
01585     case FileStream:
01586     case StandardStream:
01587     case PipeStream:
01588     {
01589       status=fflush(blob_info->file);
01590       break;
01591     }
01592     case ZipStream:
01593     {
01594 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
01595       status=gzflush(blob_info->file,Z_SYNC_FLUSH);
01596 #endif
01597       break;
01598     }
01599     case BZipStream:
01600     {
01601 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
01602       status=BZ2_bzflush((BZFILE *) blob_info->file);
01603 #endif
01604       break;
01605     }
01606     case BlobStream:
01607     {
01608 #if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO)
01609       if (blob_info->mapped != WizardFalse)
01610         status=msync(blob_info->data,blob_info->length,MS_SYNC);
01611 #endif
01612       break;
01613     }
01614   }
01615   return(status);
01616 }
01617 
01618 /*
01619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01620 %                                                                             %
01621 %                                                                             %
01622 %                                                                             %
01623 +  T e l l B l o b                                                            %
01624 %                                                                             %
01625 %                                                                             %
01626 %                                                                             %
01627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01628 %
01629 %  TellBlob() obtains the current value of the blob or file position.
01630 %
01631 %  The format of the TellBlob method is:
01632 %
01633 %      WizardOffsetType TellBlob(const BlobInfo *blob_info)
01634 %
01635 %  A description of each parameter follows:
01636 %
01637 %    o image: The image.
01638 %
01639 */
01640 WizardExport WizardOffsetType TellBlob(const BlobInfo *blob_info)
01641 {
01642   WizardOffsetType
01643     offset;
01644 
01645   assert(blob_info != (BlobInfo *) NULL);
01646   assert(blob_info->signature == WizardSignature);
01647   assert(blob_info->type != UndefinedStream);
01648   (void) LogWizardEvent(TraceEvent,GetWizardModule(),"%s",blob_info->filename);
01649   offset=(-1);
01650   switch (blob_info->type)
01651   {
01652     case UndefinedStream:
01653       break;
01654     case FileStream:
01655     {
01656       offset=ftell(blob_info->file);
01657       break;
01658     }
01659     case StandardStream:
01660     case PipeStream:
01661       break;
01662     case ZipStream:
01663     {
01664 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
01665       offset=(WizardOffsetType) gztell(blob_info->file);
01666 #endif
01667       break;
01668     }
01669     case BZipStream:
01670       break;
01671     case BlobStream:
01672     {
01673       offset=blob_info->offset;
01674       break;
01675     }
01676   }
01677   return(offset);
01678 }
01679 
01680 /*
01681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01682 %                                                                             %
01683 %                                                                             %
01684 %                                                                             %
01685 +  U n m a p B l o b                                                          %
01686 %                                                                             %
01687 %                                                                             %
01688 %                                                                             %
01689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01690 %
01691 %  UnmapBlob() deallocates the binary large object previously allocated with
01692 %  the MapBlob method.
01693 %
01694 %  The format of the UnmapBlob method is:
01695 %
01696 %      WizardBooleanType UnmapBlob(void *map,const size_t length)
01697 %
01698 %  A description of each parameter follows:
01699 %
01700 %    o map: The address  of the binary large object.
01701 %
01702 %    o length: The length of the binary large object.
01703 %
01704 */
01705 WizardExport WizardBooleanType UnmapBlob(void *map,const size_t length)
01706 {
01707 #if defined(WIZARDSTOOLKIT_HAVE_MMAP_FILEIO)
01708   int
01709     status;
01710 
01711   status=munmap(map,length);
01712   return(status == -1 ? WizardFalse : WizardTrue);
01713 #else
01714   return(WizardFalse);
01715 #endif
01716 }
01717 
01718 /*
01719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01720 %                                                                             %
01721 %                                                                             %
01722 %                                                                             %
01723 +  W r i t e B l o b                                                          %
01724 %                                                                             %
01725 %                                                                             %
01726 %                                                                             %
01727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01728 %
01729 %  WriteBlob() writes data to a blob or blob_info file.  It returns the number
01730 %  of bytes written.
01731 %
01732 %  The format of the WriteBlob method is:
01733 %
01734 %      ssize_t WriteBlob(BlobInfo *blob_info,const size_t length,
01735 %        const unsigned char *data)
01736 %
01737 %  A description of each parameter follows:
01738 %
01739 %    o blob_info: the blob.
01740 %
01741 %    o length: the number of bytes to write to the blob.
01742 %
01743 %    o data: the area to place the information requested from the blob.
01744 %
01745 */
01746 WizardExport ssize_t WriteBlob(BlobInfo *blob_info,const size_t length,
01747   const unsigned char *data)
01748 {
01749   int
01750     c;
01751 
01752   register const unsigned char
01753     *p;
01754 
01755   ssize_t
01756     count;
01757 
01758   assert(blob_info != (BlobInfo *) NULL);
01759   assert(blob_info->signature == WizardSignature);
01760   assert(data != (const unsigned char *) NULL);
01761   if (length == 0)
01762     return(0);
01763   count=0;
01764   p=data;
01765   switch (blob_info->type)
01766   {
01767     case UndefinedStream:
01768       break;
01769     case FileStream:
01770     case StandardStream:
01771     case PipeStream:
01772     {
01773       switch (length)
01774       {
01775         default:
01776         {
01777           count=(ssize_t) fwrite((const char *) data,1,length,
01778             blob_info->file);
01779           break;
01780         }
01781         case 2:
01782         {
01783           c=putc((int) *p++,blob_info->file);
01784           if (c == EOF)
01785             break;
01786           count++;
01787         }
01788         case 1:
01789         {
01790           c=putc((int) *p++,blob_info->file);
01791           if (c == EOF)
01792             break;
01793           count++;
01794         }
01795         case 0:
01796           break;
01797       }
01798       break;
01799     }
01800     case ZipStream:
01801     {
01802 #if defined(WIZARDSTOOLKIT_ZLIB_DELEGATE)
01803       switch (length)
01804       {
01805         default:
01806         {
01807           count=(ssize_t) gzwrite(blob_info->file,(void *) data,
01808             (unsigned int) length);
01809           break;
01810         }
01811         case 2:
01812         {
01813           c=gzputc(blob_info->file,(int) *p++);
01814           if (c == EOF)
01815             break;
01816           count++;
01817         }
01818         case 1:
01819         {
01820           c=gzputc(blob_info->file,(int) *p++);
01821           if (c == EOF)
01822             break;
01823           count++;
01824         }
01825         case 0:
01826           break;
01827       }
01828 #endif
01829       break;
01830     }
01831     case BZipStream:
01832     {
01833 #if defined(WIZARDSTOOLKIT_BZLIB_DELEGATE)
01834       count=(ssize_t) BZ2_bzwrite((BZFILE *) blob_info->file,(void *) data,
01835         (int) length);
01836 #endif
01837       break;
01838     }
01839     case BlobStream:
01840     {
01841       register unsigned char
01842         *q;
01843 
01844       if ((blob_info->offset+(WizardOffsetType) length) >=
01845           (WizardOffsetType) blob_info->extent)
01846         {
01847           if (blob_info->mapped != WizardFalse)
01848             return(0);
01849           blob_info->quantum<<=1;
01850           blob_info->extent+=length+blob_info->quantum;
01851           blob_info->data=(unsigned char *) ResizeQuantumMemory(
01852             blob_info->data,blob_info->extent+1,
01853             sizeof(*blob_info->data));
01854           (void) SyncBlob(blob_info);
01855           if (blob_info->data == (unsigned char *) NULL)
01856             {
01857               (void) DetachBlob(blob_info);
01858               return(0);
01859             }
01860         }
01861       q=blob_info->data+blob_info->offset;
01862       (void) CopyWizardMemory(q,p,length);
01863       blob_info->offset+=length;
01864       if (blob_info->offset >= (WizardOffsetType) blob_info->length)
01865         blob_info->length=(size_t) blob_info->offset;
01866       count=(ssize_t) length;
01867     }
01868   }
01869   return(count);
01870 }
01871 
01872 /*
01873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01874 %                                                                             %
01875 %                                                                             %
01876 %                                                                             %
01877 +  W r i t e B l o b B y t e                                                  %
01878 %                                                                             %
01879 %                                                                             %
01880 %                                                                             %
01881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01882 %
01883 %  WriteBlobByte() write an integer to a blob.  It returns the number of bytes
01884 %  written (either 0 or 1);
01885 %
01886 %  The format of the WriteBlobByte method is:
01887 %
01888 %      ssize_t WriteBlobByte(BlobInfo *blob_info,const unsigned char value)
01889 %
01890 %  A description of each parameter follows.
01891 %
01892 %    o blob_info: the blob info.
01893 %
01894 %    o value: the value to write.
01895 %
01896 */
01897 
01898 static inline ssize_t WriteBlobStream(BlobInfo *blob_info,const size_t length,
01899   const unsigned char *data)
01900 {
01901   register unsigned char
01902     *q;
01903 
01904   WizardSizeType
01905     extent;
01906 
01907   assert(blob_info != (BlobInfo *) NULL);
01908   if (blob_info->type != BlobStream)
01909     return(WriteBlob(blob_info,length,data));
01910   assert(blob_info->type != UndefinedStream);
01911   assert(data != (void *) NULL);
01912   extent=(WizardSizeType) (blob_info->offset+(WizardOffsetType) length);
01913   if (extent >= blob_info->extent)
01914     {
01915       blob_info->quantum<<=1;
01916       extent=blob_info->extent+blob_info->quantum+length;
01917       if (SetBlobExtent(blob_info,extent) == WizardFalse)
01918         return(0);
01919     }
01920   q=blob_info->data+blob_info->offset;
01921   (void) CopyWizardMemory(q,data,length);
01922   blob_info->offset+=length;
01923   if (blob_info->offset >= (WizardOffsetType) blob_info->length)
01924     blob_info->length=(size_t) blob_info->offset;
01925   return((ssize_t) length);
01926 }
01927 
01928 WizardExport ssize_t WriteBlobByte(BlobInfo *blob_info,
01929   const unsigned char value)
01930 {
01931   assert(blob_info != (BlobInfo *) NULL);
01932   assert(blob_info->signature == WizardSignature);
01933   return(WriteBlobStream(blob_info,1,&value));
01934 }
01935 
01936 /*
01937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01938 %                                                                             %
01939 %                                                                             %
01940 %                                                                             %
01941 +  W r i t e B l o b C h u n k                                                %
01942 %                                                                             %
01943 %                                                                             %
01944 %                                                                             %
01945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01946 %
01947 %  WriteBlobChunk() writes data to a blob or blob_info file.  It returns the
01948 %  number of bytes written.  WriteBlobChunk() differs from WriteBlob() by
01949 %  making an effort to write the number of bytes that was requested except in
01950 %  the event an EOF is encountered.
01951 %
01952 %  The format of the WriteBlob method is:
01953 %
01954 %      ssize_t WriteBlobChunk(BlobInfo *blob_info,const size_t length,
01955 %        const unsigned char *data)
01956 %
01957 %  A description of each parameter follows:
01958 %
01959 %    o blob_info: the blob.
01960 %
01961 %    o length: the number of bytes to write to the blob.
01962 %
01963 %    o data: the area to place the information requested from the blob.
01964 %
01965 */
01966 WizardExport ssize_t WriteBlobChunk(BlobInfo *blob_info,const size_t length,
01967   const unsigned char *data)
01968 {
01969   register ssize_t
01970     i;
01971 
01972   ssize_t
01973     count;
01974 
01975   assert(blob_info != (BlobInfo *) NULL);
01976   assert(blob_info->signature == WizardSignature);
01977   assert(data != (const unsigned char *) NULL);
01978   if (blob_info->type == BlobStream)
01979     return(WriteBlob(blob_info,length,data));
01980   count=0;
01981   for (i=0; i < (ssize_t) length; i+=count)
01982   {
01983     count=WriteBlob(blob_info,WizardMin(length-i,(size_t) SSIZE_MAX),data+i);
01984     if (count <= 0)
01985       {
01986         count=0;
01987         if (errno != EINTR)
01988           break;
01989       }
01990   }
01991   return(i);
01992 }
01993 
01994 /*
01995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01996 %                                                                             %
01997 %                                                                             %
01998 %                                                                             %
01999 +  W r i t e B l o b S t r i n g                                              %
02000 %                                                                             %
02001 %                                                                             %
02002 %                                                                             %
02003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
02004 %
02005 %  WriteBlobString() write a string to a blob.  It returns the number of
02006 %  characters written.
02007 %
02008 %  The format of the WriteBlobString method is:
02009 %
02010 %      ssize_t WriteBlobString(BlobInfo *blob_info,const char *string)
02011 %
02012 %  A description of each parameter follows.
02013 %
02014 %    o image: The image.
02015 %
02016 %    o string: Specifies the string to write.
02017 %
02018 */
02019 WizardExport ssize_t WriteBlobString(BlobInfo *blob_info,const char *string)
02020 {
02021   ssize_t
02022     count;
02023 
02024   assert(blob_info != (BlobInfo *) NULL);
02025   assert(blob_info->signature == WizardSignature);
02026   assert(string != (const char *) NULL);
02027   count=WriteBlobStream(blob_info,strlen(string),(const unsigned char *)
02028     string);
02029   return(count);
02030 }
Generated by  doxygen 1.6.2-20100208