Initial commit

This commit is contained in:
Luke Street 2021-08-25 18:28:57 -04:00
commit 91d467665e
17 changed files with 575 additions and 0 deletions

27
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,27 @@
name: build
on: [ push, pull_request ]
jobs:
default:
name: Default
strategy:
matrix:
platform: [ ubuntu-latest, macos-latest, windows-latest ]
toolchain: [ stable, 1.46.0, nightly ]
features:
- compress,alloc
- compress,decompress
- compress,decompress,std
fail-fast: false
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
override: true
- uses: actions-rs/cargo@v1
with:
command: test
args: --release --no-default-features --features ${{ matrix.features }}

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
Cargo.lock
.idea

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "lzokay"]
path = lzokay
url = https://github.com/jackoalan/lzokay.git

24
Cargo.toml Normal file
View File

@ -0,0 +1,24 @@
[package]
name = "lzokay"
version = "1.0.0"
edition = "2018"
license = "MIT"
repository = "https://github.com/encounter/lzokay-rs"
documentation = "https://docs.rs/lzokay"
readme = "README.md"
description = """
A minimal, MIT-licensed implementation of the LZO compression format.
"""
keywords = ["lzo", "compression", "no_std"]
categories = ["compression", "no-std", "api-bindings"]
[features]
alloc = []
std = ["alloc"]
decompress = []
compress = []
default = ["compress", "decompress", "std"]
[build-dependencies]
bindgen = "0.59.1"
cc = "1.0.69"

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright 2021 Luke Street.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

54
README.md Normal file
View File

