如何在C++中使用LZMA SDK

How to use LZMA SDK in C++?

本文关键字:LZMA SDK C++      更新时间:2023-10-16

我在应用程序中使用LZMA SDK时遇到困难。

我想创建一种单文件压缩工具。我不需要任何目录支持,只需要LZMA2流。但我不知道LZMA SDK是如何用于此。

有人能给我一个关于LZMA SDK如何在C++下使用的小例子吗?

我认为这是一个使用LZMA SDK的小例子。

/* LzmaUtil.c -- Test application for LZMA compression  
2008-08-05  
Igor Pavlov  
public domain */   
#define _CRT_SECURE_NO_WARNINGS   
#include <stdio.h>   
#include <stdlib.h>   
#include <string.h>   
#include "../LzmaDec.h"   
#include "../LzmaEnc.h"   
#include "../Alloc.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 };   
#define kInBufferSize (1 << 15)   
#define kOutBufferSize (1 << 15)   
unsigned char g_InBuffer[kInBufferSize];   
unsigned char g_OutBuffer[kOutBufferSize];   
size_t MyReadFile(FILE *file, void *data, size_t size)   
  { return fread(data, 1, size, file); }   
int MyReadFileAndCheck(FILE *file, void *data, size_t size)   
  { return (MyReadFile(file, data, size) == size); }   
size_t MyWriteFile(FILE *file, const void *data, size_t size)   
{   
  if (size == 0)   
    return 0;   
  return fwrite(data, 1, size, file);   
}   
int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)   
  { return (MyWriteFile(file, data, size) == size); }   
