All formats

UnRAR library

LanguageC++ (C API in dll.hpp)
LicenseUnRAR license: free, but not OSI open source; may not be used to re-create the RAR compression algorithm or build a RAR-compatible archiver
RepositoryUnRAR source (tarball from RARLAB, no public repository)
DocumentationUnRARDLL.txt in the UnRAR.dll package, comments in dll.hpp
Depends onnothing
Read / writeyes / no; RAR4 and RAR5, encrypted files and headers, volumes, solid archives, RAR 7.0 large dictionaries

The UnRAR library is the extraction half of WinRAR, published as source by RARLAB. It’s the most complete RAR reader: every RAR version, every compression method and filter, AES encryption, volumes, symlinks and hashes. 7-Zip’s older RAR code, the PHP rar extension, the Rust unrar crate and many file managers are built on it.

Programs use it through a small C API (RAROpenArchiveEx, RARReadHeaderEx, RARProcessFile, RARCloseArchive) compiled as unrar.dll on Windows or libunrar.so / libunrar.a on Unix. The API reads entries one after the other: for each header you either skip, test or extract the file. Extracted data goes to disk, or to your callback if you want it in memory.

The license is the main limitation: it’s freeware, not an OSI-approved open-source license, and some Linux distributions ship it in their non-free section.

Installation#

Shell
# Debian / Ubuntu (non-free / multiverse section)
sudo apt install libunrar-dev        # headers in /usr/include/unrar, links with -lunrar
# Windows (vcpkg, builds unrar.dll)
vcpkg install unrar

To build from source, download unrarsrc-*.tar.gz from rarlab.com:

Shell
tar xf unrarsrc-7.3.2.tar.gz
cd unrar
make lib              # builds libunrar.so and libunrar.a

On Windows, the UnRAR.dll package has a prebuilt unrar.dll / unrar64.dll, import libraries and the documentation.

On Unix, define _UNIX before including dll.hpp; on Windows include <windows.h> first.

Basic usage: list and extract a RAR file#

C++
#ifdef _WIN32
#include <windows.h>
#else
#define _UNIX
#endif
#include <unrar/dll.hpp>   // from libunrar-dev; "dll.hpp" when building from source
#include <cstdio>

int main(int argc, char **argv) {
    if (argc < 2) return 2;

    RAROpenArchiveDataEx arc = {};
    arc.ArcName = argv[1];
    arc.OpenMode = RAR_OM_EXTRACT;  // RAR_OM_LIST to only list
    HANDLE h = RAROpenArchiveEx(&arc);
    if (arc.OpenResult != ERAR_SUCCESS) {
        fprintf(stderr, "cannot open archive, error %u\n", arc.OpenResult);
        return 1;
    }

    static RARHeaderDataEx hdr;  // large struct, keep it off the stack
    int res;
    while ((res = RARReadHeaderEx(h, &hdr)) == ERAR_SUCCESS) {
        unsigned long long size = ((unsigned long long)hdr.UnpSizeHigh << 32) | hdr.UnpSize;
        printf("%-50s %12llu%s\n", hdr.FileName, size,
               (hdr.Flags & RHDF_DIRECTORY) ? " <dir>" : "");

        // extract into the "out" folder, keeping the paths stored in the archive
        res = RARProcessFile(h, RAR_EXTRACT, (char *)"out", NULL);
        if (res != ERAR_SUCCESS) {
            fprintf(stderr, "extract error %d\n", res);
            break;
        }
    }
    RARCloseArchive(h);
    return res == ERAR_END_ARCHIVE ? 0 : 1;
}
Shell
g++ -o listrar listrar.cpp -lunrar

RARReadHeaderEx returns ERAR_END_ARCHIVE after the last entry. Use RAR_SKIP instead of RAR_EXTRACT to move to the next entry without decompressing (in a solid archive the library still has to decompress the data internally).

How to extract a file from a RAR archive into memory#

