INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Compression

How to Add Compression to a VFP Program Without ActiveX, Without $ by wgcs
Posted: 21 Jun 02 (Edited 19 Aug 04)

This is a Neat little way to add compression to your program.  Note: This compression is the Squeeze algorithm used by PkZip, but does not produce ".ZIP" compatible files... basically, it takes a string and produces a smaller string that can later be un-squeezed back to it's original state.

Because this uses the FileToStr and StrToFile VFP functions, it is limited to VFP's string handling limits, which appears to be limited to about 16MB per file (since it seems VFP uses three bytes (24 bits) to store the length of a string, so the largest string it can handle is 16777184 bytes long (ie, 2^24 - 24(length) - 8(null))

First, Get zLib from http://www.gzip.org/zlib/ (more specifically, the Win32 zLib.DLL at http://www.winimage.com/zLibDll/zlib114dll.zip ) and place it into your app's directory.

Now, create zLib.prg:

CODE

*******************************************************
* zLib.prg
*  Author: William GC Steinford
*    Date: June 20, 2002
* Purpose: Easy to use Compress/Uncompress utilities
*            for VFP
*******************************************************
PROCEDURE zLib
PARAMETER cFunc, cStr
  DO CASE
    CASE upper(cFunc)='COMPRESS'
      RETURN CompressIt(cStr)
    CASE upper(cFunc)='UNCOMPRESS'
      RETURN UnCompressIt(cStr)
  ENDCASE
RETURN ''
* Functions:
*!*    int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
*!*    int uncompress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);

Function CompressIt( InFile )
DECLARE INTEGER compress IN zlib.dll AS zlibCompress ;
  STRING @ dest, INTEGER @ destLen, ;
  STRING src, INTEGER srcLen
* Compresses the source buffer into the destination buffer.
*   sourceLen is the byte length of the source buffer. Upon entry,
*   destLen is the total size of the destination buffer, which must
*   be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit,
*   destLen is the actual size of the compressed buffer.
LOCAL lnSize, lcBuff, lnFinalSize
lnSize = len(InFile)
*123,456,789,012,345  15 chars is enough for 100 Terabytes.
*100,000,000,000,000
lcBuff      = space( len(InFile)*1.2 )
lnFinalSize = len(lcBuff)
Res = zlibCompress( @lcBuff, @lnFinalSize, InFile, lnSize )
If Res=0 && Success
  RETURN PadL( alltrim(str(lnSize)), 15, '0' ) + Left( lcBuff, lnFinalSize )
endif
RETURN ''

****************************************************************************
* Proc UnCompressIt
*  The first 15 chars MUST be the (decimal) size of the uncompressed file
FUNCTION UnCompressIt( zLibFile )
DECLARE INTEGER uncompress IN zlib.dll AS zlibUnCompress ;
  STRING @ dest, INTEGER @ destLen, ;
  STRING src, INTEGER srcLen
* Decompresses the source buffer into the destination buffer.
*   sourceLen is the byte length of the source buffer. Upon entry,
*   destLen is the total size of the destination buffer, which must
*   be large enough to hold the entire uncompressed data.
* (The size of the uncompressed data must have been saved previously
*  by the compressor and transmitted to the decompressor by some mechanism
*  outside the scope of this compression library.)
*  Upon exit, destLen is the actual size of the compressed buffer.
* This function can be used to decompress a whole file at once if the input file is mmap'ed.
*
LOCAL lnSize, lcBuff, lnFinalSize
lnSize = len(zLibFile)
*123,456,789,012,345  15 chars is enough for 100 Terabytes.
*100,000,000,000,000
lnFinalSize = Val( Left( zLibFile, 15 ) )
lcBuff      = space( lnFinalSize )
zLibFile    = SubStr( zLibFile, 16 )
Res = zlibUnCompress( @lcBuff, @lnFinalSize, zLibFile, lnSize )
If Res=0 && Success
  RETURN lcBuff
endif
RETURN ''
********************************************************

Now, you can use it in either of these manners:

CODE

  SET PROCEDURE TO zLib ADDITIVE
  x = CompressIt( FileToStr("testfile.txt") )
  y = UnCompressIt( x )
  StrToFile( y, "testfile.txt.out" )
  RELEASE PROCEDURE zLib

** OR **

  x = zLib("CompressIt", FileToStr("testfile.txt") )
  y = zLib("UnCompressIt", x )
  StrToFile( y, "testfile.txt.out" )

There's room for even more improvement...

Want to do multiple files?
Just create a table with two fields: "FileName" and "FileData" to keep track of a bunch of compressed files.
For example:

CODE

  SET PROC TO (srcDrv+"\source\las\zLib") ADDITIVE
  
  CREATE TABLE plg_Inst.dbf ;
    ( FileName   C(30), ;
      FileData   M,     ;
      Register   L,     ;
      Compressed L,     ;
      OrigSize   N(15)   )
  Select Plg_Inst
  fCnt = aDir( fArr, "*.HTM" )
  if fCnt > 0
    for fNum = 1 to fCnt
      append blank
      REPLACE FileName with fArr[fNum,1], ;
              FileData with CompressIt( FileToStr(fArr[fNum,1]) ), ;
              Compressed with .T.
    endfor
  endif

Then when you want to extract them:

CODE

  if file('PLG_INST.DBF') and file('PLG_INST.FPT')
    * Copy DBF/FPT out because VFP has "issues" with
    *   accessing "included" FPT files.
    aa=FileToStr('PLG_INST.DBF')
    bb=FileToStr('PLG_INST.FPT')
    StrToFile(aa,'tmp_Inst.dbf')
    StrToFile(bb,'tmp_Inst.fpt')
    SELECT 0
    USE TMP_INST.DBF ALIAS plg_Inst
    * Dump out all internal files!
    SCAN
      If not empty(Plg_inst.FileName) ;
         and not empty(Plg_inst.FileData)
        if Plg_Inst.Compressed
          lcCompFile   = Plg_Inst.FileData
          lcUnCompFile = zLib("UnCompressIt", lcCompFile )
          if not empty(lcUnCompFile)
            =StrToFile( lcUnCompFile, alltrim(Plg_Inst.FileName) )
          else
            =MessageBox( 'Could not uncompress file "'+Plg_Inst.FileName+'".', mbxOk)
          endif
        else
          =StrToFile( Plg_Inst.FileData, alltrim(Plg_Inst.FileName) )
        endif
      endif
    ENDSCAN
    USE
    IF FILE('TMP_INST.DBF')
      DELETE FILE TMP_INST.DBF
    ENDIF
    IF FILE('TMP_INST.FPT')
      DELETE FILE TMP_INST.FPT
    ENDIF
  else
    =MessageBox('Error Installing additional files!',mbxOk,'')
  endif

So,
In some ways, it isn't Quite as good as having a real .ZIP file (you can't extract the files outside of VFP), but in some way's its Better:
    [li]It's easy to include/extract the files from a .APP/.EXE file (so you can distribute only One file)
    [li]It's all within VFP (no ActiveX to register, no MsVCrt support files)
    [li]It's Small (only 53k)
    [li]It's Free!!

Back to Microsoft: Visual FoxPro FAQ Index
Back to Microsoft: Visual FoxPro Forum

My Archive

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close