long MyGetFileLength(FILE *file)   
{   
  long length;   
  fseek(file, 0, SEEK_END);   
  length = ftell(file);   
  fseek(file, 0, SEEK_SET);   
  return length;   
}   
void PrintHelp(char *buffer)   
{   
  strcat(buffer, "nLZMA Utility 4.58 Copyright (c) 1999-2008 Igor Pavlov  2008-04-11n"   
      "nUsage:  lzma <e|d> inputFile outputFilen"   
             "  e: encode filen"   
             "  d: decode filen");   
}   
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: %xn", (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 int Decode(FILE *inFile, FILE *outFile, char *rs)   
{   
  UInt64 unpackSize;   
  int thereIsSize; /* = 1, if there is uncompressed size in headers */   
  int i;   
  int 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 */   
  if (!MyReadFileAndCheck(inFile, header, sizeof(header)))   
    return PrintError(rs, kCantReadMessage);   
  unpackSize = 0;   
  thereIsSize = 0;   
  for (i = 0; i < 8; i++)   
  {   
    unsigned char b = header[LZMA_PROPS_SIZE + i];   
    if (b != 0xFF)   
      thereIsSize = 1;   
    unpackSize += (UInt64)b << (i * 8);   
  }   
  LzmaDec_Construct(&state);   
  res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);   
  if (res != SZ_OK)   
    return res;   
  {   
    Byte inBuf[IN_BUF_SIZE];   
    Byte outBuf[OUT_BUF_SIZE];   
    size_t inPos = 0, inSize = 0, outPos = 0;   
    LzmaDec_Init(&state);   
    for (;;)   
    {   
      if (inPos == inSize)   
      {   
        inSize = MyReadFile(inFile, inBuf, IN_BUF_SIZE);   
        inPos = 0;   
      }   
      {   
        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 += (UInt32)inProcessed;   
        outPos += outProcessed;   
        unpackSize -= outProcessed;   
        if (outFile != 0)   
          MyWriteFile(outFile, outBuf, outPos);   
        outPos = 0;   
        if (res != SZ_OK || thereIsSize && unpackSize == 0)   
          break;   
        if (inProcessed == 0 && outProcessed == 0)   
        {   
          if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)   
            res = SZ_ERROR_DATA;   
          break;   
        }   
      }   
    }   
  }   
  LzmaDec_Free(&state, &g_Alloc);   
  return res;   
}   
typedef struct _CFileSeqInStream   
{   
  ISeqInStream funcTable;   
  FILE *file;   
} CFileSeqInStream;   
static SRes MyRead(void *p, void *buf, size_t *size)   
{   
  if (*size == 0)   
    return SZ_OK;   
  *size = MyReadFile(((CFileSeqInStream*)p)->file, buf, *size);   
  /*  
  if (*size == 0)  
    return SZE_FAIL;  
  */   
  return SZ_OK;   
}   
typedef struct _CFileSeqOutStream   
{   
  ISeqOutStream funcTable;   
  FILE *file;   
} CFileSeqOutStream;   
static size_t MyWrite(void *pp, const void *buf, size_t size)   
{   
  return MyWriteFile(((CFileSeqOutStream *)pp)->file, buf, size);   
}   
static SRes Encode(FILE *inFile, FILE *outFile, char *rs)   
{   
  CLzmaEncHandle enc;   
  SRes res;   
  CFileSeqInStream inStream;   
  CFileSeqOutStream outStream;   
  CLzmaEncProps props;   
  enc = LzmaEnc_Create(&g_Alloc);   
  if (enc == 0)   
    return SZ_ERROR_MEM;   
  inStream.funcTable.Read = MyRead;   
  inStream.file = inFile;   
  outStream.funcTable.Write = MyWrite;   
  outStream.file = outFile;   
  LzmaEncProps_Init(&props);   
  res = LzmaEnc_SetProps(enc, &props);   
  if (res == SZ_OK)   
  {   
    Byte header[LZMA_PROPS_SIZE + 8];   
    size_t headerSize = LZMA_PROPS_SIZE;   
    UInt64 fileSize;   
    int i;   
    res = LzmaEnc_WriteProperties(enc, header, &headerSize);   
    fileSize = MyGetFileLength(inFile);   
    for (i = 0; i < 8; i++)   
      header[headerSize++] = (Byte)(fileSize >> (8 * i));   
    if (!MyWriteFileAndCheck(outFile, header, headerSize))   
      return PrintError(rs, "writing error");   
    if (res == SZ_OK)   
      res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,   
        NULL, &g_Alloc, &g_Alloc);   
  }   
  LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);   
  return res;   
}   
int main2(int numArgs, const char *args[], char *rs)   
{   
  FILE *inFile = 0;   
  FILE *outFile = 0;   
  char c;   
  int res;   
  int encodeMode;   
  if (numArgs == 1)   
  {   
    PrintHelp(rs);   
    return 0;   
  }   
  if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)   
    return PrintUserError(rs);   
  c = args[1][0];   
  encodeMode = (c == 'e' || c == 'E');   
  if (!encodeMode && c != 'd' && c != 'D')   
    return PrintUserError(rs);   
  {   
    size_t t4 = sizeof(UInt32);   
    size_t t8 = sizeof(UInt64);   
    if (t4 != 4 || t8 != 8)   
      return PrintError(rs, "LZMA UTil needs correct UInt32 and UInt64");   
  }   
  inFile = fopen(args[2], "rb");   
  if (inFile == 0)   
    return PrintError(rs, "Can not open input file");   
  if (numArgs > 3)   
  {   
    outFile = fopen(args[3], "wb+");   
    if (outFile == 0)   
      return PrintError(rs, "Can not open output file");   
  }   
  else if (encodeMode)   
    PrintUserError(rs);   
  if (encodeMode)   
  {   
    res = Encode(inFile, outFile, rs);   
  }   
  else   
  {   
    res = Decode(inFile, outFile, rs);   
  }   
  if (outFile != 0)   
    fclose(outFile);   
  fclose(inFile);   
  if (res != SZ_OK)   
  {   
    if (res == SZ_ERROR_MEM)   
      return PrintError(rs, kCantAllocateMessage);   
    else if (res == SZ_ERROR_DATA)   
      return PrintError(rs, kDataErrorMessage);   
    else   
      return PrintErrorNumber(rs, res);   
  }   
  return 0;   
}   
int MY_CDECL main(int numArgs, const char *args[])   
{   
  char rs[800] = { 0 };   
  int res = main2(numArgs, args, rs);   
  printf(rs);   
  return res;   
}

你也可以在上看到它

http://read.pudn.com/downloads151/sourcecode/zip/656407/7z460/C/LzmaUtil/LzmaUtil.c__.htm

http://read.pudn.com/downloads157/sourcecode/zip/698262/LZMA/LzmaUtil.c__.htm

我最近发现了一个用C++编写的好例子。GH用户Treeki发布了原始要点:

