G:/ScriptBasic/source/extensions/zlib/interface.c

Go to the documentation of this file.
00001 /* FILE: zlbintrf.c
00002 
00003 This file is a ScriptBasic interface file to the library zlib.
00004 
00005 
00006 NTLIBS: zlibs.lib
00007 UXLIBS: -lc -lz
00008 DWLIBS: -lc -lz
00009 */
00010 #include <stdio.h>
00011 #include "../../basext.h"
00012 
00013 #include "zlib.h"
00014 
00015 #define ZLIB_ERROR_INTERNAL001 0x00080001
00016 #define ZLIB_ERROR_INTERNAL002 0x00080002
00017 #define ZLIB_ERROR_INTERNAL003 0x00080003
00018 #define ZLIB_ERROR_INTERNAL004 0x00080004
00019 #define ZLIB_ERROR_INTERNAL005 0x00080005
00020 #define ZLIB_ERROR_INTERNAL006 0x00080006
00021 #define ZLIB_ERROR_INTERNAL007 0x00080007
00022 
00023 #define ZLIB_ERROR_NOCOMPRESS  0x00080100
00024 #define ZLIB_ERROR_ARGUMENT    0x00080101
00025 #define ZLIB_ERROR_DATA        0x00080102
00026 #define ZLIB_ERROR_DATA1       0x00080103
00027 #define ZLIB_ERROR_FILE_READ   0x00080104
00028 #define ZLIB_ERROR_FILE_WRITE  0x00080105
00029 
00030 /* This is the buffer increment size in case no data was inflated
00031    in the first run or in case estimate is too small (smaller than this
00032    value).                                                              */
00033 #define ZBUFFER_INCREASE 1024
00034 
00035 
00036 /* This is the file buffer size when converting a file to gz and back.  */
00037 #define ZBUFFER_SIZE 1024
00038 
00039 besVERSION_NEGOTIATE
00040 
00041   return (int)INTERFACE_VERSION;
00042 
00043 besEND
00044 
00045 besSUB_START
00046 
00047 besEND
00048 
00049 besSUB_FINISH
00050 
00051 besEND
00052 
00053 /* functions that are passed to the zlib library to allocate memory */
00054 static void *zliballoc_interface(void *opaque, uInt items, uInt size){
00055   pSupportTable pSt;
00056   void *pvReturn;
00057 
00058   pSt = opaque;
00059   pvReturn = besALLOC((long)items*size);
00060   if( pvReturn )return pvReturn;
00061   return Z_NULL;
00062   }
00063 static void zlibfree_interface(void *opaque, voidpf address){
00064   pSupportTable pSt;
00065 
00066   pSt = opaque;
00067   besFREE(address);
00068   }
00069 
00092 besFUNCTION(zlbcmprs)
00093   VARIABLE Argument;
00094   z_stream zsStream;
00095   int iCompressionLevel;
00096   unsigned char *pszBuffer;
00097   int iZError;
00098 
00099   besRETURNVALUE = NULL;
00100 
00101   if( besARGNR < 1 )return EX_ERROR_TOO_FEW_ARGUMENTS;
00102 
00103   zsStream.data_type = Z_UNKNOWN;
00104   zsStream.opaque = pSt;
00105   zsStream.zalloc = zliballoc_interface;
00106   zsStream.zfree  = zlibfree_interface;
00107 
00108   /* Get the compression level to be used from the option
00109 
00110      option zlib$CompressionLevel x
00111 
00112      If this is not set then the default compression level
00113      is 6 (zlib 5).
00114 
00115      Note that the BASIC program should use compression level
00116      1 ... 10. This is converted to 0 ... 9. This is because
00117      option value zero is the default in ScriptBasic and there is
00118      no way to guess if the option is set to zero or is not present.
00119 
00120      Therefore the BASIC code should not bother compression level and
00121      use the default level 6 (zlib 5) or should set it between 1 and 10.
00122 
00123      If the compression level is higher than 10 then it is set to 10 (zlib level 9).
00124      If the compression level is negative it is set to 1 (zlib level 0).
00125   */
00126 
00127   iCompressionLevel = (int)besOPTION("zlib$CompressionLevel");
00128   if( iCompressionLevel > 10 )iCompressionLevel = 10;
00129   if( iCompressionLevel < 0 )iCompressionLevel = 1;
00130   if( iCompressionLevel == 0 )
00131     iCompressionLevel = Z_DEFAULT_COMPRESSION;
00132   else
00133     iCompressionLevel --;
00134 
00135   /* get the string to be compressed */
00136 
00137   Argument = besARGUMENT(1);
00138   besDEREFERENCE(Argument);
00139   /* if the argument is undefined we raise error */
00140   if( Argument == NULL )return ZLIB_ERROR_ARGUMENT;
00141   if( Argument->vType != VTYPE_STRING )
00142     Argument = besCONVERT2STRING(Argument);
00143 
00144   pszBuffer = besALLOC(STRLEN(Argument));
00145   if( pszBuffer == NULL )return COMMAND_ERROR_MEMORY_LOW;
00146 
00147   zsStream.next_in = STRINGVALUE(Argument);
00148   zsStream.avail_in = STRLEN(Argument);
00149   zsStream.total_in = STRLEN(Argument);
00150   zsStream.avail_out = STRLEN(Argument);
00151   zsStream.next_out = pszBuffer;
00152   zsStream.total_out = 0;
00153 
00154   iZError = deflateInit(&zsStream,iCompressionLevel);
00155   if( iZError == Z_MEM_ERROR )return COMMAND_ERROR_MEMORY_LOW;
00156   /* this should not happen, because we have checked the compression level value */
00157   if( iZError == Z_STREAM_ERROR )return ZLIB_ERROR_INTERNAL001;
00158   /* this happens if the module was built using an incorrect version of the static lib file */
00159   if( iZError == Z_VERSION_ERROR )return ZLIB_ERROR_INTERNAL002;
00160 
00161   iZError = deflate(&zsStream,Z_FINISH);
00162 
00163   if( iZError != Z_STREAM_END )return ZLIB_ERROR_NOCOMPRESS;
00164 
00165   besALLOC_RETURN_STRING(zsStream.total_out);
00166 
00167   memcpy(STRINGVALUE(besRETURNVALUE),pszBuffer,zsStream.total_out);
00168   besFREE(pszBuffer);
00169   deflateEnd(&zsStream);
00170 besEND
00171 
00180 besFUNCTION(zlbucprs)
00181   VARIABLE Argument;
00182   long lBufferSize,lCompressedSize,lNewBufferSize;
00183   z_stream zsStream;
00184   unsigned char *pszBuffer,*pszNewBuffer;
00185   int iZError;
00186 
00187   besRETURNVALUE = NULL;
00188 
00189   if( besARGNR < 1 )return EX_ERROR_TOO_FEW_ARGUMENTS;
00190 
00191   zsStream.data_type = Z_UNKNOWN;
00192   zsStream.opaque = pSt;
00193   zsStream.zalloc = zliballoc_interface;
00194   zsStream.zfree  = zlibfree_interface;
00195 
00196   /* get the string to be uncompressed */
00197   Argument = besARGUMENT(1);
00198   besDEREFERENCE(Argument);
00199 
00200   /* if the argument is undefined we raise error */
00201   if( Argument == NULL )return ZLIB_ERROR_ARGUMENT;
00202 
00203   /* the argument should be a string. This is not likely that a long
00204      or a double converted to string could be reasonably uncompressed. */
00205   if( Argument->vType != VTYPE_STRING )return ZLIB_ERROR_ARGUMENT;
00206 
00207   /* first we allocate a buffer that is as large as the compressed image. */
00208   lCompressedSize = lBufferSize = STRLEN(Argument);
00209   pszBuffer = besALLOC(lBufferSize);
00210   if( pszBuffer == NULL )return COMMAND_ERROR_MEMORY_LOW;
00211 
00212   zsStream.next_in = STRINGVALUE(Argument);
00213   zsStream.avail_in = STRLEN(Argument);
00214   zsStream.total_in = STRLEN(Argument);
00215   zsStream.avail_out = STRLEN(Argument);
00216   zsStream.next_out = pszBuffer;
00217   zsStream.total_out = 0;
00218 
00219   iZError = inflateInit(&zsStream);
00220   if( iZError == Z_MEM_ERROR )return COMMAND_ERROR_MEMORY_LOW;
00221   /* this should not happen, because we have checked the compression level value */
00222   if( iZError == Z_STREAM_ERROR )return ZLIB_ERROR_INTERNAL003;
00223   /* this happens if the module was built using an incorrect version of the static lib file */
00224   if( iZError == Z_VERSION_ERROR )return ZLIB_ERROR_INTERNAL004;
00225 
00226   /* inflate the input buffer to the output buffer and put as many
00227      output bytes to the output as possible */
00228   while( (iZError = inflate(&zsStream,Z_SYNC_FLUSH)) != Z_STREAM_END ){
00229     switch( iZError ){
00230       case Z_DATA_ERROR:   besFREE(pszBuffer);
00231                            return ZLIB_ERROR_DATA;
00232       case Z_NEED_DICT:    besFREE(pszBuffer);
00233                            return ZLIB_ERROR_DATA1;
00234       case Z_STREAM_ERROR: besFREE(pszBuffer);
00235                            return ZLIB_ERROR_INTERNAL005;
00236       case Z_MEM_ERROR:    besFREE( pszBuffer );
00237                            return COMMAND_ERROR_MEMORY_LOW;
00238       case Z_BUF_ERROR:    besFREE(pszBuffer);
00239                            return ZLIB_ERROR_INTERNAL006;
00240       }
00241     if( iZError != Z_OK ){
00242       besFREE(pszBuffer);
00243       return ZLIB_ERROR_INTERNAL007;
00244       }
00245 
00246     /* estimate the buffer size needed to hold the uncompressed data */
00247     if( lCompressedSize - zsStream.avail_in > 0 ){
00248       lNewBufferSize = (zsStream.total_out*lCompressedSize) / (lCompressedSize - zsStream.avail_in);
00249       /* We avoid extraordinarily large buffer allocation in case the uncompressed data starts
00250          with some redundant area and therefore starts inflating extremely and indicate huge
00251          final size. Never increase the buffer larger than the double of the current. */
00252       if( lNewBufferSize > 2 * lBufferSize )
00253         lNewBufferSize = 2 * lBufferSize;
00254       /* The estimate may be sensitive to rounding error when there are only a few bytes left. To
00255          avoid the situation when the final bytes are allocated individually we always increase the
00256          buffer at least ZBUFFER_INCREASE bytes. */
00257       if( lNewBufferSize < lBufferSize + ZBUFFER_INCREASE )
00258         lNewBufferSize = lBufferSize + ZBUFFER_INCREASE;
00259       }else{
00260       /* if the output buffer was so small that the decompressor just could not start then we have
00261          no estimate on the output buffer size. Just increase it adding the default increase to
00262          the size. */
00263       lNewBufferSize = lBufferSize + ZBUFFER_INCREASE;
00264       }
00265 
00266     /* Allocate the new buffer. */
00267     pszNewBuffer = besALLOC(lNewBufferSize);
00268     if( pszNewBuffer == NULL ){
00269       besFREE(pszBuffer);
00270       return COMMAND_ERROR_MEMORY_LOW;
00271       }
00272 
00273     /* copy the content of the old buffer to the new location and release the old buffer */
00274     memcpy(pszNewBuffer,pszBuffer,zsStream.total_out);
00275     besFREE(pszBuffer);
00276 
00277     pszBuffer = pszNewBuffer; /* from now on this is the new buffer */
00278 
00279     zsStream.next_out = pszBuffer + zsStream.total_out;
00280     zsStream.avail_out += lNewBufferSize - zsStream.total_out;
00281     lBufferSize = lNewBufferSize;
00282     }
00283 
00284   if( iZError != Z_STREAM_END )return ZLIB_ERROR_NOCOMPRESS;
00285 
00286   besALLOC_RETURN_STRING(zsStream.total_out);
00287 
00288   memcpy(STRINGVALUE(besRETURNVALUE),pszBuffer,zsStream.total_out);
00289   besFREE(pszBuffer);
00290   inflateEnd(&zsStream);
00291 besEND
00292 
00293 #define GZ_SUFFIX ".gz"
00294 
00303 besFUNCTION(gzipfunc)
00304   VARIABLE Argument;
00305   int FileAccess;
00306   char *pszInputFileName;
00307   char *pszOutputFileName;
00308   FILE *fin;
00309   gzFile out;
00310   char mode[4];
00311   size_t len;
00312   char *buf;
00313   int iCompressionLevel;
00314   int iRemoveOriginal;
00315 
00316   mode[0] = 'w';mode[1] = 'b';mode[2] = (char)0;
00317 
00318   iCompressionLevel = (int)besOPTION("zlib$CompressionLevel");
00319   if( iCompressionLevel > 10 )iCompressionLevel = 10;
00320   if( iCompressionLevel < 0 )iCompressionLevel = 1;
00321   if( iCompressionLevel > 0 ){
00322     mode[2] = '0' + iCompressionLevel;
00323     mode[3] = (char)0;
00324     }
00325   besRETURNVALUE = NULL;
00326 
00327   if( besARGNR < 1 )return EX_ERROR_TOO_FEW_ARGUMENTS;
00328 
00329   /* get the input file name */
00330   Argument = besARGUMENT(1);
00331   besDEREFERENCE(Argument);
00332   if( Argument == NULL )return EX_ERROR_TOO_FEW_ARGUMENTS;
00333   Argument = besCONVERT2STRING(Argument);
00334   besCONVERT2ZCHAR(Argument,pszInputFileName);
00335 
00336   if( besARGNR >= 3 )
00337     Argument = besARGUMENT(3);
00338   else
00339     Argument = NULL;
00340   if( Argument ){
00341     besDEREFERENCE(Argument);
00342     Argument = besCONVERT2LONG(Argument);
00343     iRemoveOriginal = LONGVALUE(Argument);
00344     }else iRemoveOriginal = 1;
00345 
00346   if( besARGNR >= 2 ){
00347     Argument = besARGUMENT(2);
00348     besDEREFERENCE(Argument);
00349     }else Argument = NULL;
00350 
00351   if( Argument == NULL ){
00352     pszOutputFileName = besALLOC(strlen(pszInputFileName)+strlen(GZ_SUFFIX)+1);
00353     strcpy(pszOutputFileName,pszInputFileName);
00354     strcat(pszOutputFileName,GZ_SUFFIX);
00355     }else{
00356     /* get the output file name */
00357     Argument = besCONVERT2STRING(Argument);
00358     besCONVERT2ZCHAR(Argument,pszOutputFileName);
00359     }
00360 
00361   if( !strcmp(pszInputFileName,pszOutputFileName) ){
00362     besFREE(pszInputFileName);
00363     besFREE(pszOutputFileName);
00364     return EX_ERROR_TOO_FEW_ARGUMENTS;
00365     }
00366 
00367   FileAccess = besHOOK_FILE_ACCESS(pszOutputFileName);
00368   if( !(FileAccess&2) ){
00369     besFREE(pszInputFileName);
00370     besFREE(pszOutputFileName);
00371     return COMMAND_ERROR_FILE_CANNOT_BE_OPENED;
00372     }
00373 
00374   fin = besHOOK_FOPEN(pszInputFileName,"rb");
00375   if( fin == NULL ){
00376     besFREE(pszOutputFileName);
00377     return COMMAND_ERROR_FILE_CANNOT_BE_OPENED;
00378     }
00379   out = gzopen(pszOutputFileName,mode);
00380   besFREE(pszOutputFileName);
00381   if( out == NULL ){
00382     besFREE(pszInputFileName);
00383     besHOOK_FCLOSE(fin);
00384     return COMMAND_ERROR_FILE_CANNOT_BE_OPENED;
00385     }
00386 
00387   buf = besALLOC(ZBUFFER_SIZE);
00388   if( buf == NULL ){
00389     besFREE(pszInputFileName);
00390     besHOOK_FCLOSE(fin);
00391     gzclose(out);
00392     return COMMAND_ERROR_MEMORY_LOW;
00393     }
00394   for(;;){
00395     len = besHOOK_FREAD(buf, 1, ZBUFFER_SIZE, fin);
00396     if( besHOOK_FERROR(fin) ){
00397       besFREE(pszInputFileName);
00398       gzclose(out);
00399       besHOOK_FCLOSE(fin);
00400       return ZLIB_ERROR_FILE_READ;
00401       }
00402     if( len == 0 )break;
00403 #pragma warning (disable:4018)
00404     if( gzwrite(out, buf, (unsigned)len) != len ){
00405 #pragma warning (default:4018)
00406       besFREE(pszInputFileName);
00407       gzclose(out);
00408       besHOOK_FCLOSE(fin);
00409       return ZLIB_ERROR_FILE_WRITE;
00410       }
00411     }
00412   besFREE(buf);
00413   gzclose(out);
00414   besHOOK_FCLOSE(fin);
00415 
00416   /* the final step is to remove the original file */
00417   if( iRemoveOriginal )
00418     besHOOK_REMOVE(pszInputFileName);
00419   besFREE(pszInputFileName);
00420 besEND
00421 
00431 besFUNCTION(gunzpfnc)
00432   VARIABLE Argument;
00433   int FileAccess;
00434   char *pszInputFileName;
00435   char *pszOutputFileName;
00436   FILE *out,*fp;
00437   gzFile fin;
00438   long len;
00439   char *buf;
00440   int iRemoveOriginal,ch,gzHeaderOK;
00441   static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
00442 
00443   besRETURNVALUE = NULL;
00444 
00445   if( besARGNR < 1 )return EX_ERROR_TOO_FEW_ARGUMENTS;
00446 
00447   /* get the input file name */
00448   Argument = besARGUMENT(1);
00449   besDEREFERENCE(Argument);
00450   if( Argument == NULL )return EX_ERROR_TOO_FEW_ARGUMENTS;
00451   Argument = besCONVERT2STRING(Argument);
00452   besCONVERT2ZCHAR(Argument,pszInputFileName);
00453 
00454   if( besARGNR >= 3 )
00455     Argument = besARGUMENT(3);
00456   else
00457     Argument = NULL;
00458   if( Argument ){
00459     besDEREFERENCE(Argument);
00460     Argument = besCONVERT2LONG(Argument);
00461     iRemoveOriginal = LONGVALUE(Argument);
00462     }else iRemoveOriginal = 1;
00463 
00464   if( besARGNR >= 2 ){
00465     Argument = besARGUMENT(2);
00466     besDEREFERENCE(Argument);
00467     }else Argument = NULL;
00468 
00469   if( Argument == NULL ){
00470     len = strlen(pszInputFileName);
00471     pszOutputFileName = besALLOC(len+1);
00472     strcpy(pszOutputFileName,pszInputFileName);
00473     /* create the output file chopping off the .gz or .z extension */
00474     if( len > 2 &&
00475         tolower(pszOutputFileName[len-1]) == 'z' &&
00476         tolower(pszOutputFileName[len-2]) == 'g' &&
00477         pszOutputFileName[len-3] == '.' ){
00478         pszOutputFileName[len-3] = (char)0;
00479         }else
00480      if( len > 1 &&
00481         tolower(pszOutputFileName[len-1]) == 'z' &&
00482         pszOutputFileName[len-2] == '.' ){
00483         pszOutputFileName[len-2] = (char)0;
00484         }else{
00485         /* if there is only a single argument (input file name) and
00486            that argument string is not ending with .z or .gz then
00487            we can not guess the output file name. */
00488         besFREE(pszOutputFileName);
00489         besFREE(pszInputFileName);
00490         return EX_ERROR_TOO_FEW_ARGUMENTS;
00491         }
00492     }else{
00493     /* get the output file name */
00494     Argument = besCONVERT2STRING(Argument);
00495     besCONVERT2ZCHAR(Argument,pszOutputFileName);
00496     }
00497 
00498   /* the input and the output file names can not be the same
00499      we can not cope with the same file with different name issue however. */
00500   if( !strcmp(pszInputFileName,pszOutputFileName) ){
00501     besFREE(pszInputFileName);
00502     besFREE(pszOutputFileName);
00503     return EX_ERROR_TOO_FEW_ARGUMENTS;
00504     }
00505 
00506   FileAccess = besHOOK_FILE_ACCESS(pszInputFileName);
00507   if( !(FileAccess&1) ){
00508     besFREE(pszInputFileName);
00509     besFREE(pszOutputFileName);
00510     return COMMAND_ERROR_FILE_CANNOT_BE_OPENED;
00511     }
00512 
00513   gzHeaderOK = 1;
00514   fp = fopen(pszInputFileName,"rb");
00515   if( fp != NULL ){
00516     ch = fgetc(fp);
00517     if( ch != gz_magic[0] )gzHeaderOK = 0;
00518     ch = fgetc(fp);
00519     if( ch != gz_magic[1] )gzHeaderOK = 0;
00520     fclose(fp);
00521     }else gzHeaderOK = 0;
00522 
00523   fin = gzHeaderOK ? gzopen(pszInputFileName,"rb") : NULL;
00524   if( fin == NULL ){
00525     besFREE(pszOutputFileName);
00526     return COMMAND_ERROR_FILE_CANNOT_BE_OPENED;
00527     }
00528   out = besHOOK_FOPEN(pszOutputFileName,"wb");
00529   besFREE(pszOutputFileName);
00530   if( out == NULL ){
00531     besFREE(pszInputFileName);
00532     gzclose(fin);
00533     return COMMAND_ERROR_FILE_CANNOT_BE_OPENED;
00534     }
00535 
00536   buf = besALLOC(ZBUFFER_SIZE);
00537   if( buf == NULL ){
00538     besFREE(pszInputFileName);
00539     besHOOK_FCLOSE(out);
00540     gzclose(fin);
00541     return COMMAND_ERROR_MEMORY_LOW;
00542     }
00543   for(;;){
00544     len = gzread(fin,buf, ZBUFFER_SIZE);
00545     if( len < 0 ){
00546       besFREE(pszInputFileName);
00547       gzclose(fin);
00548       besHOOK_FCLOSE(out);
00549       return ZLIB_ERROR_FILE_READ;
00550       }
00551     if( len == 0 )break;
00552     if( besHOOK_FWRITE(buf,1,len,out) != len ){
00553       besFREE(pszInputFileName);
00554       gzclose(fin);
00555       besHOOK_FCLOSE(out);
00556       return ZLIB_ERROR_FILE_WRITE;
00557       }
00558     }
00559   besFREE(buf);
00560   gzclose(fin);
00561   besHOOK_FCLOSE(out);
00562 
00563   /* the final step is to remove the original file */
00564   if( iRemoveOriginal )
00565     besHOOK_REMOVE(pszInputFileName);
00566   besFREE(pszInputFileName);
00567 besEND
00568 

Generated on Sun Mar 12 23:56:29 2006 for ScriptBasic by  doxygen 1.4.6-NO