libreofficekit 0.2.0

Wrapper around the LibreofficeKit (LOK) C++ library
Documentation
# LibreOfficeKit

Rust library providing safe access to the LibreOfficeSDK (LOK)

This library provides functionality for:
- Converting documents between various office and non-office formats (docx, xlsx, odt, ...etc into PDF and other supported formats see [File Conversion Filter Names]https://help.libreoffice.org/latest/en-US/text/shared/guide/convertfilters.html)
- Cryptographically signing documents
- Obtaining available file filters from LibreOffice
- Obtaining LibreOffice version information
- Executing document macros
- Determine document type



> [!IMPORTANT]
>
> LibreOffice has some broken behavior in the newer versions where some process end cleanup logic causes a segmentation fault when the program exists.
>
> Versions that are not affected by this LibreOffice bug are versions 6.x with 
> the latest being 6.4.7.2, any versions newer than this seem to be affected by 
> this bug. This bug is present in all versions newer than 6.x including latest (25.2.0.0.alpha0+ as at 1 Sep 2024)
>
> You can find downloads to 6.4.7.2 on the download archives https://downloadarchive.documentfoundation.org/libreoffice/old/6.4.7.2/ but its recommended you use the latest version instead in most cases.


## Converting a file

To convert an office file format (docx, xlsx, odt, ...etc) into a PDF you can use the following code:

```rust
let office = Office::new(Office::find_install_path().unwrap()).unwrap();

let input_url = DocUrl::from_relative_path("./tests/samples/sample-docx.docx").unwrap();
let output_url = DocUrl::from_absolute_path("/tmp/test.pdf").unwrap();

let mut document = office.document_load(&input_url).unwrap();

let success = document.save_as(&output_url, "pdf", None).unwrap();

if !success {
    // ...Document conversion failed
}

// ...Do something with the file at output_url

```

> [!NOTE]
>
> You can find the full supported list of conversion formats on the LibreOffice website
> [Here]https://help.libreoffice.org/latest/en-US/text/shared/guide/convertfilters.html


## Loading a password protected file

You can load password protected office documents using the code below:

```rust
let office = Office::new(Office::find_install_path().unwrap()).unwrap();

let input_url =
    DocUrl::from_relative_path("./tests/samples/sample-docx-encrypted.docx").unwrap();
let needs_password = Rc::new(AtomicBool::new(false));

// Allow password requests
office
    .set_optional_features(OfficeOptionalFeatures::DOCUMENT_PASSWORD)
    .unwrap();

office
    .register_callback({
        // Copies of local variables to include in the callback
        let needs_password = needs_password.clone();
        let input_url = input_url.clone();

        // Callback itself
        move |office, ty, _| {
            if let CallbackType::DocumentPassword = ty {
                // Password was requested
                if needs_password.swap(true, Ordering::SeqCst) {
                    // Password we provided was incorrect, you must clear the password to prevent infinite callback loop
                    // the callback will be called until the correct password (Or None) is provided
                    office.set_document_password(&input_url, None).unwrap();
                    return;
                }

                // Provide the password
                office
                    .set_document_password(&input_url, Some("password"))
                    .unwrap();
            }
        }
    })
    .unwrap();

// Document loads
let document = office.document_load(&input_url).unwrap();

// Check Password was requested
assert!(needs_password.load(Ordering::SeqCst));

// ...Do something with document
```

> [!IMPORTANT]
>
> Ensure you always specify a `None` password on failure or if you don't have a password (and have specified the `OfficeOptionalFeatures::DOCUMENT_PASSWORD` optional feature) LibreOffice will continue to block the `document_load` call and repeatedly invoke the callback until either the correct password is given or `None` is provided

## Freeing memory

LibreOffice will accumulate buffers over time as you convert/load documents, if you are using LOK in a long running process you will want to use the `Office::trim_memory` function to free some of that memory:

```rust
let office = Office::new(Office::find_install_path().unwrap()).unwrap();

// ... Do some document loading and conversion 

office.trim_memory(2000).unwrap();
```

> [!NOTE]
> Negative number provided to `trim_memory` tells LibreOffice to re-fill its memory caches
>
> Large positive number (>=1000) encourages immediate maximum memory saving.

## Credits

The original implementation of this library was based upon https://github.com/undeflife/libreoffice-rs aiming to be more complex and cover more
use cases, to use as a backend for an Office file format conversion server.