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