7zip LZMA compression

Share your advanced PureBasic knowledge/code with the community.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

7zip LZMA compression

Post by Mistrel »

I wanted to use LZMA compression in my project so I compiled it from source using the C interface and wrapped up some functions for it in PureBasic. There is a DLL available on SourceForge but it uses a nonstandard COM interface. Maybe srod can figure out what to do with that. :P

The library was compiled with Visual C++ 2010 Beta 2 with maximum optimizations.
http://3dfolio.com/files/7z.zip

Code: Select all

#LZMA_PROPS_SIZE=5
#LZMA_SIZE_OFFSET=#LZMA_PROPS_SIZE
#LZMA_HEADER_SIZE=#LZMA_SIZE_OFFSET+8

#SZ_OK=0
#SZ_ERROR_DATA=1
#SZ_ERROR_MEM=2
#SZ_ERROR_CRC=3
#SZ_ERROR_UNSUPPORTED=4
#SZ_ERROR_PARAM=5
#SZ_ERROR_INPUT_EOF=6
#SZ_ERROR_OUTPUT_EOF=7
#SZ_ERROR_READ=8
#SZ_ERROR_WRITE=9
#SZ_ERROR_PROGRESS=10
#SZ_ERROR_FAIL=11
#SZ_ERROR_THREAD=12
#SZ_ERROR_ARCHIVE=16
#SZ_ERROR_NO_ARCHIVE=17