// note: -D_7ZIP_ST is required when compiling on non-Windows platforms
// g++ -o lzma_sample -std=c++14 -D_7ZIP_ST lzma_sample.cpp LzmaDec.c LzmaEnc.c LzFind.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <memory>
#include "LzmaEnc.h"
#include "LzmaDec.h"
static void *_lzmaAlloc(ISzAllocPtr, size_t size) {
    return new uint8_t[size];
}
static void _lzmaFree(ISzAllocPtr, void *addr) {
    if (!addr)
        return;
    delete[] reinterpret_cast<uint8_t *>(addr);
}
static ISzAlloc _allocFuncs = {
    _lzmaAlloc, _lzmaFree
};

std::unique_ptr<uint8_t[]> lzmaCompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
    std::unique_ptr<uint8_t[]> result;
    // set up properties
    CLzmaEncProps props;
    LzmaEncProps_Init(&props);
    if (inputSize >= (1 << 20))
        props.dictSize = 1 << 20; // 1mb dictionary
    else
        props.dictSize = inputSize; // smaller dictionary = faster!
    props.fb = 40;
    // prepare space for the encoded properties
    SizeT propsSize = 5;
    uint8_t propsEncoded[5];
    // allocate some space for the compression output
    // this is way more than necessary in most cases...
    // but better safe than sorry
    //   (a smarter implementation would use a growing buffer,
    //    but this requires a bunch of fuckery that is out of
    ///   scope for this simple example)
    SizeT outputSize64 = inputSize * 1.5;
    if (outputSize64 < 1024)
        outputSize64 = 1024;
    auto output = std::make_unique<uint8_t[]>(outputSize64);
    int lzmaStatus = LzmaEncode(
        output.get(), &outputSize64, input, inputSize,
        &props, propsEncoded, &propsSize, 0,
        NULL,
        &_allocFuncs, &_allocFuncs);
    *outputSize = outputSize64 + 13;
    if (lzmaStatus == SZ_OK) {
        // tricky: we have to generate the LZMA header
        // 5 bytes properties + 8 byte uncompressed size
        result = std::make_unique<uint8_t[]>(outputSize64 + 13);
        uint8_t *resultData = result.get();
        memcpy(resultData, propsEncoded, 5);
        for (int i = 0; i < 8; i++)
            resultData[5 + i] = (inputSize >> (i * 8)) & 0xFF;
        memcpy(resultData + 13, output.get(), outputSize64);
    }
    return result;
}

std::unique_ptr<uint8_t[]> lzmaDecompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
    if (inputSize < 13)
        return NULL; // invalid header!
    // extract the size from the header
    UInt64 size = 0;
    for (int i = 0; i < 8; i++)
        size |= (input[5 + i] << (i * 8));
    if (size <= (256 * 1024 * 1024)) {
        auto blob = std::make_unique<uint8_t[]>(size);
        ELzmaStatus lzmaStatus;
        SizeT procOutSize = size, procInSize = inputSize - 13;
        int status = LzmaDecode(blob.get(), &procOutSize, &input[13], &procInSize, input, 5, LZMA_FINISH_END, &lzmaStatus, &_allocFuncs);
        if (status == SZ_OK && procOutSize == size) {
            *outputSize = size;
            return blob;
        }
    }
    return NULL;
}

void hexdump(const uint8_t *buf, int size) {
    int lines = (size + 15) / 16;
    for (int i = 0; i < lines; i++) {
        printf("%08x | ", i * 16);
        int lineMin = i * 16;
        int lineMax = lineMin + 16;
        int lineCappedMax = (lineMax > size) ? size : lineMax;
        for (int j = lineMin; j < lineCappedMax; j++)
            printf("%02x ", buf[j]);
        for (int j = lineCappedMax; j < lineMax; j++)
            printf("   ");
        printf("| ");
        for (int j = lineMin; j < lineCappedMax; j++) {
            if (buf[j] >= 32 && buf[j] <= 127)
                printf("%c", buf[j]);
            else
                printf(".");
        }
        printf("n");
    }
}

void testIt(const uint8_t *input, int size) {
    printf("Test Input:n");
    hexdump(input, size);
    uint32_t compressedSize;
    auto compressedBlob = lzmaCompress(input, size, &compressedSize);
    if (compressedBlob) {
        printf("Compressed:n");
        hexdump(compressedBlob.get(), compressedSize);
    } else {
        printf("Nope, we screwed itn");
        return;
    }
    // let's try decompressing it now
    uint32_t decompressedSize;
    auto decompressedBlob = lzmaDecompress(compressedBlob.get(), compressedSize, &decompressedSize);
    if (decompressedBlob) {
        printf("Decompressed:n");
        hexdump(decompressedBlob.get(), decompressedSize);
    } else {
        printf("Nope, we screwed it (part 2)n");
        return;
    }
    printf("----------n");
}
void testIt(const char *string) {
    testIt((const uint8_t *)string, strlen(string));
}

