LOCAL oCompression As LZNT1Compression
oCompression = CREATEOBJECT("LZNT1Compression")
LOCAL cSourceFile, cCompressedFile, cRestoredFile
* Set cSourceFile to a valid path.
* Test on a smaller file first.
cSourceFile = "c:\temp\somefile.txt"
cCompressedFile = JUSTPATH(cSourceFile) + "\" +;
STRTRAN(JUSTFNAME(cSourceFile), ".", "_") +;
".cmp"
cRestoredFile = JUSTPATH(cSourceFile) + "\" +;
JUSTSTEM(cSourceFile) + "_restored." +;
JUSTEXT(m.cSourceFile)
? "Source file:", cSourceFile
? "Compressed file:", cCompressedFile
? "Restored file:", cRestoredFile
IF oCompression.CompressFile(cSourceFile,;
cCompressedFile)
? oCompression.DecompressFile(cCompressedFile,;
cRestoredFile)
ENDIF
* end of main
DEFINE CLASS LZNT1Compression As Custom
#DEFINE COMPRESSION_FORMAT_LZNT1 2
#DEFINE COMPRESSION_ENGINE_STANDARD 0
#DEFINE COMPRESSION_ENGINE_MAXIMUM 0x0100
#DEFINE UNCOMPRESSED_CHUNK_SIZE 4096 && system default
#DEFINE STATUS_SUCCESS 0
#DEFINE STATUS_BUFFER_ALL_ZEROS 0x00000117
#DEFINE STATUS_INVALID_PARAMETER 0xc000000d
#DEFINE STATUS_UNSUPPORTED_COMPRESSION 0xc000025f
#DEFINE STATUS_NOT_SUPPORTED 0xc00000bb
#DEFINE STATUS_BUFFER_TOO_SMALL 0xc0000023
#DEFINE STATUS_BAD_COMPRESSION_BUFFER 0xc0000242
* error code = 35 -- 0x23
PROTECTED WorkSpaceCompress, WorkSpaceDecompress,;
CompressionFormat, CompressionEngine
WorkSpaceCompress = 0x8000
WorkSpaceDecompress = 0x1000
CompressionFormat = COMPRESSION_FORMAT_LZNT1
* choose either STANDARD or MAXIMUM
* lesser time vs. better compression
CompressionEngine = COMPRESSION_ENGINE_STANDARD && _MAXIMUM
PROCEDURE Init
WITH THIS
.declare
.ReadInternalSettings
ENDWITH
FUNCTION CompressFile(cOriginalFile As String,;
cCompressedFile As String) As Boolean
LOCAL cSourceBuffer, cTargetBuffer,;
ex As Exception, lResult
TRY
lResult = .F.
cSourceBuffer = FILETOSTR(m.cOriginalFile)
IF LEN(m.cSourceBuffer) > 0
cTargetBuffer = ""
IF THIS.CompressString(@cSourceBuffer,;
@cTargetBuffer) > 0
STRTOFILE(cTargetBuffer, m.cCompressedFile)
lResult = .T.
ENDIF
ENDIF
CATCH TO ex
= MESSAGEBOX(TRANSFORM(ex.ErrorNo) + ". " +;
ex.Message, 48, "Compression Error!")
ENDTRY
RETURN m.lResult
FUNCTION DecompressFile(cCompressedFile As String,;
cDecompressedFile As String) As Boolean
LOCAL cSourceBuffer, cTargetBuffer,;
ex As Exception, lResult
TRY
lResult = .F.
cSourceBuffer = FILETOSTR(m.cCompressedFile)
IF LEN(m.cSourceBuffer) > 0
cTargetBuffer = ""
IF THIS.DecompressString(@cSourceBuffer,;
@cTargetBuffer) > 0
STRTOFILE(cTargetBuffer, m.cDecompressedFile)
lResult = .T.
ENDIF
ENDIF
CATCH TO ex
= MESSAGEBOX(TRANSFORM(ex.ErrorNo) + ". " +;
ex.Message, 48, "Decompression Error!")
ENDTRY
RETURN m.lResult
FUNCTION CompressString(cOriginalString As String,;
cCompressedString As String) As Number
LOCAL oInputBuffer As PChar, oOutputBuffer As PChar,;
oWorkSpace As PChar, nCompressedSize,;
nFinalCompressedSize, nStatus
oInputBuffer = CREATEOBJECT("PChar", m.cOriginalString)
oWorkSpace = CREATEOBJECT("PChar",;
REPLICATE(CHR(0), THIS.WorkSpaceCompress))
* as a precaution, set the size of the output buffer
* some larger than the original string
nCompressedSize = MAX(4096, LEN(m.cOriginalString) * 1.3)
DO WHILE .T.
nFinalCompressedSize = 0
oOutputBuffer = CREATEOBJECT("PChar",;
REPLICATE(CHR(0), m.nCompressedSize))
nStatus = RtlCompressBuffer(;
BITOR(THIS.CompressionFormat, THIS.CompressionEngine),;
oInputBuffer.GetAddr(),;
oInputBuffer.GetAllocSize(),;
oOutputBuffer.GetAddr(),;
oOutputBuffer.GetAllocSize(),;
UNCOMPRESSED_CHUNK_SIZE,;
@nFinalCompressedSize,;
oWorkSpace.GetAddr();
)
DO CASE
CASE m.nStatus = STATUS_SUCCESS
EXIT
CASE BITAND(m.nStatus, 0xffff) =;
BITAND(STATUS_BUFFER_TOO_SMALL, 0xffff)
* This may happen with a file to be compressed
* being already in compressed format (JPEG, PDF, ZIP).
* Increase buffer size and loop.
oOutputBuffer = NULL
nCompressedSize = nCompressedSize +;
LEN(m.cOriginalString)
OTHERWISE
= MESSAGEBOX("API error code: " +;
TRANSFORM(m.nStatus), 48,;
"Compression Error!")
cCompressedString = ""
RETURN 0
ENDCASE
ENDDO
cCompressedString = SUBSTR(oOutputBuffer.GetValue(),;
1, nFinalCompressedSize)
RETURN nFinalCompressedSize
FUNCTION DecompressString(cCompressedString As String,;
cDecompressedString As String) As Number
LOCAL oUncompressedBuffer As PChar, oCompressedBuffer As PChar,;
nUncompressedSize, nFinalUncompressedSize, nStatus
oCompressedBuffer = CREATEOBJECT("PChar", m.cCompressedString)
nUncompressedSize = LEN(m.cCompressedString) * 2
DO WHILE .T.
oUncompressedBuffer = CREATEOBJECT("PChar",;
REPLICATE(CHR(0), nUncompressedSize))
nFinalUncompressedSize = 0
nStatus = RtlDecompressBuffer(;
THIS.CompressionFormat,;
oUncompressedBuffer.GetAddr(),;
oUncompressedBuffer.GetAllocSize(),;
oCompressedBuffer.GetAddr(),;
oCompressedBuffer.GetAllocSize(),;
@nFinalUncompressedSize;
)
DO CASE
CASE nStatus = STATUS_SUCCESS
EXIT
CASE BITAND(nStatus, 0xffff) =;
BITAND(STATUS_BAD_COMPRESSION_BUFFER, 0xffff)
* if a larger buffer required
* increase buffer size and loop
oUncompressedBuffer = NULL
nUncompressedSize = nUncompressedSize +;
LEN(m.cCompressedString)
OTHERWISE
* some other error
= MESSAGEBOX("API error code: " +;
TRANSFORM(m.nStatus), 48,;
"Decompression Error!")
RETURN 0
ENDCASE
ENDDO
cDecompressedString = SUBSTR(oUncompressedBuffer.GetValue(),;
1, nFinalUncompressedSize)
RETURN m.nFinalUncompressedSize
PROTECTED FUNCTION ReadInternalSettings()
LOCAL nFlag, nWorkSpaceCompress, nWorkSpaceDecompress
WITH THIS
nFlag = BITOR(.CompressionFormat, .CompressionEngine)
STORE 0 TO nWorkSpaceCompress, nWorkSpaceDecompress
IF RtlGetCompressionWorkSpaceSize( m.nFlag,;
@nWorkSpaceCompress,;
@nWorkSpaceDecompress ) <> STATUS_SUCCESS
RETURN .F.
ENDIF
.WorkSpaceCompress = m.nWorkSpaceCompress
.WorkSpaceDecompress = m.nWorkSpaceDecompress
ENDWITH
PROTECTED PROCEDURE declare
DECLARE INTEGER GetLastError IN kernel32
DECLARE INTEGER RtlGetCompressionWorkSpaceSize IN ntdll;
SHORT CompressionFormatAndEngine,;
LONG @CompressBufferWorkSpaceSize,;
LONG @CompressFragmentWorkSpaceSize
DECLARE INTEGER RtlCompressBuffer IN ntdll;
SHORT CompressionFormatAndEngine,;
INTEGER UncompressedBuffer, LONG UncompressedBufferSize,;
INTEGER CompressedBuffer, LONG CompressedBufferSize,;
LONG UncompressedChunkSize,;
LONG @FinalCompressedSize, INTEGER WorkSpace
DECLARE INTEGER RtlDecompressBuffer IN ntdll;
SHORT CompressionFormat,;
INTEGER UncompressedBuffer, LONG UncompressedBufferSize,;
INTEGER CompressedBuffer, LONG CompressedBufferSize,;
LONG @FinalUncompressedSize
ENDDEFINE
DEFINE CLASS PChar As Session
PROTECTED hMem
PROCEDURE Init(cString As String)
THIS.hMem = 0
THIS.setValue(cString)
PROCEDURE Destroy
THIS.ReleaseString
FUNCTION GetAddr
RETURN THIS.hMem
FUNCTION GetValue
LOCAL nBufsize, cBuffer
nBufsize = THIS.GetAllocSize()
cBuffer = REPLICATE(CHR(0), m.nBufsize)
IF THIS.hMem <> 0
DECLARE RtlMoveMemory IN kernel32 As MemToStr;
STRING @, INTEGER, INTEGER
= MemToStr(@cBuffer, THIS.hMem, nBufsize)
ENDIF
RETURN m.cBuffer
FUNCTION GetAllocSize
DECLARE INTEGER GlobalSize IN kernel32 INTEGER hMem
RETURN Iif(THIS.hMem=0, 0, GlobalSize(THIS.hMem))
PROCEDURE SetValue(cString)
#DEFINE GMEM_FIXED 0
#DEFINE GMEM_MOVEABLE 2
#DEFINE GMEM_ZEROINIT 0x0040
THIS.ReleaseString
DECLARE INTEGER GlobalAlloc IN kernel32;
INTEGER, INTEGER
DECLARE RtlMoveMemory IN kernel32 As StrToMem;
INTEGER, STRING @, INTEGER
LOCAL nBufsize
nBufsize = LEN(cString)
THIS.hMem = GlobalAlloc(0x0040, nBufsize)
IF THIS.hMem <> 0
= StrToMem(THIS.hMem, @cString, nBufsize)
ENDIF
PROCEDURE ReleaseString
IF THIS.hMem <> 0
DECLARE INTEGER GlobalFree IN kernel32 INTEGER
= GlobalFree (THIS.hMem)
THIS.hMem = 0
ENDIF
ENDDEFINE
|