bindle-file 0.1.0

an efficient binary archive format
Documentation
/* Auto-generated by cbindgen - do not edit manually */

#ifndef BINDLE_H
#define BINDLE_H

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

/**
 * Compression mode for entries.
 */
typedef enum BindleCompress {
  /**
   * No compression.
   */
  BindleCompressNone = 0,
  /**
   * Zstandard compression.
   */
  BindleCompressZstd = 1,
  /**
   * Automatically compress if entry is larger than 2KB threshold.
   * Note: This is never stored on disk, only used as a policy hint.
   */
  BindleCompressAuto = 2,
} BindleCompress;

/**
 * A binary archive for collecting files.
 *
 * Uses memory-mapped I/O for fast reads, supports optional zstd compression, and handles updates via shadowing.
 * Files can be added incrementally without rewriting the entire archive.
 *
 * # Example
 *
 * ```no_run
 * use bindle_file::{Bindle, Compress};
 *
 * let mut archive = Bindle::open("data.bndl")?;
 * archive.add("file.txt", b"data", Compress::None)?;
 * archive.save()?;
 * # Ok::<(), std::io::Error>(())
 * ```
 */
typedef struct Bindle Bindle;

/**
 * A streaming reader for archive entries.
 *
 * Created by the archive's `reader()` method. Automatically decompresses compressed entries and tracks CRC32 for integrity verification.
 *
 * # Example
 *
 * ```no_run
 * # use bindle_file::Bindle;
 * # let archive = Bindle::open("data.bndl")?;
 * let mut reader = archive.reader("file.txt")?;
 * std::io::copy(&mut reader, &mut std::io::stdout())?;
 * reader.verify_crc32()?;
 * # Ok::<(), std::io::Error>(())
 * ```
 */
typedef struct BindleReader BindleReader;

/**
 * A streaming writer for adding entries to an archive.
 *
 * Created by [`Bindle::writer()`]. Automatically compresses data if requested and computes CRC32 for integrity verification.
 *
 * The writer must be closed with [`close()`](Writer::close) or will be automatically closed when dropped. After closing, call [`Bindle::save()`] to commit the index.
 *
 * # Example
 *
 * ```no_run
 * use std::io::Write;
 * use bindle_file::{Bindle, Compress};
 *
 * let mut archive = Bindle::open("data.bndl")?;
 * let mut writer = archive.writer("file.txt", Compress::None)?;
 * writer.write_all(b"data")?;
 * writer.close()?;
 * archive.save()?;
 * # Ok::<(), std::io::Error>(())
 * ```
 */
typedef struct BindleWriter BindleWriter;

/**
 * Creates a new archive, overwriting any existing file.
 *
 * # Parameters
 * * `path` - NUL-terminated path to the archive file
 *
 * # Returns
 * A pointer to the Bindle handle, or NULL on error. Must be freed with `bindle_close()`.
 */
struct Bindle *bindle_create(const char *path);

/**
 * Opens an existing archive or creates a new one.
 *
 * # Parameters
 * * `path` - NUL-terminated path to the archive file
 *
 * # Returns
 * A pointer to the Bindle handle, or NULL on error. Must be freed with `bindle_close()`.
 */
struct Bindle *bindle_open(const char *path);

/**
 * Opens an existing archive. Returns NULL if the file doesn't exist.
 *
 * # Parameters
 * * `path` - NUL-terminated path to the archive file
 *
 * # Returns
 * A pointer to the Bindle handle, or NULL on error. Must be freed with `bindle_close()`.
 */
struct Bindle *bindle_load(const char *path);

/**
 * Adds data to the archive with the given name.
 *
 * # Parameters
 * * `ctx` - Bindle handle from `bindle_open()`
 * * `name` - NUL-terminated entry name
 * * `data` - Data bytes (may contain NUL bytes)
 * * `data_len` - Length of data in bytes
 * * `compress` - Compression mode (BindleCompressNone, BindleCompressZstd, or BindleCompressAuto)
 *
 * # Returns
 * True on success. Call `bindle_save()` to commit changes.
 */
bool bindle_add(struct Bindle *ctx,
                const char *name,
                const uint8_t *data,
                size_t data_len,
                enum BindleCompress compress);

/**
 * Adds a file from the filesystem to the archive.
 *
 * # Parameters
 * * `ctx` - Bindle handle from `bindle_open()`
 * * `name` - NUL-terminated entry name
 * * `path` - NUL-terminated path to file on disk
 * * `compress` - Compression mode
 *
 * # Returns
 * True on success. Call `bindle_save()` to commit changes.
 */
bool bindle_add_file(struct Bindle *ctx,
                     const char *name,
                     const char *path,
                     enum BindleCompress compress);

/**
 * Commits all pending changes to disk.
 *
 * Writes the index and footer. Must be called after add/remove operations.
 */
bool bindle_save(struct Bindle *ctx);

/**
 * Closes the archive and frees the handle.
 *
 * After calling this, the ctx pointer is no longer valid.
 */
void bindle_close(struct Bindle *ctx);

/**
 * Reads an entry from the archive, decompressing if needed.
 *
 * # Parameters
 * * `ctx_ptr` - Bindle handle
 * * `name` - NUL-terminated entry name
 * * `out_len` - Output parameter for data length
 *
 * # Returns
 * Pointer to data buffer, or NULL if not found or CRC32 check fails.
 * Must be freed with `bindle_free_buffer()`.
 */