Procedure _LzmaCompress(*Dest, *DestLen, *Src, SrcLen, *OutProps, *OutPropsSize, Level=5, DictSize=((1<<24)&$FFFFFFFF), Lc=3, Lp=0, Pb=2, Fb=32, NumThreads=2)
  Protected Lib, Ptr, Result=#SZ_OK
  
  Lib=OpenLibrary(#PB_Any,"7z.dll")
  Ptr=GetFunction(Lib,"LzmaCompress")
  
  If Ptr
    Result=CallFunctionFast(Ptr,*Dest,*DestLen,*Src,SrcLen,*OutProps,*OutPropsSize,Level,DictSize,Lc,Lp,Pb,Fb,NumThreads)
  EndIf
  
  CloseLibrary(Lib)
  
  ProcedureReturn Result
EndProcedure

Procedure _LzmaUncompress(*Dest, *DestLen, *Src, *SrcLen, *Props, PropsSize)
  Protected Lib, Ptr, Result=#SZ_OK
  
  Lib=OpenLibrary(#PB_Any,"7z.dll")
  Ptr=GetFunction(Lib,"LzmaUncompress")
  
  If Ptr
    Result=CallFunctionFast(Ptr,*Dest,*DestLen,*Src,*SrcLen,*Props,PropsSize)
  EndIf
  
  CloseLibrary(Lib)
  
  ProcedureReturn Result
EndProcedure

Procedure LzmaCompressFile(SourceFile.s, DestinationFile.s, Level=5, DictSize=((1<<24)&$FFFFFFFF))
  Protected FileID, SourceSize, *SourceMem, DestSize, *DestMem, *OutProps, OutPropsSize, Result
  
  FileID=ReadFile(#PB_Any,SourceFile.s)
  If Not FileID
    ProcedureReturn #SZ_ERROR_READ
  EndIf
  SourceSize=Lof(FileID)
  If SourceSize=0
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_READ
  EndIf
  
  ;/ Allocate memory for the source file to be read into memory
  *SourceMem=AllocateMemory(SourceSize)
  If Not *SourceMem
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
  
  ReadData(FileID,*SourceMem,SourceSize)
  CloseFile(FileID)
  
  ;/ Allocate 105% of file size for destination buffer + 64 kilobytes
  DestSize=SourceSize/20*21+(1<<16)
  *DestMem=AllocateMemory(DestSize)
  If Not *DestMem
    FreeMemory(*SourceMem)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
  
  ;/ Allocate memory for the properties section
  *OutProps=AllocateMemory(#LZMA_PROPS_SIZE)
  If Not *OutProps
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
  
  OutPropsSize=#LZMA_PROPS_SIZE
  Result=_LzmaCompress(*DestMem,@DestSize,*SourceMem,SourceSize,*OutProps,@outPropsSize,Level,DictSize)
  If Not Result=#SZ_OK Or Not DestSize Or Not OutPropsSize
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    FreeMemory(*OutProps)
    ProcedureReturn Result
  EndIf
  
  FileID=CreateFile(#PB_Any,DestinationFile.s)
  If Not FileID
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    FreeMemory(*OutProps)
    ProcedureReturn #SZ_ERROR_WRITE
  EndIf
  
  WriteData(FileID,*OutProps,#LZMA_PROPS_SIZE)
  WriteQuad(FileID,SourceSize)
  WriteData(FileID,*DestMem,DestSize)
  CloseFile(FileID)
  
  FreeMemory(*SourceMem)
  FreeMemory(*DestMem)
  FreeMemory(*OutProps)
  
  ProcedureReturn Result
EndProcedure

Procedure LzmaUncompressFile(SourceFile.s, DestinationFile.s)
  Protected FileID, SourceSize, *OutProps, DictSize, *SourceMem, *DestMem, DestSize, Result
  
  FileID=ReadFile(#PB_Any,SourceFile.s)
  If Not FileID
    ProcedureReturn #SZ_ERROR_READ
  EndIf
  SourceSize=Lof(FileID)
  If SourceSize=0
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_READ
  EndIf
  
  ;/ Read header information
  *OutProps=AllocateMemory(#LZMA_PROPS_SIZE)
  ReadData(FileID,*OutProps,#LZMA_PROPS_SIZE)
  DestSize=ReadQuad(FileID)
  DictSize=PeekL(*OutProps+1)
  
  ;/ Read compressed data to memory
  SourceSize=Lof(FileID)-Loc(FileID)
  *SourceMem=AllocateMemory(SourceSize)
  If Not *SourceMem
    FreeMemory(*OutProps)
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
  
  ReadData(FileID,*SourceMem,SourceSize)
  CloseFile(FileID)
  
  ;/ Allocate memory to hold the uncompressed data
  *DestMem=AllocateMemory(DestSize)
  If Not *DestMem
    FreeMemory(*OutProps)
    FreeMemory(*SourceMem)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
  
  Result=_LzmaUncompress(*DestMem,@DestSize,*SourceMem,@SourceSize,*OutProps,#LZMA_PROPS_SIZE)
  If Not Result=#SZ_OK Or Not DestSize Or Not SourceSize
    FreeMemory(*OutProps)
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    ProcedureReturn Result
  EndIf
  
  FileID=CreateFile(#PB_Any,DestinationFile.s)
  If Not FileID
    FreeMemory(*OutProps)
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    ProcedureReturn #SZ_ERROR_WRITE
  EndIf
  WriteData(FileID,*DestMem,DestSize)
  CloseFile(FileID)
  
  FreeMemory(*OutProps)
  FreeMemory(*SourceMem)
  FreeMemory(*DestMem)
  
  ProcedureReturn Result
EndProcedure
Here is a simple test:

Code: Select all

Procedure CompressionTest(FileName.s, Level)
  Protected Start
  
  Start=ElapsedMilliseconds()
  If Not LzmaCompressFile(FileName.s,"compressed",Level,((1<<24)&$FFFFFFFF))=#SZ_OK
    Debug "Error compressing"
    End
  EndIf
  Debug "Compression time "+Str(ElapsedMilliseconds()-Start)
  
  Start=ElapsedMilliseconds()
  If Not LzmaUnCompressFile("compressed","uncompressed")=#SZ_OK
    Debug "Error decompressing"
    End
  EndIf
  Debug "Decompression time "+Str(ElapsedMilliseconds()-Start)
  Debug "Compressed size "+StrF(FileSize("compressed")/FileSize("uncompressed")*100,2)
EndProcedure
The results from my test are:

Code: Select all

Level 1
Compression time 1935
Decompression time 234
Compressed ratio 18.72%

Level 5
Compression time 4431
Decompression time 234
Compressed ratio 17.30%

Level 9
Compression time 4555
Decompression time 249
Compressed ratio 17.30%
Before compression: 6.7 MB
After compression: 1.16 MB

I was also considering bzip2 but it couldn't even manage to compress the same file to under 2 MB. LZMA is supposed to be faster at decompressing as well. Though it's much slower at compression.
Last edited by Mistrel on Fri Feb 19, 2010 12:56 am, edited 8 times in total.
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: 7zip LZMA compression

Post by Mistrel »

Additional information from the LzmaLib header:

Code: Select all

/*
RAM requirements for LZMA:
  for compression:   (dictSize * 11.5 + 6 MB) + state_size
  for decompression: dictSize + state_size
    state_size = (4 + (1.5 << (lc + lp))) KB
    by default (lc=3, lp=0), state_size = 16 KB.

LZMA properties (5 bytes) format
    Offset Size  Description
      0     1    lc, lp and pb in encoded form.
      1     4    dictSize (little endian).
*/

/*
LzmaCompress
------------

outPropsSize -
     In:  the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
     Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.

  LZMA Encoder will use defult values for any parameter, if it is
  -1  for any from: level, loc, lp, pb, fb, numThreads
   0  for dictSize
  
level - compression level: 0 <= level <= 9;

  level dictSize algo  fb
    0:    16 KB   0    32
    1:    64 KB   0    32
    2:   256 KB   0    32
    3:     1 MB   0    32
    4:     4 MB   0    32
    5:    16 MB   1    32
    6:    32 MB   1    32
    7+:   64 MB   1    64
 
  The default value for "level" is 5.

  algo = 0 means fast method
  algo = 1 means normal method

dictSize - The dictionary size in bytes. The maximum value is
        128 MB = (1 << 27) bytes for 32-bit version
          1 GB = (1 << 30) bytes for 64-bit version
     The default value is 16 MB = (1 << 24) bytes.
     It's recommended to use the dictionary that is larger than 4 KB and
     that can be calculated as (1 << N) or (3 << N) sizes.

lc - The number of literal context bits (high bits of previous literal).
     It can be in the range from 0 to 8. The default value is 3.
     Sometimes lc=4 gives the gain for big files.

lp - The number of literal pos bits (low bits of current position for literals).
     It can be in the range from 0 to 4. The default value is 0.
     The lp switch is intended for periodical data when the period is equal to 2^lp.
     For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
     better to set lc=0, if you change lp switch.

pb - The number of pos bits (low bits of current position).
     It can be in the range from 0 to 4. The default value is 2.
     The pb switch is intended for periodical data when the period is equal 2^pb.

fb - Word size (the number of fast bytes).
     It can be in the range from 5 to 273. The default value is 32.
     Usually, a big number gives a little bit better compression ratio and
     slower compression process.

numThreads - The number of thereads. 1 or 2. The default value is 2.
     Fast mode (algo = 0) can use only 1 thread.

Out:
  destLen  - processed output size
Returns:
  SZ_OK               - OK
  SZ_ERROR_MEM        - Memory allocation error
  SZ_ERROR_PARAM      - Incorrect paramater
  SZ_ERROR_OUTPUT_EOF - output buffer overflow
  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
*/
Thorium
Addict
Addict
Posts: 1305
Joined: Sat Aug 15, 2009 6:59 pm

Re: 7zip LZMA compression

Post by Thorium »

Thanks, very usefull.
Can you compile a 64bit version of the lib?
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: 7zip LZMA compression

Post by Mistrel »

Uploaded to the same file I liked above. I tested it with PB 4.40 and it worked like a charm. I didn't have to change a single line of code. :)

I fixed a small bug in the test example I provided. It should work great now.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Re: 7zip LZMA compression

Post by Joakim Christiansen »

Nice, may come in handy. :D
I like logic, hence I dislike humans but love computers.
User avatar
Rings
Moderator
Moderator
Posts: 1435
Joined: Sat Apr 26, 2003 1:11 am

Re: 7zip LZMA compression

Post by Rings »

okay, i did a small enhancment,
- CompilerIf for the 2 versions of the dll.
- time measurement only for the compress/uncompress,
coz file-operations costs also time here

Code: Select all

; /*
; RAM requirements For LZMA:
;   For compression:   (dictSize * 11.5 + 6 MB) + state_size
;   For decompression: dictSize + state_size
;     state_size = (4 + (1.5 << (lc + lp))) KB
;     by Default (lc=3, lp=0), state_size = 16 KB.
; 
; LZMA properties (5 bytes) format
;     Offset Size  Description
;       0     1    lc, lp And pb in encoded form.
;       1     4    dictSize (little endian).
; */
; 
; /*
; LzmaCompress
; ------------
; 
; outPropsSize -
;      In:  the pointer To the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
;      Out: the pointer To the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
; 
;   LZMA Encoder will use defult values For any parameter, If it is
;   -1  For any from: level, loc, lp, pb, fb, numThreads
;    0  For dictSize
;  
; level - compression level: 0 <= level <= 9;
; 
;   level dictSize algo  fb
;     0:    16 KB   0    32
;     1:    64 KB   0    32
;     2:   256 KB   0    32
;     3:     1 MB   0    32
;     4:     4 MB   0    32
;     5:    16 MB   1    32
;     6:    32 MB   1    32
;     7+:   64 MB   1    64
; 
;   The Default value For "level" is 5.
; 
;   algo = 0 means fast method
;   algo = 1 means normal method
; 
; dictSize - The dictionary size in bytes. The maximum value is
;         128 MB = (1 << 27) bytes For 32-bit version
;           1 GB = (1 << 30) bytes For 64-bit version
;      The Default value is 16 MB = (1 << 24) bytes.
;      It's recommended to use the dictionary that is larger than 4 KB and
;      that can be calculated As (1 << N) Or (3 << N) sizes.
; 
; lc - The number of literal context bits (high bits of previous literal).
;      It can be in the range from 0 To 8. The Default value is 3.
;      Sometimes lc=4 gives the gain For big files.
; 
; lp - The number of literal pos bits (low bits of current position For literals).
;      It can be in the range from 0 To 4. The Default value is 0.
;      The lp switch is intended For periodical Data when the period is equal To 2^lp.
;      For example, For 32-bit (4 bytes) periodical Data you can use lp=2. Often it's
;      better To set lc=0, If you change lp switch.
; 
; pb - The number of pos bits (low bits of current position).
;      It can be in the range from 0 To 4. The Default value is 2.
;      The pb switch is intended For periodical Data when the period is equal 2^pb.
; 
; fb - Word size (the number of fast bytes).
;      It can be in the range from 5 To 273. The Default value is 32.
;      Usually, a big number gives a little bit better compression ratio And
;      slower compression process.
; 
; numThreads - The number of thereads. 1 Or 2. The Default value is 2.
;      Fast mode (algo = 0) can use only 1 thread.
; 
; Out:
;   destLen  - processed output size
; Returns:
;   SZ_OK               - OK
;   SZ_ERROR_MEM        - Memory allocation error
;   SZ_ERROR_PARAM      - Incorrect paramater
;   SZ_ERROR_OUTPUT_EOF - output buffer overflow
;   SZ_ERROR_THREAD     - errors in multithreading functions (only For Mt version)
; */
; 

#LZMA_PROPS_SIZE=5
#LZMA_SIZE_OFFSET=#LZMA_PROPS_SIZE
#LZMA_HEADER_SIZE=#LZMA_SIZE_OFFSET+8

#SZ_OK=0
#SZ_ERROR_DATA=1
#SZ_ERROR_MEM=2
#SZ_ERROR_CRC=3
#SZ_ERROR_UNSUPPORTED=4
#SZ_ERROR_PARAM=5
#SZ_ERROR_INPUT_EOF=6
#SZ_ERROR_OUTPUT_EOF=7
#SZ_ERROR_READ=8
#SZ_ERROR_WRITE=9
#SZ_ERROR_PROGRESS=10
#SZ_ERROR_FAIL=11
#SZ_ERROR_THREAD=12
#SZ_ERROR_ARCHIVE=16
#SZ_ERROR_NO_ARCHIVE=17

Procedure _LzmaCompress(*Dest, *DestLen, *Src, SrcLen, *OutProps, *OutPropsSize, Level=5, DictSize=((1<<24)&$FFFFFFFF), Lc=3, Lp=0, Pb=2, Fb=32, NumThreads=2)
  Protected Lib, Ptr, Result=#SZ_OK
  CompilerIf #PB_Compiler_Processor =#PB_Processor_x64 
   Lib=OpenLibrary(#PB_Any,"7z-64.dll")
  CompilerElse
   Lib=OpenLibrary(#PB_Any,"7z-32.dll")
  CompilerEndIf
  
  Ptr=GetFunction(Lib,"LzmaCompress")
 
  If Ptr
    Result=CallFunctionFast(Ptr,*Dest,*DestLen,*Src,SrcLen,*OutProps,*OutPropsSize,Level,DictSize,Lc,Lp,Pb,Fb,NumThreads)
  EndIf
 
  CloseLibrary(Lib)
 
  ProcedureReturn Result
EndProcedure

Procedure _LzmaUncompress(*Dest, *DestLen, *Src, *SrcLen, *Props, PropsSize)
  Protected Lib, Ptr, Result=#SZ_OK
 
 CompilerIf #PB_Compiler_Processor =#PB_Processor_x64 
   Lib=OpenLibrary(#PB_Any,"7z-64.dll")
  CompilerElse
   Lib=OpenLibrary(#PB_Any,"7z-32.dll")
  CompilerEndIf
  
  Ptr=GetFunction(Lib,"LzmaUncompress")
 
  If Ptr
    Result=CallFunctionFast(Ptr,*Dest,*DestLen,*Src,*SrcLen,*Props,PropsSize)
  EndIf
 
  CloseLibrary(Lib)
 
  ProcedureReturn Result
EndProcedure

Procedure LzmaCompressFile(SourceFile.s, DestinationFile.s, Level=5, DictSize=((1<<24)&$FFFFFFFF))
  Protected FileID, SourceSize, *SourceMem, DestSize, *DestMem, *OutProps, OutPropsSize, Result
 
  FileID=ReadFile(#PB_Any,SourceFile.s)
  If Not FileID
    ProcedureReturn #SZ_ERROR_READ
  EndIf
  SourceSize=Lof(FileID)
  If SourceSize=0
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_READ
  EndIf
 
  ;/ Allocate memory for the source file to be read into memory
  *SourceMem=AllocateMemory(SourceSize)
  If Not *SourceMem
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
 
  ReadData(FileID,*SourceMem,SourceSize)
  CloseFile(FileID)
 
  ;/ Allocate 105% of file size for destination buffer + 16 bytes
  DestSize=SourceSize/20*21+(1<<16)
  *DestMem=AllocateMemory(DestSize)
  If Not *DestMem
    FreeMemory(*SourceMem)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
 
  ;/ Allocate memory for the properties section
  *OutProps=AllocateMemory(#LZMA_PROPS_SIZE)
  If Not *OutProps
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
 
  OutPropsSize=#LZMA_PROPS_SIZE
  Start=ElapsedMilliseconds()
  Debug start
  Result=_LzmaCompress(*DestMem,@DestSize,*SourceMem,SourceSize,*OutProps,@outPropsSize,Level,DictSize)
  Stop=ElapsedMilliseconds()
  Debug Stop
  Debug "Compression time "+Str(Stop-Start)
  
  If Not Result=#SZ_OK Or Not DestSize Or Not OutPropsSize
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    FreeMemory(*OutProps)
    ProcedureReturn Result
  EndIf
 
  FileID=CreateFile(#PB_Any,DestinationFile.s)
  If Not FileID
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    FreeMemory(*OutProps)
    ProcedureReturn #SZ_ERROR_WRITE
  EndIf
 
  WriteData(FileID,*OutProps,#LZMA_PROPS_SIZE)
  WriteQuad(FileID,SourceSize)
  WriteData(FileID,*DestMem,DestSize)
  CloseFile(FileID)
 
  FreeMemory(*SourceMem)
  FreeMemory(*DestMem)
  FreeMemory(*OutProps)
 
  ProcedureReturn Result
EndProcedure

Procedure LzmaUncompressFile(SourceFile.s, DestinationFile.s)
  Protected FileID, SourceSize, *OutProps, DictSize, *SourceMem, *DestMem, DestSize, Result
 
  FileID=ReadFile(#PB_Any,SourceFile.s)
  If Not FileID
    ProcedureReturn #SZ_ERROR_READ
  EndIf
  SourceSize=Lof(FileID)
  If SourceSize=0
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_READ
  EndIf
 
  ;/ Read header information
  *OutProps=AllocateMemory(#LZMA_PROPS_SIZE)
  ReadData(FileID,*OutProps,#LZMA_PROPS_SIZE)
  DestSize=ReadQuad(FileID)
  DictSize=PeekL(*OutProps+1)
 
  ;/ Read compressed data to memory
  SourceSize=Lof(FileID)-Loc(FileID)
  *SourceMem=AllocateMemory(SourceSize)
  If Not *SourceMem
    FreeMemory(*OutProps)
    CloseFile(FileID)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
 
  ReadData(FileID,*SourceMem,SourceSize)
  CloseFile(FileID)
 
  ;/ Allocate memory to hold the uncompressed data
  *DestMem=AllocateMemory(DestSize)
  If Not *DestMem
    FreeMemory(*OutProps)
    FreeMemory(*SourceMem)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
 
  Start=ElapsedMilliseconds()
  Result=_LzmaUncompress(*DestMem,@DestSize,*SourceMem,@SourceSize,*OutProps,#LZMA_PROPS_SIZE)
  Debug "UnCompression time "+Str(ElapsedMilliseconds()-Start)
  If Not Result=#SZ_OK Or Not DestSize Or Not SourceSize
    FreeMemory(*OutProps)
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    ProcedureReturn Result
  EndIf
 
  FileID=CreateFile(#PB_Any,DestinationFile.s)
  If Not FileID
    FreeMemory(*OutProps)
    FreeMemory(*SourceMem)
    FreeMemory(*DestMem)
    ProcedureReturn #SZ_ERROR_WRITE
  EndIf
  WriteData(FileID,*DestMem,DestSize)
  CloseFile(FileID)
 
  FreeMemory(*OutProps)
  FreeMemory(*SourceMem)
  FreeMemory(*DestMem)
 
  ProcedureReturn Result
EndProcedure

Procedure CompressionTest(FileName.s, Level)
  Protected Start
 
  ;Start=ElapsedMilliseconds()
  If Not LzmaCompressFile(FileName.s,"compressed",Level,((1<<24)&$FFFFFFFF))=#SZ_OK
    Debug "Error compressing"
    End
  EndIf
  ;Debug "Compression time "+Str(ElapsedMilliseconds()-Start)
 
  ;Start=ElapsedMilliseconds()
  If Not LzmaUnCompressFile("compressed","uncompressed")=#SZ_OK
    Debug "Error decompressing"
    End
  EndIf
  ;Debug "Decompression time "+Str(ElapsedMilliseconds()-Start)
  Debug "Compressed size "+StrF(FileSize("compressed")/FileSize("uncompressed")*100,2)
EndProcedure

CompressionTest ("d:\screenshot.bmp",1)

SPAMINATOR NR.1
javabean
User
User
Posts: 60
Joined: Sat Nov 08, 2003 10:29 am
Location: Austria

Re: 7zip LZMA compression

Post by javabean »

Well done, Mistrel!
I'm currently working on a project that needs LZMA compression too. But actually I need a static library (.lib) for that. The last few days I have been playing around with the original plain C Source (LZMA SDK) to get it compiled into a static lib (with PellesC). But so far I haven't got it - not even a dll (I'm not really a C/C++ guy ;-) ). -Any hints on how I could get it compiled?
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: 7zip LZMA compression

Post by Mistrel »

Here is a synopsis of how I built the dlls and static libraries from the SDK. I used Visual C++ from the command line to do it so your compiler linker options are probably different.

The trick is that it requires support for multithreading. That means compiling each object with /MT and linking to the multithreaded version of the C runtime library (libcmt.lib vs libc.lib).

There may be a definition you can switch on to disable multithreading if you can't get it to link.

Code: Select all

Project sources:
7zBuf.c 7zCrcOpt.c 7zIn.c Bcj2.c BraIA64.c LzFind.c Lzma2Enc.c LzmaDec.c MtCoder.c Xz.c XzEnc.c 7zBuf2.c 7zDec.c 7zStream.c Bra.c CpuArch.c LzFindMt.c Lzma86Dec.c LzmaEnc.c Sha256.c XzCrc64.c XzIn.c 7zCrc.c 7zFile.c Alloc.c Bra86.c Delta.c Lzma2Dec.c Lzma86Enc.c LzmaLib.c Threads.c XzDec.c

Include this when compiling to dll:
LzmaLibExports.c

Sources paths:
lzma/9.10/C; lzma/9.10/C/Util/LzmaLib

Includes:
lzma/9.10/C

Compile flags (optimizations + multithreading)
CFLAGS=/Ox /O2 /MT

When compiling to a dll:
LIBRARIES=libcmt.lib
LFLAGS=/NODEFAULTLIB:libc.lib

After compiling a static library this is what you will need to link to it:
LIBRARIES=libcmt.lib libcpmt.lib
LFLAGS=/NODEFAULTLIB:libc.lib libcp.lib
javabean
User
User
Posts: 60
Joined: Sat Nov 08, 2003 10:29 am
Location: Austria

Re: 7zip LZMA compression

Post by javabean »

Thanks a lot Mistrel!
I'll give it a try...
javabean
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: 7zip LZMA compression

Post by luis »

Hi Mistrel, I have a question:

Code: Select all

;/ Allocate 105% of file size for destination buffer + 16 bytes
  DestSize=SourceSize/20*21+(1<<16)
  *DestMem=AllocateMemory(DestSize)
  If Not *DestMem
    FreeMemory(*SourceMem)
    ProcedureReturn #SZ_ERROR_MEM
  EndIf
How do you know a 105% of the source size (+ 16 bytes) will be enough ? The data can always be inflated by an unknown amount if not compressible... or not ? Maybe I'm missing something. Probably I should check the LZMA docs I know !

Anyway 1<<16 is 64KB (not 16 bytes) ... I'm a little confused.

Thanks.
"Have you tried turning it off and on again ?"
A little PureBasic review
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: 7zip LZMA compression

Post by Mistrel »

luis wrote:How do you know a 105% of the source size (+ 16 bytes) will be enough ? The data can always be inflated by an unknown amount if not compressible... or not ? Maybe I'm missing something. Probably I should check the LZMA docs I know !

Anyway 1<<16 is 64KB (not 16 bytes) ... I'm a little confused.
It doesn't matter if it's too small because the *DestLen parameter is supposed to prevent overwriting beyond the memory bounds. If it fails I believe the error returned would be #SZ_ERROR_OUTPUT_EOF with a *DestLen result of 0.

And yes, it's 64KB. I got it wrong. :)
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: 7zip LZMA compression

Post by luis »

OK, I see, thank you ! :P
"Have you tried turning it off and on again ?"
A little PureBasic review
jamba
Enthusiast
Enthusiast
Posts: 144
Joined: Fri Jan 15, 2010 2:03 pm
Location: Triad, NC
Contact:

Re: 7zip LZMA compression

Post by jamba »

awesome, I love 7zip!

I may integrate this into my project, thanks!

:D
-Jon

Fedora user
But I work with Win7
Mistrel
Addict
Addict
Posts: 3415
Joined: Sat Jun 30, 2007 8:04 pm

Re: 7zip LZMA compression

Post by Mistrel »

The resulting file doesn't include the 7zip headers. It's just the lzma compression, just so you know.
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: 7zip LZMA compression

Post by luis »

I made a version slightly different and it use a .lib instead of a .dll

*REMOVED*

Updated in its own thread here: http://www.purebasic.fr/english/viewtop ... 17&start=0
Last edited by luis on Mon Feb 22, 2010 9:30 pm, edited 3 times in total.
"Have you tried turning it off and on again ?"
A little PureBasic review
Post Reply