LZMA SDK 9.20(與C相關)
阿新 • • 發佈:2019-01-05
1.概述
lzma是7-Zip壓縮專案中7z格式的預設與通用壓縮方法,壓縮率高,解壓速度快,需要的記憶體小。目錄中包括ANSI-C/C++/C#/Java原始碼,以及用於windows的編譯好的檔案,以及幾個文件:
- lzma.txt - LZMA SDK描述檔案
- 7zFormat.txt - 7z格式描述檔案
- 7zC.txt - 7z ANSI-C解碼描述檔案
- methods.txt - .7z檔案的壓縮方式
- lzma.exe - 編譯好的檔案,用於windows下檔案到檔案的解壓縮
- 7zr.exe - 編譯好的7-Zip,支援7z/lzma/xz等格式
- history.txt - LZMA SDK的歷史版本
2.C檔案
C資料夾下:
- 7zCrc*.* - CRC code
- Alloc.* - Memory allocation functions
- Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
- LzFind.* - Match finder for LZ (LZMA) encoders
- LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
- LzHash.h - Additional file for LZ match finder
- LzmaDec.* - LZMA decoding
- LzmaEnc.* - LZMA encoding
- LzmaLib.* - LZMA Library for DLL calling
- Types.h - Basic types for another .c files
- Threads.* - The code for multithreading.
Util資料夾下:
- LzmaLib - LZMA庫 (.DLL for Windows)
- Lzma - LZMA使用方法 (檔案到檔案的 LZMA encoder/decoder).
- 7z - 7z ANSI-C 解碼器
3.用法
LZMA <e|d> inputFile outputFile [<switches>...]
e: encode file
d: decode file
<Switches>
-a{N}: 壓縮模式 0 = fast, 1 = normal
default: 1 (normal)
-d{N} : 字典大小 - [0, 30], default: 23 (8MB)
字典大小最大值為 1 GB = 2^30 bytes.
計算方式為 DictionarySize = 2^N bytes.
對於用LZMA壓縮的檔案解壓,字典大小為 D = 2^N 就需要 D bytes 記憶體(RAM)
-fb{N}: fast bytes 數 - [5, 273], default: 128
這個數越大,壓縮比越大,速度也越慢
-lc{N}: literal context bits 數 - [0, 8], default: 3
對於大檔案,通常設定 lc=4.
-lp{N}: literal pos bits 數 - [0, 4], default: 0
當週期為 2^N 時,預留給週期數據.
例如,對於 32-bit (4 bytes),可以設 lp=2.
如果這裡有變化,通常要設定 lc0.
-pb{N}: pos bits 數 - [0, 4], default: 2
當週期為 2^N 時,預留給週期數據.
-mf{MF_ID}: Match Finder. Default: bt4.
hc* 組演算法壓縮比不好, 但當與fast mode(-a0)結合時速度很快.
記憶體需求取決於字典大小(下表中的引數"d").
MF_ID | Memory | Description |
---|---|---|
bt2 | d * 9.5 + 4MB | Binary Tree with 2 bytes hashing. |
bt3 | d * 11.5 + 4MB | Binary Tree with 3 bytes hashing. |
bt4 | d * 11.5 + 4MB | Binary Tree with 4 bytes hashing. |
hc4 | d * 7.5 + 4MB | Hash Chain with 4 bytes hashing. |
-eos: 寫流結束的標記.預設情況LZMA不寫eos標記, 因為LZMA解碼器能從.lzma檔案頭中知道未壓縮的大小
-si: 從stdin中讀資料 (將會寫eos標記).
-so: 把資料寫到stdout
4.LZMA 壓縮檔案格式
Offset | Size | Description |
---|---|---|
0 | 1 | Special LZMA properties (lc,lp, pb in encoded form) |
1 | 4 | Dictionary size (little endian) |
5 | 8 | Uncompressed size (little endian). -1 means unknown size |
13 | Compressed data |
5.使用
要把很多標頭檔案和c檔案加入到專案中:
我的主檔案_7zTest.cpp中的內容是:
// _7zTest.cpp : 定義控制檯應用程式的入口點。
//
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Alloc.h"
#include "7zFile.h"
#include "7zVersion.h"
#include "LzmaDec.h"
#include "LzmaEnc.h"
const char *kCantReadMessage = "Can not read input file";
const char *kCantWriteMessage = "Can not write output file";
const char *kCantAllocateMessage = "Can not allocate memory";
const char *kDataErrorMessage = "Data error";
static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
static void SzFree(void *p, void *address) { p = p; MyFree(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
int PrintError(char *buffer, const char *message)
{
strcat(buffer, "\nError: ");
strcat(buffer, message);
strcat(buffer, "\n");
return 1;
}
int PrintErrorNumber(char *buffer, SRes val)
{
sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
return 1;
}
int PrintUserError(char *buffer)
{
return PrintError(buffer, "Incorrect command");
}
#define IN_BUF_SIZE (1 << 16)
#define OUT_BUF_SIZE (1 << 16)
static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream,
UInt64 unpackSize)
{
int thereIsSize = (unpackSize != (UInt64)(Int64)-1);
Byte inBuf[IN_BUF_SIZE];
Byte outBuf[OUT_BUF_SIZE];
size_t inPos = 0, inSize = 0, outPos = 0;
//Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
LzmaDec_Init(state);
for (;;)
{
if (inPos == inSize)
{
inSize = IN_BUF_SIZE;
RINOK(inStream->Read(inStream, inBuf, &inSize));
inPos = 0;
}
{
SRes res;
SizeT inProcessed = inSize - inPos;
SizeT outProcessed = OUT_BUF_SIZE - outPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
ELzmaStatus status;
if (thereIsSize && outProcessed > unpackSize)
{
outProcessed = (SizeT)unpackSize;
finishMode = LZMA_FINISH_END;
}
res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
inBuf + inPos, &inProcessed, finishMode, &status);
inPos += inProcessed;
outPos += outProcessed;
unpackSize -= outProcessed;
if (outStream)
if (outStream->Write(outStream, outBuf, outPos) != outPos)
return SZ_ERROR_WRITE;
outPos = 0;
if (res != SZ_OK || thereIsSize && unpackSize == 0)
return res;
if (inProcessed == 0 && outProcessed == 0)
{
if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
return SZ_ERROR_DATA;
return res;
}
}
}
}
static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream)
{
UInt64 unpackSize;
int i;
SRes res = 0;
CLzmaDec state;
/* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
unsigned char header[LZMA_PROPS_SIZE + 8];
/* Read and parse header */
RINOK(SeqInStream_Read(inStream, header, sizeof(header)));
unpackSize = 0;
for (i = 0; i < 8; i++)
unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8);
//Allocate CLzmaDec structures (state + dictionary) using LZMA properties
LzmaDec_Construct(&state);
RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc));
res = Decode2(&state, outStream, inStream, unpackSize);
//Free all allocated structures
LzmaDec_Free(&state, &g_Alloc);
return res;
}
static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, char *rs)
{
CLzmaEncHandle enc;
SRes res;
CLzmaEncProps props;
rs = rs;
//Create CLzmaEncHandle object
enc = LzmaEnc_Create(&g_Alloc);
if (enc == 0)
return SZ_ERROR_MEM;
//initialize CLzmaEncProps properties 初始化各壓縮引數
LzmaEncProps_Init(&props);
//Send LZMA properties to LZMA Encoder
res = LzmaEnc_SetProps(enc, &props);
if (res == SZ_OK)
{
//Write encoded properties to header
Byte header[LZMA_PROPS_SIZE + 8];//LZMA properties+Dictionary size(little endian)+Uncompressed size(little endian).
size_t headerSize = LZMA_PROPS_SIZE;
int i;
res = LzmaEnc_WriteProperties(enc, header, &headerSize);//把屬性寫到header
for (i = 0; i < 8; i++)
header[headerSize++] = (Byte)(fileSize >> (8 * i));
if (outStream->Write(outStream, header, headerSize) != headerSize)
res = SZ_ERROR_WRITE;
else
{
if (res == SZ_OK)
//Call encoding function
res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc);
}
}
//Destroy LZMA Encoder Object
LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
return res;
}
int main2(int numArgs, const char *args[], char *rs)
{
CFileSeqInStream inStream; //輸入檔案流
CFileOutStream outStream; //輸出檔案流
char c; //記錄操作
int res;
int encodeMode;
Bool useOutFile = False; //記錄是否自定義輸出檔案
FileSeqInStream_CreateVTable(&inStream); //
File_Construct(&inStream.file); //
FileOutStream_CreateVTable(&outStream);
File_Construct(&outStream.file);
if (numArgs < 2 || numArgs > 3 || strlen(args[0]) != 1)//引數數量不對或第一個引數長度不為1
return PrintUserError(rs);
c = args[0][0];
encodeMode = (c == 'e' || c == 'E');//encodeMode為1表示壓縮
if (!encodeMode && c != 'd' && c != 'D')//encodeMode不為1且不表示解壓,出錯
return PrintUserError(rs);
{
size_t t4 = sizeof(UInt32);
size_t t8 = sizeof(UInt64);
if (t4 != 4 || t8 != 8) //檢查機器位數
return PrintError(rs, "Incorrect UInt32 or UInt64");
}
if (InFile_Open(&inStream.file, args[1]) != 0) //開啟輸入檔案
return PrintError(rs, "Can not open input file");
if (numArgs > 2) //若有輸出檔案引數
{
useOutFile = True;
if (OutFile_Open(&outStream.file, args[2]) != 0)
return PrintError(rs, "Can not open output file");
}
else if (encodeMode) //壓縮模式必須自己定義輸出檔案
PrintUserError(rs);
if (encodeMode)
{
UInt64 fileSize;
File_GetLength(&inStream.file, &fileSize); //獲取檔案長度
res = Encode(&outStream.s, &inStream.s, fileSize, rs);
}
else
{
res = Decode(&outStream.s, useOutFile ? &inStream.s : NULL); //解壓模式
}
if (useOutFile)
File_Close(&outStream.file);
File_Close(&inStream.file);
if (res != SZ_OK)
{
if (res == SZ_ERROR_MEM)
return PrintError(rs, kCantAllocateMessage);
else if (res == SZ_ERROR_DATA)
return PrintError(rs, kDataErrorMessage);
else if (res == SZ_ERROR_WRITE)
return PrintError(rs, kCantWriteMessage);
else if (res == SZ_ERROR_READ)
return PrintError(rs, kCantReadMessage);
return PrintErrorNumber(rs, res);
}
return 0;
}
int MY_CDECL main()//C Declaration
{
char rs[800] = { 0 };
//const char *args[] = {"e", "Z:\\b.xml", "Z:\\bb.7z" };//壓縮
const char *args[] = {"d", "Z:\\bb.7z", "Z:\\b.xml" };//解壓
int numArgs = sizeof(args) / sizeof(args[0]);
int res = main2(numArgs, args, rs);
fputs(rs, stdout);
return res;
}
由lzma920\C\Util\Lzma\LzmaUtil.c修改而來。