All formats

LZMA SDK

LanguageC (7z decoder, LZMA/LZMA2/XZ codecs), C++ (7z encoder and decoder), plus C# and Java LZMA codecs
Licensepublic domain
Repository7-zip.org/sdk.html (downloads); source mirror at github.com/ip7z/7zip (the C folder)
DocumentationDOC/7zFormat.txt, DOC/lzma-sdk.txt and the sample C/Util/7z/7zMain.c
Depends onnothing
Read / writeyes / no in C (the C++ part has a reduced 7z encoder); no encryption in the C decoder

The LZMA SDK is the code that 7-Zip itself is built from, placed in the public domain by Igor Pavlov. Its C part contains LZMA, LZMA2 and XZ compressors and decompressors and a compact 7z decoder that needs only a few kilobytes of code plus the dictionary size in memory. It’s used in installers, boot loaders, firmware and programs that need to unpack 7z without a license obligation.

The C 7z decoder supports Copy, LZMA, LZMA2, PPMd, Delta and the BCJ, BCJ2, ARM, ARM64, ARMT, PPC, SPARC, IA64 and RISC-V filters, solid archives and compressed headers. It doesn’t support AES encryption, BZip2 or Deflate inside 7z, and it decompresses a whole folder (solid block) into memory, so it suits small and medium archives. To create 7z archives in C++ use the reduced 7-Zip code in the SDK’s CPP folder, or bit7z with the 7-Zip DLL.

Installation#

Download the SDK from 7-zip.org/sdk.html (lzma*.7z or .tar.xz) and add these files from the C folder to your project:

7zAlloc.c 7zArcIn.c 7zBuf.c 7zBuf2.c 7zCrc.c 7zCrcOpt.c 7zDec.c 7zFile.c 7zStream.c
Bcj2.c Bra.c Bra86.c BraIA64.c CpuArch.c Delta.c Lzma2Dec.c LzmaDec.c Ppmd7.c Ppmd7Dec.c

Define Z7_PPMD_SUPPORT to enable PPMd and Z7_EXTRACT_ONLY for a decoder-only build (the same flags the sample C/Util/7z/makefile.gcc uses). There is no vcpkg or Conan package for the SDK alone (the vcpkg 7zip port builds the full LGPL 7-Zip library), so copying the files is the usual way.

Basic usage: list files and extract them to memory#

This follows the sample 7zMain.c: open the file, wrap it in a look-ahead stream, open the archive database, then extract each file.

C
#include <stdio.h>
#include "7z.h"
#include "7zAlloc.h"
#include "7zCrc.h"
#include "7zFile.h"

#define kInputBufSize ((size_t)1 << 18)
static const ISzAlloc g_Alloc = { SzAlloc, SzFree };

int main(int argc, char **argv) {
    CFileInStream archiveStream;
    CLookToRead2 lookStream;
    CSzArEx db;
    SRes res = SZ_OK;
    ISzAlloc allocImp = g_Alloc, allocTempImp = g_Alloc;

    if (argc < 2 || InFile_Open(&archiveStream.file, argv[1]) != 0) {
        fprintf(stderr, "cannot open input file\n");
        return 1;
    }
    FileInStream_CreateVTable(&archiveStream);
    archiveStream.wres = 0;
    LookToRead2_CreateVTable(&lookStream, False);
    lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
    if (!lookStream.buf) return 1;
    lookStream.bufSize = kInputBufSize;
    lookStream.realStream = &archiveStream.vt;
    LookToRead2_INIT(&lookStream)

    CrcGenerateTable();
    SzArEx_Init(&db);
    res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);

    if (res == SZ_OK) {
        UInt32 blockIndex = 0xFFFFFFFF;  // cache of the last decoded folder
        Byte *outBuffer = NULL;          // must be NULL before the first call
        size_t outBufferSize = 0;
        UInt16 name[1024];

        for (UInt32 i = 0; i < db.NumFiles && res == SZ_OK; i++) {
            if (SzArEx_GetFileNameUtf16(&db, i, NULL) > 1024) continue;
            SzArEx_GetFileNameUtf16(&db, i, name);  // UTF-16, 0-terminated
            for (int k = 0; name[k]; k++) putchar(name[k] < 128 ? (char)name[k] : '?');

            if (SzArEx_IsDir(&db, i)) {
                printf("/\n");
                continue;
            }
            size_t offset = 0, outSizeProcessed = 0;
            res = SzArEx_Extract(&db, &lookStream.vt, i, &blockIndex,
                                 &outBuffer, &outBufferSize,
                                 &offset, &outSizeProcessed,
                                 &allocImp, &allocTempImp);
            if (res == SZ_OK) {
                // file data: outBuffer + offset, outSizeProcessed bytes
                printf("  %zu bytes\n", outSizeProcessed);
            }
        }
        ISzAlloc_Free(&allocImp, outBuffer);
    }

    SzArEx_Free(&db, &allocImp);
    ISzAlloc_Free(&allocImp, lookStream.buf);
    File_Close(&archiveStream.file);

    if (res == SZ_ERROR_UNSUPPORTED) fprintf(stderr, "unsupported method (encrypted?)\n");
    else if (res == SZ_ERROR_CRC) fprintf(stderr, "CRC error\n");
    else if (res != SZ_OK) fprintf(stderr, "error %d\n", res);
    return res == SZ_OK ? 0 : 1;
}

How to get file size, time and CRC without extracting#

The archive database CSzArEx has all metadata after SzArEx_Open:

C
UInt64 size = SzArEx_GetFileSize(&db, i);
if (SzBitWithVals_Check(&db.MTime, i)) {
    const CNtfsFileTime *t = &db.MTime.Vals[i];  // Windows FILETIME: Low, High
}
if (SzBitWithVals_Check(&db.CRCs, i)) {
    UInt32 crc = db.CRCs.Vals[i];
}
if (SzBitWithVals_Check(&db.Attribs, i)) {
    UInt32 attrib = db.Attribs.Vals[i];  // Windows attributes
}

How to read a 7z archive from memory#

SzArEx_Open reads through the ILookInStream interface. Instead of CFileInStream, implement ISeekInStream (Read and Seek callbacks) over your buffer and assign it to lookStream.realStream. The rest of the code stays the same.

How to decompress raw LZMA or LZMA2 data#

For .lzma files or LZMA streams in your own format, use LzmaDecode / Lzma2Decode from LzmaDec.h / Lzma2Dec.h, or LzmaUncompress from LzmaLib.h for the simplest one-call API. See DOC/lzma-sdk.txt.

Tips#