1. 程式人生 > >LZMA SDK 9.20(與C相關)

LZMA SDK 9.20(與C相關)

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修改而來。