#archive #file #bindings #rar #abstraction #extract #unrar

sys no-std unrar_sys

FFI bindings to unrar (with minimal abstractions)

8 releases

0.5.6 Sep 1, 2024
0.5.5 Aug 31, 2024
0.3.1 Nov 11, 2023
0.3.0 Jun 22, 2023
0.1.0 Aug 2, 2015

#410 in Compression

Download history 402/week @ 2024-07-29 277/week @ 2024-08-05 315/week @ 2024-08-12 373/week @ 2024-08-19 1530/week @ 2024-08-26 1232/week @ 2024-09-02 505/week @ 2024-09-09 630/week @ 2024-09-16 423/week @ 2024-09-23 727/week @ 2024-09-30 441/week @ 2024-10-07 297/week @ 2024-10-14 595/week @ 2024-10-21 794/week @ 2024-10-28 307/week @ 2024-11-04 844/week @ 2024-11-11

2,583 downloads per month
Used in 9 crates (2 directly)

MIT/Apache

780KB
22K SLoC

C++ 21K SLoC // 0.1% comments Visual Studio Project 699 SLoC Rust 398 SLoC // 0.0% comments Shell 19 SLoC

unrar

crates.io API docs build MIT license

High-level wrapper around the unrar C library provided by rarlab.

This library can only extract and list archives, it cannot create them.

Please look inside the examples directory to see how to use this library. Specifically the lister example is well documented and advanced!

Basic example to list archive entries:

use unrar::Archive;

fn main() {
    for entry in Archive::new("archive.rar").open_for_listing().unwrap() {
        println!("{}", entry.unwrap());
    }
}

Run this example: cargo run --example basic_list path/to/archive.rar. You can create an archive by using the rar CLI: rar a archive.rar .

Overview

The primary type in this crate is Archive which denotes an archive on the file system. Archive itself makes no FS operations, unless one of the open methods are called, returning an OpenArchive.

Archive

The Archive struct provides two major classes of methods:

  1. methods that do not touch the FS. These are opinionated utility methods that are based on RAR path conventions out in the wild. Most commonly, multipart files usually have extensions such as .part08.rar or .r08.rar. Since extracting must start at the first part, it may be helpful to figure that out using, for instance, archive.as_first_part()
  2. methods that open the underlying path in the specified mode (possible modes are List, ListSplit and Process). These methods have the word open in them, are fallible operations, return OpenArchive inside a Result and are as follows:

OpenArchive

An archive is opened in one of these three modes: List, ListSplit or Process. This library does not provide random access into archives. Instead, files inside the archive can only be processed as a stream, unidirectionally, front to back, alternating between ReadHeader and ProcessFile operations (as dictated by the underlying C++ library).

That is the idea behind cursors:

OpenArchive: Cursors

Via cursors, the archive keeps track what operation is permitted next:

The library enforces this by making use of the typestate pattern. An archive, once opened, starts in the CursorBeforeHeader state and, thus, must have its read_header method called, which returns a new OpenArchive instance in the CursorBeforeFile state that only exposes methods that internally map to the ProcessFile operation. Which methods are accessible in each step depends on the archive's current state and the mode it was opened in.

Available methods for Open mode/Cursor position combinations

Here is an overview of what methods are exposed for the OpenMode/Cursor combinations:

Open mode↓ ╲ Cursor position→ before header before file
List, ListSplit read_header skip
Process read_header skip, read, extract, extract_to, extract_with_base

OpenArchive: Iterator

Archives opened in List or ListSplit mode also implement Iterator whereas archives in Process mode do not (though this may change in future releases). That is because the first two will read and return headers while being forced to skip over the payload whereas the latter has more sophisticated processing possibilities that's not easy to convey using an Iterator.

Example

For more sophisticated examples, please look inside the examples/ folder.

Here's what a function that returns the first content of a file could look like:

fn first_file_content<P: AsRef<Path>>(path: P) -> UnrarResult<Vec<u8>> {
    let archive = Archive::new(&path).open_for_processing()?; // cursor: before header
    let archive = archive.read_header()?.expect("empty archive"); // cursor: before file
    dbg!(&archive.entry().filename);
    let (data, _rest) = archive.read()?; // cursor: before header
    Ok(data)
}
# use std::path::Path;
# use unrar::{Archive, UnrarResult};
#
# let data = first_file_content("data/version.rar").unwrap();
# assert_eq!(std::str::from_utf8(&data), Ok("unrar-0.4.0"));

Features

  • Multipart files
  • Listing archives
  • Extracting them
  • Reading them into memory (without extracting)
  • Testing them
  • Encrypted archives with password
  • Linked statically against the unrar source.
  • Build unrar C++ code from source
  • Basic functionality that operates on filenames / paths (without reading archives)
  • Documentation / RustDoc
  • Test Suite
  • utilizes type system to enforce correct usage
  • Well-designed errors (planned)
  • TBD

Non-Features

As this library is only a wrapper, these following features are not easily feasible and as such not planned:

  • Creating archives
  • Random access into arbitrary archive entries
  • Pure Rust implementation
  • Processing archives from a file descriptor / fs::File handle
  • Processing archives from a byte stream

Contributing

Feel free to contribute! If you detect a bug, open an issue.

Pull requests are also welcome!

Help

If you need help using the library, feel free to create a new discussion or open an issue.

License

The parts authored by this library's contributors are licensed under either of

at your option.

The embedded C/C++ library uses its own license. For more informations, see its license file.

Dependencies