uint8_t *bindle_read_buffer(struct Bindle *ctx_ptr, const char *name, size_t *out_len);

/**
 * Frees a buffer returned by `bindle_read()`.
 */
void bindle_free_buffer(uint8_t *ptr);

/**
 * Reads an uncompressed entry without allocating.
 *
 * Returns a pointer directly into the memory-mapped archive. Only works for uncompressed entries.
 *
 * # Parameters
 * * `ctx` - Bindle handle
 * * `name` - NUL-terminated entry name
 * * `out_len` - Output parameter for data length
 *
 * # Returns
 * Pointer into the mmap, or NULL if entry is compressed or doesn't exist.
 * The pointer is valid as long as the Bindle handle is open. Do NOT free this pointer.
 */
const uint8_t *bindle_read_uncompressed_direct(struct Bindle *ctx,
                                               const char *name,
                                               size_t *out_len);

/**
 * Returns the number of entries in the archive.
 */
size_t bindle_length(const struct Bindle *ctx);

/**
 * Returns the name of the entry at the given index as a null-terminated C string.
 *
 * Use with `bindle_length()` to iterate over all entries. The pointer is valid as long as the Bindle handle is open.
 * Do NOT free the returned pointer.
 */
const char *bindle_entry_name(const struct Bindle *ctx,
                              size_t index);

/**
 * Reclaims space by removing shadowed data.
 *
 * Rebuilds the archive with only live entries.
 */
bool bindle_vacuum(struct Bindle *ctx);

/**
 * Extracts all entries to a destination directory.
 */
bool bindle_unpack(struct Bindle *ctx, const char *dest_path);

/**
 * Recursively adds all files from a directory to the archive.
 *
 * Call `bindle_save()` to commit changes.
 */
bool bindle_pack(struct Bindle *ctx, const char *src_path, enum BindleCompress compress);

/**
 * Returns true if an entry with the given name exists.
 */
bool bindle_exists(const struct Bindle *ctx, const char *name);

/**
 * Removes an entry from the index.
 *
 * Returns true if the entry existed. Data remains in the file until `bindle_vacuum()` is called.
 * Call `bindle_save()` to commit changes.
 */
bool bindle_remove(struct Bindle *ctx, const char *name);

/**
 * Creates a streaming writer for adding an entry.
 *
 * The writer must be closed with `bindle_writer_close()`, then call `bindle_save()` to commit.
 * Do not access the Bindle handle while the writer is active.
 */
struct BindleWriter *bindle_writer_new(struct Bindle *ctx,
                                       const char *name,
                                       enum BindleCompress compress);

/**
 * Writes data to the writer.
 */
bool bindle_writer_write(struct BindleWriter *stream, const uint8_t *data, size_t len);

/**
 * Closes the writer and finalizes the entry.
 */
bool bindle_writer_close(struct BindleWriter *stream);

/**
 * Creates a streaming reader for an entry.
 *
 * Automatically decompresses if needed. Must be freed with `bindle_reader_close()`.
 * Call `bindle_reader_verify_crc32()` after reading to verify integrity.
 */
struct BindleReader *bindle_reader_new(const struct Bindle *ctx, const char *name);

/**
 * Reads data from the reader into the provided buffer.
 *
 * Returns the number of bytes read, or -1 on error. Returns 0 on EOF.
 */
ptrdiff_t bindle_reader_read(struct BindleReader *reader, uint8_t *buffer, size_t buffer_len);

/**
 * Verify the CRC32 of data read from the reader.
 * Should be called after reading all data to ensure integrity.
 * Returns true if CRC32 matches, false otherwise.
 */
bool bindle_reader_verify_crc32(const struct BindleReader *reader);

/**
 * Closes the reader and frees the handle.
 */
void bindle_reader_close(struct BindleReader *reader);

/**
 * Gets the uncompressed size of an entry by name.
 *
 * # Parameters
 * * `ctx` - Bindle handle
 * * `name` - NUL-terminated entry name
 *
 * # Returns
 * The uncompressed size in bytes, or 0 if the entry doesn't exist.
 * Note: Returns 0 for both non-existent entries and zero-length entries.
 */
size_t bindle_entry_size(const struct Bindle *ctx, const char *name);

/**
 * Gets the compression type of an entry by name.
 *
 * # Parameters
 * * `ctx` - Bindle handle
 * * `name` - NUL-terminated entry name
 *
 * # Returns
 * The Compress value (0 = None, 1 = Zstd), or 0 if the entry doesn't exist.
 */
enum BindleCompress bindle_entry_compress(const struct Bindle *ctx, const char *name);

/**
 * Reads an entry into a pre-existing buffer.
 *
 * Decompresses if needed and verifies CRC32. Reads up to `buffer_len` bytes.
 *
 * # Parameters
 * * `ctx` - Bindle handle
 * * `name` - NUL-terminated entry name
 * * `buffer` - Pre-allocated buffer to read into
 * * `buffer_len` - Maximum number of bytes to read
 *
 * # Returns
 * The number of bytes actually read, or 0 if the entry doesn't exist or CRC32 check fails.
 * If the entry is larger than `buffer_len`, only `buffer_len` bytes are read.
 */
size_t bindle_read(const struct Bindle *ctx, const char *name, uint8_t *buffer, size_t buffer_len);

#endif  /* BINDLE_H */