Biblioteca Office C / FFI — Inicio Rápido
La API C de office_oxide es una ABI estable y delgada sobre el núcleo Rust. Todos los bindings de mayor nivel (Go, C#, Node.js nativo) llaman exactamente a los mismos puntos de entrada. Si tu lenguaje no tiene un wrapper listo, siempre puedes enlazar la librería C directamente.
La superficie autoritativa vive en include/office_oxide_c/office_oxide.h; esta guía cubre la misma API.
Instalación
Opción 1 — compilar desde el source Rust
git clone https://github.com/yfedoseev/office_oxide
cd office_oxide
cargo build --release --lib
La librería compartida sale en target/release/:
| OS | Archivo |
|---|---|
| Linux | liboffice_oxide.so |
| macOS | liboffice_oxide.dylib |
| Windows | office_oxide.dll (+ .lib import) |
El header está en include/office_oxide_c/office_oxide.h.
Opción 2 — instalar una librería prebuilt
install -Dm644 include/office_oxide_c/office_oxide.h /usr/local/include/office_oxide.h
install -Dm755 target/release/liboffice_oxide.so /usr/local/lib/liboffice_oxide.so
Leer un documento
#include <stdio.h>
#include <stdlib.h>
#include "office_oxide.h"
int main(void) {
int err = 0;
char *text = office_extract_text("report.docx", &err);
if (!text) {
fprintf(stderr, "office_oxide failed: code=%d\n", err);
return 1;
}
printf("%s\n", text);
office_oxide_free_string(text);
return 0;
}
Compilar y ejecutar:
cc quickstart.c -I/usr/local/include -L/usr/local/lib -loffice_oxide -o quickstart
LD_LIBRARY_PATH=/usr/local/lib ./quickstart
API principal
Info de la librería
const char *version = office_oxide_version(); // "0.1.0" — no liberar
const char *fmt = office_oxide_detect_format("f"); // "docx"/... o NULL
Document (solo lectura)
int err = 0;
OfficeDocumentHandle *doc = office_document_open("file.xlsx", &err);
if (!doc) { /* manejar err */ }
const char *fmt = office_document_format(doc); // "xlsx" — no liberar
char *text = office_document_plain_text(doc, &err);
char *md = office_document_to_markdown(doc, &err);
char *html = office_document_to_html(doc, &err);
char *ir = office_document_to_ir_json(doc, &err);
if (office_document_save_as(doc, "file.docx", &err) != 0) { /* manejar err */ }
office_oxide_free_string(text);
office_oxide_free_string(md);
office_oxide_free_string(html);
office_oxide_free_string(ir);
office_document_free(doc);
Abrir desde un buffer en memoria:
uint8_t *data = ...;
size_t len = ...;
OfficeDocumentHandle *doc =
office_document_open_from_bytes(data, len, "docx", &err);
format debe ser una de las seis cadenas: "docx" | "xlsx" | "pptx" | "doc" | "xls" | "ppt".
EditableDocument
La edición preserva todas las partes OPC sin tocar. Solo DOCX, XLSX y PPTX.
int err = 0;
OfficeEditableHandle *ed = office_editable_open("template.docx", &err);
if (!ed) { /* manejar err */ }
int64_t n = office_editable_replace_text(ed, "{{name}}", "Alice", &err);
if (n < 0) { /* manejar err */ }
printf("%lld reemplazos\n", (long long)n);
if (office_editable_save(ed, "out.docx", &err) != 0) { /* manejar err */ }
office_editable_free(ed);
Establecer celdas XLSX:
OfficeEditableHandle *wb = office_editable_open("budget.xlsx", &err);
office_editable_set_cell(wb, 0, "A1", OFFICE_CELL_STRING, "Total", 0.0, &err);
office_editable_set_cell(wb, 0, "B1", OFFICE_CELL_NUMBER, NULL, 42.5, &err);
office_editable_set_cell(wb, 0, "C1", OFFICE_CELL_BOOLEAN, NULL, 1.0, &err);
office_editable_set_cell(wb, 0, "D1", OFFICE_CELL_EMPTY, NULL, 0.0, &err);
office_editable_save(wb, "budget.xlsx", &err);
office_editable_free(wb);
Para booleanos: value_num distinto de cero significa true.
Serializar a un buffer en heap:
size_t out_len = 0;
uint8_t *buf = office_editable_save_to_bytes(ed, &out_len, &err);
if (!buf) { /* manejar err */ }
/* sube o streamea buf[0..out_len] */
office_oxide_free_bytes(buf, out_len);
Helpers de una sola llamada
char *text = office_extract_text("file.docx", &err);
char *md = office_to_markdown("file.pptx", &err);
char *html = office_to_html("file.xlsx", &err);
/* libera cada uno con office_oxide_free_string */
Reglas de memoria
- Los
char*devueltos poroffice_document_*,office_editable_*y los helpers de una sola llamada deben liberarse conoffice_oxide_free_string(ptr). - Los
uint8_t*devueltos junto con un out-parameterout_lendeben liberarse conoffice_oxide_free_bytes(ptr, len).lendebe coincidir con el valor que la API escribió enout_len. - Los handles opacos se liberan con su correspondiente
*_free(). - Los
const char*devueltos poroffice_oxide_version,office_oxide_detect_format,office_document_formatson estáticos — no liberar.
Errores
Toda llamada que pueda fallar acepta un out-parameter int *error_code:
int err = 0;
OfficeDocumentHandle *doc = office_document_open("missing.docx", &err);
if (!doc) {
switch (err) {
case OFFICE_ERR_IO: fputs("error de io\n", stderr); break;
case OFFICE_ERR_PARSE: fputs("error de parseo\n", stderr); break;
/* ... */
}
}
| Macro | Valor | Significado |
|---|---|---|
OFFICE_OK |
0 | éxito |
OFFICE_ERR_INVALID_ARG |
1 | puntero nil / cadena de formato desconocida |
OFFICE_ERR_IO |
2 | error de filesystem |
OFFICE_ERR_PARSE |
3 | documento corrupto |
OFFICE_ERR_EXTRACTION |
4 | parseo OK pero falló el render |
OFFICE_ERR_INTERNAL |
5 | bug — abre una issue |
OFFICE_ERR_UNSUPPORTED |
6 | extensión/feature no soportada |
Constantes de valor de celda
| Macro | Valor |
|---|---|
OFFICE_CELL_EMPTY |
0 |
OFFICE_CELL_STRING |
1 |
OFFICE_CELL_NUMBER |
2 |
OFFICE_CELL_BOOLEAN |
3 |
Formatos heredados
Abre con office_document_open — el formato se detecta por extensión y se verifica con magic bytes. office_document_save_as convierte heredado → OOXML de manera transparente:
OfficeDocumentHandle *doc = office_document_open("old.xls", &err);
office_document_save_as(doc, "modern.xlsx", &err);
office_document_free(doc);
Hilos
Cada handle pertenece al llamador — no compartas un único handle entre hilos. Distintos handles pueden usarse en paralelo; la librería en sí es reentrante.
C++
El header está envuelto en guardas extern "C", así que cabe directo en una unidad de traducción C++:
#include "office_oxide.h"
Combínalo con wrappers RAII (std::unique_ptr<OfficeDocumentHandle, decltype(&office_document_free)>) para que la limpieza sea exception-safe.
Solución de problemas
| Síntoma | Solución |
|---|---|
Linker: undefined reference to office_document_open |
Añade -loffice_oxide y la -L correspondiente; verifica que la librería se compiló con --release --lib. |
En runtime: error while loading shared libraries: liboffice_oxide.so |
Añade el directorio de la lib a LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (macOS), o ponla junto al exe (Windows). |
OFFICE_ERR_INVALID_ARG en open_from_bytes |
format debe ser exactamente `“docx” |
| Double-free o corrupción de heap | Cada char* liberado con office_oxide_free_string, cada buffer de bytes con office_oxide_free_bytes(ptr, len) usando el out_len original. |
office_editable_replace_text devuelve 0 en XLSX |
Comportamiento esperado — para edición de hojas usa office_editable_set_cell. |
Véase también
- Crate Rust — el núcleo subyacente
- Binding Go — usa esta misma ABI C vía cgo
- Binding C# — usa esta misma ABI C vía P/Invoke