@ -0,0 +1,54 @@
# LZ👌-rs [![Build Status]][actions] [![Latest Version]][crates.io] [![Api Rustdoc]][rustdoc] ![Rust Version]
[Build Status]: https://github.com/encounter/lzokay-rs/workflows/build/badge.svg
[actions]: https://github.com/encounter/lzokay-rs/actions
[Latest Version]: https://img.shields.io/crates/v/lzokay.svg
[crates.io]: https://crates.io/crates/lzokay
[Api Rustdoc]: https://img.shields.io/badge/api-rustdoc-blue.svg
[rustdoc]: https://docs.rs/lzokay
[Rust Version]: https://img.shields.io/badge/rust-1.46+-blue.svg?maxAge=3600
Rust wrapper for [LZ👌](https://github.com/jackoalan/lzokay), a minimal, MIT-licensed implementation of the
[LZO compression format](http://www.oberhumer.com/opensource/lzo/).
See the original [README](https://github.com/jackoalan/lzokay/blob/master/README.md) for more information.
### Features
- MIT-licensed
- Simple compression and decompression routines
- `#![no_std]` compatible
### Usage
See the [compress](https://docs.rs/lzokay/latest/lzokay/compress)
or [decompress](https://docs.rs/lzokay/latest/lzokay/decompress)
documentation for reference.
In `Cargo.toml`:
```toml
[dependencies]
lzokay = "1.0.0"
```
Or, to only enable certain features:
```toml
[dependencies.lzokay]
version = "1.0.0"
default-features = false
features = ["decompress", "compress"]
```
- `decompress`: Enables decompression functions.
- `compress`: Enables compression functions.
- `alloc`: Enables optional compression functions that perform heap allocation.
Without `std`, this uses `extern crate alloc`.
- `std`: Enables use of `std`. Implies `alloc`.
All features are enabled by default.
### License
LZ👌 and LZ👌-rs are available under the MIT License and have no external dependencies.

24
build.rs Normal file
View File

@ -0,0 +1,24 @@
use std::{env, path::PathBuf};
fn main() {
println!("cargo:rerun-if-changed=wrapper.h");
println!("cargo:rerun-if-changed=lzokay/lzokay.cpp");
println!("cargo:rerun-if-changed=lzokay/lzokay.hpp");
cc::Build::new().cpp(true).file("lzokay/lzokay.cpp").compile("lzokay");
#[allow(unused_mut)]
let mut bindings = bindgen::Builder::default()
.header("wrapper.hpp")
.clang_arg("-Ilzokay")
.allowlist_function("lzokay::.*")
.size_t_is_usize(true)
.ctypes_prefix("types")
.derive_debug(false)
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
#[cfg(not(feature = "std"))]
{
bindings = bindings.layout_tests(false);
}
let result = bindings.generate().expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
result.write_to_file(out_path.join("bindings.rs")).expect("Couldn't write bindings!");
}

1
lzokay Submodule

@ -0,0 +1 @@
Subproject commit 546a9695271e8a8b4711383f828172754fd825f2

8
rustfmt.toml Normal file
View File

@ -0,0 +1,8 @@
fn_single_line = true
group_imports = "StdExternalCrate"
imports_granularity = "Crate"
overflow_delimited_expr = true
reorder_impl_items = true
use_field_init_shorthand = true
use_small_heuristics = "Max"
where_single_line = true

201
src/compress.rs Normal file
View File

@ -0,0 +1,201 @@
//! # Compression routines
//!
//! Available with feature `compress`.
//!
//! [`compress`] and [`compress_with_dict`] available with features `std` and/or `alloc`.
//!
//! # Examples
//!
//! Compressing a buffer into a heap-allocated vector:
//! ```
//! use lzokay::compress::*;
//! # #[allow(non_upper_case_globals)] const input: [u8; 512] = [0u8; 512];
//!
//! let dst: Vec<u8> = compress(&input)?;
//! # assert_eq!(dst.len(), 10);
//! # Ok::<(), lzokay::Error>(())
//! ```
//!
//! Several compression calls with shared dictionary, avoiding needless work:
//! ```
//! use lzokay::compress::*;
//! # #[allow(non_upper_case_globals)] const input1: [u8; 512] = [0u8; 512];
//! # #[allow(non_upper_case_globals)] const input2: [u8; 512] = [0u8; 512];
//!
//! let mut dict = new_dict();
//! let dst1 = compress_with_dict(&input1, &mut dict)?;
//! let dst2 = compress_with_dict(&input2, &mut dict)?;
//! # assert_eq!(dst1.len(), 10);
//! # assert_eq!(dst2.len(), 10);
//! # Ok::<(), lzokay::Error>(())
//! ```
//!
//! `#![no_std]` compatible compression:
//! ```
//! use lzokay::compress::*;
//! # #[allow(non_upper_case_globals)] const input: [u8; 512] = [0u8; 512];
//!
//! // Allocate dst on stack, with worst-case compression size
//! let mut dst = [0u8; compress_worst_size(input.len())];
//! // Allocate dictionary storage on stack
//! let mut storage = [0u8; dict_storage_size()];
//! // Create dictionary from storage
//! let mut dict = dict_from_storage(&mut storage);
//! let size = compress_no_alloc(&input, &mut dst, &mut dict)?;
//! # assert_eq!(size, 10);
//! # Ok::<(), lzokay::Error>(())
//! ```
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{
alloc::{alloc_zeroed, dealloc, Layout},
boxed::Box,
vec::Vec,
};
use core::{marker::PhantomData, mem::size_of, ptr::null_mut};
use crate::{bindings, lzokay_result, Error};
type DictStorage = bindings::lzokay_DictBase_storage_type;
/// Dictionary type
pub struct Dict<'a> {
base: bindings::lzokay_DictBase,
#[cfg(feature = "alloc")]
storage: Option<Box<[u8; dict_storage_size()]>>,
phantom: PhantomData<&'a DictStorage>,
}
/// Creates a new heap-allocated dictionary.
#[cfg(feature = "alloc")]
pub fn new_dict() -> Dict<'static> {
let mut dict = Dict {
base: bindings::lzokay_DictBase { _storage: null_mut() },
storage: Option::Some(Box::new([0u8; dict_storage_size()])),
phantom: PhantomData,
};
dict.base._storage = dict.storage.as_mut().unwrap().as_mut_ptr() as *mut DictStorage;
dict
}
/// Dictionary storage size, for manual or stack allocation.
pub const fn dict_storage_size() -> usize { size_of::<DictStorage>() }
/// Creates a dictionary from the supplied storage.
///
/// Storage **must** be at least [`dict_storage_size()`] bytes,
/// otherwise this function will panic.
pub fn dict_from_storage(storage: &mut [u8]) -> Dict {
if storage.len() < dict_storage_size() {
panic!(
"Dictionary storage is not large enough: {}, expected {}",
storage.len(),
dict_storage_size()
);
}
Dict {
base: bindings::lzokay_DictBase { _storage: storage.as_mut_ptr() as *mut DictStorage },
storage: Option::None,
phantom: PhantomData,
}
}
/// Worst-case compression size.
pub const fn compress_worst_size(s: usize) -> usize { s + s / 16 + 64 + 3 }
/// Compress the supplied buffer into a heap-allocated vector.
///
/// Creates a new dictionary for each invocation.
#[cfg(feature = "alloc")]
pub fn compress(src: &[u8]) -> Result<Vec<u8>, Error> { compress_with_dict(src, &mut new_dict()) }
/// Compress the supplied buffer into a heap-allocated vector,
/// with the supplied pre-allocated dictionary.
#[cfg(feature = "alloc")]
pub fn compress_with_dict(src: &[u8], dict: &mut Dict) -> Result<Vec<u8>, Error> {
let mut out_size = 0usize;
let capacity = compress_worst_size(src.len());
let mut dst = Vec::with_capacity(capacity);
let result = unsafe {
let result = bindings::lzokay_compress(
src.as_ptr(),
src.len(),
dst.as_mut_ptr(),
capacity,
&mut out_size,
&mut dict.base,
);
if result == bindings::lzokay_EResult_Success {
dst.set_len(out_size as usize);
}
result
};
lzokay_result(dst, result)
}
/// Compress the supplied buffer.
///
/// For sizing `dst`, use [`compress_worst_size`].
pub fn compress_no_alloc(src: &[u8], dst: &mut [u8], dict: &mut Dict) -> Result<usize, Error> {
let mut out_size = 0usize;
let result = unsafe {
bindings::lzokay_compress(
src.as_ptr(),
src.len(),
dst.as_mut_ptr(),
dst.len(),
&mut out_size,
&mut dict.base,
)
};
lzokay_result(out_size as usize, result)
}
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use crate::compress::{compress, compress_with_dict, new_dict};
use crate::compress::{
compress_no_alloc, compress_worst_size, dict_from_storage, dict_storage_size,
};
const INPUT_1: &[u8] = include_bytes!("test1.txt");
const EXPECTED_1: &[u8] = include_bytes!("test1.bin");
const INPUT_2: &[u8] = include_bytes!("test2.txt");
const EXPECTED_2: &[u8] = include_bytes!("test2.bin");
#[test]
#[cfg(feature = "alloc")]
fn test_compress() {
let dst = compress(INPUT_1).expect("Failed to compress");
assert_eq!(dst, EXPECTED_1);
}
#[test]
#[cfg(feature = "alloc")]
fn test_compress_with_dict() {
let mut dict = new_dict();
let dst = compress_with_dict(INPUT_1, &mut dict).expect("Failed to compress (1)");
assert_eq!(dst, EXPECTED_1);
// Compress a second time to test dictionary reuse
let dst = compress_with_dict(INPUT_2, &mut dict).expect("Failed to compress (2)");
assert_eq!(dst, EXPECTED_2);
}
#[test]
fn test_compress_no_alloc() {
let mut dst = [0u8; compress_worst_size(INPUT_1.len())];
let mut storage = [0u8; dict_storage_size()];
let mut dict = dict_from_storage(&mut storage);
let out_size =
compress_no_alloc(INPUT_1, &mut dst, &mut dict).expect("Failed to compress (1)");
assert_eq!(&dst[0..out_size], EXPECTED_1);
// Compress a second time to test dictionary reuse
let out_size =
compress_no_alloc(INPUT_2, &mut dst, &mut dict).expect("Failed to compress (2)");
assert_eq!(&dst[0..out_size], EXPECTED_2);
}
}

63
src/decompress.rs Normal file
View File

@ -0,0 +1,63 @@
//! # Decompression routines
//!
//! Available with feature `decompress`.
//!
//! # Examples
//!
//! Decompressing a buffer with known output size:
//! ```
//! use lzokay::decompress::decompress;
//! # #[allow(non_upper_case_globals)] const input: [u8; 10] = [0x12, 0, 0x20, 0, 0xdf, 0, 0, 0x11, 0, 0];
//! # #[allow(non_upper_case_globals)] const decompressed_size: usize = 512;
//!
//! let mut dst = vec![0u8; decompressed_size];
//! let size = decompress(&input, &mut dst)?;
//! # assert_eq!(size, decompressed_size);
//! # Ok::<(), lzokay::Error>(())
//! ```
use crate::{bindings, lzokay_result, Error};
/// Decompress `src` into `dst`.
///
/// `dst` must be large enough to hold the entire decompressed output.
pub fn decompress(src: &[u8], dst: &mut [u8]) -> Result<usize, Error> {
let mut out_size = 0usize;
let result = unsafe {
bindings::lzokay_decompress(
src.as_ptr(),
src.len(),
dst.as_mut_ptr(),
dst.len(),
&mut out_size,
)
};
lzokay_result(out_size as usize, result)
}
#[cfg(test)]
mod tests {
use crate::decompress::decompress;
const INPUT_1: &[u8] = include_bytes!("test1.bin");
const EXPECTED_1: &[u8] = include_bytes!("test1.txt");
const INPUT_2: &[u8] = include_bytes!("test2.bin");
const EXPECTED_2: &[u8] = include_bytes!("test2.txt");
const fn max(a: usize, b: usize) -> usize {
if a > b {
a
} else {
b
}
}
#[test]
fn test_decompress() {
let mut dst = [0u8; max(EXPECTED_1.len(), EXPECTED_2.len())];
let size = decompress(INPUT_1, &mut dst).expect("Failed to decompress (1)");
assert_eq!(&dst[0..size], EXPECTED_1);
let size = decompress(INPUT_2, &mut dst).expect("Failed to decompress (2)");
assert_eq!(&dst[0..size], EXPECTED_2);
}
}

127
src/lib.rs Normal file
View File

@ -0,0 +1,127 @@
#![cfg_attr(not(feature = "std"), no_std)]
//! # LZ👌-rs
//!
//! Rust wrapper for [LZ👌](https://github.com/jackoalan/lzokay), a minimal, MIT-licensed
//! implementation of the [LZO compression format](http://www.oberhumer.com/opensource/lzo/).
//!
//! See the original [README](https://github.com/jackoalan/lzokay/blob/master/README.md) for more information.
//!
//! ### Features
//!
//! - MIT-licensed
//! - Simple compression and decompression routines
//! - `#![no_std]` compatible
//!
//! ### Usage
//!
//! See the [`compress`] or [`decompress`] documentation for reference.
//!
//! In `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! lzokay = "1.0.0"
//! ```
//!
//! Or, to only enable certain features:
//!
//! ```toml
//! [dependencies.lzokay]
//! version = "1.0.0"
//! default-features = false
//! features = ["decompress", "compress"]
//! ```
//!
//! - `decompress`: Enables decompression functions.
//! - `compress`: Enables compression functions.
//! - `alloc`: Enables optional compression functions that perform heap allocation.
//! Without `std`, this uses `extern crate alloc`.
//! - `std`: Enables use of `std`. Implies `alloc`.
//!
//! All features are enabled by default.
//!
//! ### License
//!
//! LZ👌 and LZ👌-rs are available under the MIT License and have no external dependencies.
#[cfg(feature = "compress")]
pub mod compress;
#[cfg(feature = "decompress")]
pub mod decompress;
mod bindings {
#![allow(unknown_lints)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(deref_nullptr)]
#![allow(dead_code)]
#[cfg(not(feature = "std"))]
mod types {
pub type c_uchar = u8;
pub type c_ushort = u16;
pub type c_uint = u32;
pub type c_int = i32;
}
#[cfg(feature = "std")]
mod types {
pub type c_uchar = ::std::os::raw::c_uchar;
pub type c_ushort = ::std::os::raw::c_ushort;
pub type c_uint = ::std::os::raw::c_uint;
pub type c_int = ::std::os::raw::c_int;
}
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
/// Error result codes
#[derive(Debug, Eq, PartialEq)]
pub enum Error {
/// Likely indicates bad compressed LZO input.
LookbehindOverrun,
/// Output buffer was not large enough to store the compression/decompression result.
OutputOverrun,
/// Compressed input buffer is invalid or truncated.
InputOverrun,
/// Unknown error.
Error,
/// Decompression succeeded, but input buffer has remaining data.
InputNotConsumed,
}
fn lzokay_result<T>(result: T, error: bindings::lzokay_EResult) -> Result<T, Error> {
if error == bindings::lzokay_EResult_Success {
Result::Ok(result)
} else {
Result::Err(match error {
bindings::lzokay_EResult_LookbehindOverrun => Error::LookbehindOverrun,
bindings::lzokay_EResult_OutputOverrun => Error::OutputOverrun,
bindings::lzokay_EResult_InputOverrun => Error::InputOverrun,
bindings::lzokay_EResult_InputNotConsumed => Error::InputNotConsumed,
_ => Error::Error,
})
}
}
#[cfg(test)]
mod tests {
#[cfg(all(not(feature = "std"), feature = "alloc"))]
extern crate alloc;
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;
#[cfg(all(feature = "compress", feature = "alloc"))]
use super::compress::compress;
#[cfg(feature = "decompress")]
use super::decompress::decompress;
#[test]
#[cfg(all(feature = "compress", feature = "decompress", feature = "alloc"))]
fn test_round_trip() {
let src = include_bytes!("test1.txt");
let compressed = compress(src).expect("Failed to compress");
let mut dst = vec![0u8; src.len()];
decompress(&compressed, &mut dst).expect("Failed to decompress");
assert_eq!(&src[..], dst.as_slice());
}
}

BIN
src/test1.bin Normal file

Binary file not shown.

9
src/test1.txt Normal file
View File

@ -0,0 +1,9 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae laoreet nulla. Vestibulum sollicitudin magna in condimentum suscipit. Mauris consectetur semper ligula, sed suscipit elit fermentum vitae. Aliquam quis lacus tortor. In faucibus pellentesque ipsum et mattis. Mauris congue fringilla lorem, at ornare felis posuere vitae. Nam eget ligula viverra, rhoncus lectus eget, scelerisque nisl. Aliquam eget scelerisque libero. Maecenas id magna mollis, commodo tortor in, cursus orci. Mauris in rutrum sapien. Donec eget lobortis tellus. Vivamus auctor lacus id sodales varius. Ut ipsum neque, malesuada nec euismod ut, euismod id est. Pellentesque vitae tellus vel tortor vestibulum sagittis. Nullam lacinia egestas quam semper pulvinar. Vestibulum efficitur vel erat sit amet suscipit.
Donec id ligula est. Donec ut justo dolor. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam non ipsum imperdiet, condimentum lacus ac, tempus arcu. Nulla id iaculis quam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur eu pharetra nibh, luctus suscipit orci. Morbi aliquam mi neque. Praesent a blandit libero. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent in mauris rutrum, mattis augue vitae, pretium massa. Quisque sed quam mi. Praesent blandit turpis tortor, pellentesque varius neque ornare nec. Pellentesque dictum facilisis tellus, quis volutpat metus mattis vel. Nulla viverra orci mi, vitae semper nunc ornare a.
Nulla varius nisl ac eros pretium auctor ut eget mi. Maecenas in tempus felis. Morbi laoreet nisl at risus suscipit, id consectetur eros facilisis. Etiam rutrum efficitur bibendum. Nunc id metus ut mauris cursus bibendum. Quisque a dui iaculis, porta metus sed, tristique purus. Nunc at turpis elit. Aenean in rutrum lorem, eget malesuada ex. Phasellus quis tempor sapien. Sed sit amet libero nec sapien molestie sodales sit amet id quam. Ut vehicula ipsum at turpis ultricies, vel laoreet urna dignissim. Curabitur enim est, iaculis vel mi auctor, aliquam molestie ipsum. Morbi at mattis dui. Praesent id vestibulum eros, vel congue justo. Mauris ac tortor et erat vestibulum tempor sed hendrerit diam. Suspendisse potenti.
Fusce in accumsan nunc, eget suscipit mauris. Aenean dolor mauris, feugiat at lacus in, laoreet porta tellus. Etiam nisi eros, blandit nec pellentesque nec, suscipit tincidunt mi. Ut enim nisi, aliquet a posuere at, rutrum eu justo. Ut fringilla nisl arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut finibus ligula est. Pellentesque nec porta massa.
Fusce nec tempus augue. Quisque fermentum nulla velit, pharetra gravida massa eleifend eget. Etiam consectetur eget quam ut ornare. Praesent dolor eros, placerat sed est id, commodo tristique elit. Curabitur ornare nunc et odio malesuada, vel gravida mauris iaculis. Phasellus ut dui et dolor ornare molestie. Ut efficitur massa et nibh tincidunt, et malesuada velit feugiat. Praesent fringilla libero ut mi fermentum fermentum. Nulla facilisi. Sed dapibus risus non risus dapibus, ut blandit lacus ornare. Fusce velit quam, hendrerit at velit vel, sagittis consectetur ipsum. Aenean ultrices massa in libero consectetur ornare. Etiam blandit urna vel odio viverra semper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur aliquet nunc id justo mattis bibendum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.

BIN
src/test2.bin Normal file

Binary file not shown.

9
src/test2.txt Normal file
View File

@ -0,0 +1,9 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ac mollis ligula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aenean varius lorem nec facilisis commodo. Mauris et maximus neque, a tempor lectus. Vestibulum nibh sem, faucibus sed justo vel, accumsan euismod nulla. Suspendisse eu dolor condimentum, blandit mauris a, accumsan nunc. Sed cursus libero ut bibendum fringilla. Sed nulla erat, lobortis sit amet sem eget, mattis feugiat felis.
Cras rutrum maximus orci vitae mollis. Nulla convallis, sapien sed tristique malesuada, quam libero tristique ex, ac efficitur mi lacus eget lectus. Proin bibendum, turpis in ornare efficitur, arcu lectus fermentum leo, ac interdum tortor lacus a urna. Curabitur pellentesque nisi ut tincidunt pulvinar. Fusce pharetra turpis sit amet lectus tincidunt sodales. Phasellus aliquam diam sit amet velit vestibulum, ut hendrerit leo auctor. Sed interdum, velit vel gravida lacinia, tortor neque aliquet mauris, eu tempus nibh lorem non magna. Vestibulum auctor pellentesque dui et lacinia. Vivamus vel scelerisque libero. Aenean sollicitudin orci elit, vel condimentum augue ullamcorper vestibulum. Donec dignissim laoreet accumsan. Maecenas dictum finibus posuere. Nunc nec nulla nisl.
Etiam vel ultricies elit. Vestibulum interdum, ex eu blandit congue, elit enim mattis lacus, eget vestibulum libero turpis ut felis. Pellentesque et placerat lacus. Nam ac pretium purus. Nam at scelerisque magna. Aenean scelerisque mi mauris, nec sagittis mauris mollis eu. Nam feugiat nibh in odio luctus hendrerit. Ut ante velit, sagittis a malesuada nec, hendrerit rhoncus tellus. Aenean venenatis, est et tristique imperdiet, justo augue tempus elit, laoreet viverra enim neque aliquet ligula. Sed viverra purus eu velit pulvinar, quis congue massa commodo. Vivamus finibus tristique turpis et hendrerit. Pellentesque tristique consectetur turpis, sed aliquet lorem euismod nec. In porttitor elementum orci vel vehicula. Fusce non dolor quis tortor feugiat fringilla in sodales elit.
Cras molestie purus non diam mollis, eu feugiat nisi sollicitudin. Curabitur congue consequat efficitur. Sed tempus gravida tortor id placerat. Duis pretium tortor sem, non pulvinar mauris interdum et. Donec et arcu ipsum. Nunc urna est, ornare sed pellentesque non, iaculis in lacus. Fusce ullamcorper rutrum odio.
Nulla auctor, nisl molestie elementum semper, justo ligula volutpat risus, eget laoreet lectus purus ut libero. Duis in feugiat sapien. Aliquam aliquam auctor interdum. Fusce auctor lorem et iaculis vestibulum. Duis in dolor semper, accumsan ligula et, pellentesque turpis. Ut eget velit velit. Pellentesque bibendum lacus dui, vitae eleifend velit condimentum ut. Nunc semper consectetur elit.

1
wrapper.hpp Normal file
View File

@ -0,0 +1 @@
#include <lzokay.hpp>