int main(int argc, char **argv) {
    testIt("a");
    testIt("here is a cool string");
    testIt("here's something that should compress pretty well: abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef");
    return 0;
}

您可以参考此文件了解如何使用lzma2

https://github.com/Tencent/libpag/blob/aab6391e455193c8ec5b8e2031b495b3fe77b034/test/framework/utils/LzmaUtil.cpp

/////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Tencent is pleased to support the open source community by making libpag available.
//
//  Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
//  except in compliance with the License. You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  unless required by applicable law or agreed to in writing, software distributed under the
//  license is distributed on an "as is" basis, without warranties or conditions of any kind,
//  either express or implied. see the license for the specific language governing permissions
//  and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
#include "LzmaUtil.h"
#include "test/framework/lzma/Lzma2DecMt.h"
#include "test/framework/lzma/Lzma2Enc.h"
namespace pag {
static void* LzmaAlloc(ISzAllocPtr, size_t size) {
  return new uint8_t[size];
}
static void LzmaFree(ISzAllocPtr, void* address) {
  if (!address) {
    return;
  }
  delete[] reinterpret_cast<uint8_t*>(address);
}
static ISzAlloc gAllocFuncs = {LzmaAlloc, LzmaFree};
class SequentialOutStream {
 public:
  virtual ~SequentialOutStream() = default;
  virtual bool write(const void* data, size_t size) = 0;
};
class SequentialInStream {
 public:
  virtual ~SequentialInStream() = default;
  virtual bool read(void* data, size_t size, size_t* processedSize) = 0;
};
struct CSeqInStreamWrap {
  ISeqInStream vt;
  std::unique_ptr<SequentialInStream> inStream;
};
struct CSeqOutStreamWrap {
  ISeqOutStream vt;
  std::unique_ptr<SequentialOutStream> outStream;
};
class BuffPtrInStream : public SequentialInStream {
 public:
  explicit BuffPtrInStream(const uint8_t* buffer, size_t bufferSize)
      : buffer(buffer), bufferSize(bufferSize) {
  }
  bool read(void* data, size_t size, size_t* processedSize) override {
    if (processedSize) {
      *processedSize = 0;
    }
    if (size == 0 || position >= bufferSize) {
      return true;
    }
    auto remain = bufferSize - position;
    if (remain > size) {
      remain = size;
    }
    memcpy(data, static_cast<const uint8_t*>(buffer) + position, remain);
    position += remain;
    if (processedSize) {
      *processedSize = remain;
    }
    return true;
  }
 private:
  const uint8_t* buffer = nullptr;
  size_t bufferSize = 0;
  size_t position = 0;
};
class VectorOutStream : public SequentialOutStream {
 public:
  explicit VectorOutStream(std::vector<uint8_t>* buffer) : buffer(buffer) {
  }
  bool write(const void* data, size_t size) override {
    auto oldSize = buffer->size();
    buffer->resize(oldSize + size);
    memcpy(&(*buffer)[oldSize], data, size);
    return true;
  }
 private:
  std::vector<uint8_t>* buffer;
};
class BuffPtrSeqOutStream : public SequentialOutStream {
 public:
  BuffPtrSeqOutStream(uint8_t* buffer, size_t size) : buffer(buffer), bufferSize(size) {
  }
  bool write(const void* data, size_t size) override {
    auto remain = bufferSize - position;
    if (remain > size) {
      remain = size;
    }
    if (remain != 0) {
      memcpy(buffer + position, data, remain);
      position += remain;
    }
    return remain != 0 || size == 0;
  }
 private:
  uint8_t* buffer = nullptr;
  size_t bufferSize = 0;
  size_t position = 0;
};
static const size_t kStreamStepSize = 1 << 31;
static SRes MyRead(const ISeqInStream* p, void* data, size_t* size) {
  CSeqInStreamWrap* wrap = CONTAINER_FROM_VTBL(p, CSeqInStreamWrap, vt);
  auto curSize = (*size < kStreamStepSize) ? *size : kStreamStepSize;
  if (!wrap->inStream->read(data, curSize, &curSize)) {
    return SZ_ERROR_READ;
  }
  *size = curSize;
  return SZ_OK;
}
static size_t MyWrite(const ISeqOutStream* p, const void* buf, size_t size) {
  auto* wrap = CONTAINER_FROM_VTBL(p, CSeqOutStreamWrap, vt);
  if (wrap->outStream->write(buf, size)) {
    return size;
  }
  return 0;
}
class Lzma2Encoder {
 public:
  Lzma2Encoder() {
    encoder = Lzma2Enc_Create(&gAllocFuncs, &gAllocFuncs);
  }
  ~Lzma2Encoder() {
    Lzma2Enc_Destroy(encoder);
  }
  std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
    if (encoder == nullptr || inputData == nullptr || inputData->size() == 0) {
      return nullptr;
    }
    auto inputSize = inputData->size();
    CLzma2EncProps lzma2Props;
    Lzma2EncProps_Init(&lzma2Props);
    lzma2Props.lzmaProps.dictSize = inputSize;
    lzma2Props.lzmaProps.level = 9;
    lzma2Props.numTotalThreads = 4;
    Lzma2Enc_SetProps(encoder, &lzma2Props);
    std::vector<uint8_t> outBuf;
    outBuf.resize(1 + 8);
    outBuf[0] = Lzma2Enc_WriteProperties(encoder);
    for (int i = 0; i < 8; i++) {
      outBuf[1 + i] = static_cast<uint8_t>(inputSize >> (8 * i));
    }
    CSeqInStreamWrap inWrap = {};
    inWrap.vt.Read = MyRead;
    inWrap.inStream = std::make_unique<BuffPtrInStream>(
        static_cast<const uint8_t*>(inputData->data()), inputSize);
    CSeqOutStreamWrap outStream = {};
    outStream.vt.Write = MyWrite;
    outStream.outStream = std::make_unique<VectorOutStream>(&outBuf);
    auto status =
        Lzma2Enc_Encode2(encoder, &outStream.vt, nullptr, nullptr, &inWrap.vt, nullptr, 0, nullptr);
    if (status != SZ_OK) {
      return nullptr;
    }
    return Data::MakeWithCopy(&outBuf[0], outBuf.size());
  }
 private:
  CLzma2EncHandle encoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Compress(const std::shared_ptr<Data>& pixelData) {
  Lzma2Encoder encoder;
  return encoder.code(pixelData);
}
class Lzma2Decoder {
 public:
  Lzma2Decoder() {
    decoder = Lzma2DecMt_Create(&gAllocFuncs, &gAllocFuncs);
  }
  ~Lzma2Decoder() {
    if (decoder) {
      Lzma2DecMt_Destroy(decoder);
    }
  }
  std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
    if (decoder == nullptr || inputData == nullptr || inputData->size() == 0) {
      return nullptr;
    }
    auto input = static_cast<const uint8_t*>(inputData->data());
    auto inputSize = inputData->size() - 9;
    Byte prop = static_cast<const Byte*>(input)[0];
    CLzma2DecMtProps props;
    Lzma2DecMtProps_Init(&props);
    props.inBufSize_ST = inputSize;
    props.numThreads = 1;
    UInt64 outBufferSize = 0;
    for (int i = 0; i < 8; i++) {
      outBufferSize |= (input[1 + i] << (i * 8));
    }
    auto outBuffer = new uint8_t[outBufferSize];
    CSeqInStreamWrap inWrap = {};
    inWrap.vt.Read = MyRead;
    inWrap.inStream = std::make_unique<BuffPtrInStream>(input + 9, inputSize);
    CSeqOutStreamWrap outWrap = {};
    outWrap.vt.Write = MyWrite;
    outWrap.outStream = std::make_unique<BuffPtrSeqOutStream>(outBuffer, outBufferSize);
    UInt64 inProcessed = 0;
    int isMT = false;
    auto res = Lzma2DecMt_Decode(decoder, prop, &props, &outWrap.vt, &outBufferSize, 1, &inWrap.vt,
                                 &inProcessed, &isMT, nullptr);
    if (res == SZ_OK && inputSize == inProcessed) {
      return Data::MakeAdopted(outBuffer, outBufferSize, Data::DeleteProc);
    }
    delete[] outBuffer;
    return nullptr;
  }
 private:
  CLzma2DecMtHandle decoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Decompress(const std::shared_ptr<Data>& data) {
  Lzma2Decoder decoder;
  return decoder.code(data);
}
}  // namespace pag