Open in extract mode, set a callback, and process the entry with RAR_TEST: the decompressed data is passed to the callback in chunks and nothing is written to disk.

C++
#include <vector>
#include <cstring>

static int CALLBACK on_event(UINT msg, LPARAM user, LPARAM p1, LPARAM p2) {
    if (msg == UCM_PROCESSDATA) {
        auto *out = reinterpret_cast<std::vector<unsigned char> *>(user);
        auto *data = reinterpret_cast<unsigned char *>(p1);
        out->insert(out->end(), data, data + p2);
        return 1;   // continue; -1 cancels
    }
    if (msg == UCM_NEEDPASSWORD) return -1;  // no password available
    return 1;
}

bool read_entry(char *archive, const char *name, std::vector<unsigned char> &out) {
    RAROpenArchiveDataEx arc = {};
    arc.ArcName = archive;
    arc.OpenMode = RAR_OM_EXTRACT;
    arc.Callback = on_event;
    arc.UserData = (LPARAM)&out;
    HANDLE h = RAROpenArchiveEx(&arc);
    if (arc.OpenResult != ERAR_SUCCESS) return false;

    static RARHeaderDataEx hdr;
    bool found = false;
    while (RARReadHeaderEx(h, &hdr) == ERAR_SUCCESS) {
        bool match = strcmp(hdr.FileName, name) == 0;
        if (RARProcessFile(h, match ? RAR_TEST : RAR_SKIP, NULL, NULL) != ERAR_SUCCESS) break;
        if (match) { found = true; break; }
    }
    RARCloseArchive(h);
    return found;
}

RAR_TEST also verifies the CRC-32 or BLAKE2 checksum: a corrupt entry returns ERAR_BAD_DATA.

How to extract a password-protected RAR#

Set the password after opening the archive:

C++
HANDLE h = RAROpenArchiveEx(&arc);
if (arc.OpenResult == ERAR_SUCCESS) {
    RARSetPassword(h, (char *)"secret");
    if (arc.Flags & ROADF_ENCHEADERS)
        printf("file names are encrypted too\n");
    // ... RARReadHeaderEx / RARProcessFile as usual ...
}

With a RAR5 archive, a wrong password makes RARProcessFile (or RARReadHeaderEx for encrypted headers) return ERAR_BAD_PASSWORD. RAR4 has no password check value, so a wrong password shows up as ERAR_BAD_DATA (CRC error). No password returns ERAR_MISSING_PASSWORD. To ask the user only when needed, handle UCM_NEEDPASSWORD in the callback: copy the password into the buffer at p1 (size p2) and return 1.

How to check if an archive is solid, encrypted or a volume#

RAROpenArchiveEx fills arc.Flags from the main archive header:

C++
if (arc.Flags & ROADF_SOLID)       printf("solid\n");
if (arc.Flags & ROADF_VOLUME)      printf("multi-volume\n");
if (arc.Flags & ROADF_FIRSTVOLUME) printf("first volume\n");
if (arc.Flags & ROADF_RECOVERY)    printf("has recovery record\n");
if (arc.Flags & ROADF_LOCK)        printf("locked\n");

Per entry, hdr.Flags & RHDF_ENCRYPTED tells if a file is encrypted, and RHDF_SPLITBEFORE / RHDF_SPLITAFTER if it continues from or into another volume.

How to extract a multi-volume RAR#

Open the first volume (name.part1.rar or name.rar). The library opens the next volumes by name as it goes. When a volume is missing it calls the callback with UCM_CHANGEVOLUME and p2 == RAR_VOL_ASK: return -1 to stop, or write another path into the buffer at p1 and return 1.

C++
if (msg == UCM_CHANGEVOLUME) {
    if (p2 == RAR_VOL_ASK) {
        fprintf(stderr, "missing volume: %s\n", (char *)p1);
        return -1;
    }
    return 1;  // RAR_VOL_NOTIFY: the next volume was opened
}

Tips#