an efficient binary archive format
at main 344 lines 10 kB view raw
1/* Auto-generated by cbindgen - do not edit manually */ 2 3#ifndef BINDLE_H 4#define BINDLE_H 5 6#include <stddef.h> 7#include <stdint.h> 8#include <stdbool.h> 9 10/** 11 * Compression mode for entries. 12 */ 13typedef enum BindleCompress { 14 /** 15 * No compression. 16 */ 17 BindleCompressNone = 0, 18 /** 19 * Zstandard compression. 20 */ 21 BindleCompressZstd = 1, 22 /** 23 * Automatically compress if entry is larger than 2KB threshold. 24 * Note: This is never stored on disk, only used as a policy hint. 25 */ 26 BindleCompressAuto = 2, 27} BindleCompress; 28 29/** 30 * A binary archive for collecting files. 31 * 32 * Uses memory-mapped I/O for fast reads, supports optional zstd compression, and handles updates via shadowing. 33 * Files can be added incrementally without rewriting the entire archive. 34 * 35 * # Example 36 * 37 * ```no_run 38 * use bindle_file::{Bindle, Compress}; 39 * 40 * let mut archive = Bindle::open("data.bndl")?; 41 * archive.add("file.txt", b"data", Compress::None)?; 42 * archive.save()?; 43 * # Ok::<(), std::io::Error>(()) 44 * ``` 45 */ 46typedef struct Bindle Bindle; 47 48/** 49 * A streaming reader for archive entries. 50 * 51 * Created by the archive's `reader()` method. Automatically decompresses compressed entries and tracks CRC32 for integrity verification. 52 * 53 * # Example 54 * 55 * ```no_run 56 * # use bindle_file::Bindle; 57 * # let archive = Bindle::open("data.bndl")?; 58 * let mut reader = archive.reader("file.txt")?; 59 * std::io::copy(&mut reader, &mut std::io::stdout())?; 60 * reader.verify_crc32()?; 61 * # Ok::<(), std::io::Error>(()) 62 * ``` 63 */ 64typedef struct BindleReader BindleReader; 65 66/** 67 * A streaming writer for adding entries to an archive. 68 * 69 * Created by [`Bindle::writer()`]. Automatically compresses data if requested and computes CRC32 for integrity verification. 70 * 71 * 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. 72 * 73 * # Example 74 * 75 * ```no_run 76 * use std::io::Write; 77 * use bindle_file::{Bindle, Compress}; 78 * 79 * let mut archive = Bindle::open("data.bndl")?; 80 * let mut writer = archive.writer("file.txt", Compress::None)?; 81 * writer.write_all(b"data")?; 82 * writer.close()?; 83 * archive.save()?; 84 * # Ok::<(), std::io::Error>(()) 85 * ``` 86 */ 87typedef struct BindleWriter BindleWriter; 88 89/** 90 * Creates a new archive, overwriting any existing file. 91 * 92 * # Parameters 93 * * `path` - NUL-terminated path to the archive file 94 * 95 * # Returns 96 * A pointer to the Bindle handle, or NULL on error. Must be freed with `bindle_close()`. 97 */ 98struct Bindle *bindle_create(const char *path); 99 100/** 101 * Opens an existing archive or creates a new one. 102 * 103 * # Parameters 104 * * `path` - NUL-terminated path to the archive file 105 * 106 * # Returns 107 * A pointer to the Bindle handle, or NULL on error. Must be freed with `bindle_close()`. 108 */ 109struct Bindle *bindle_open(const char *path); 110 111/** 112 * Opens an existing archive. Returns NULL if the file doesn't exist. 113 * 114 * # Parameters 115 * * `path` - NUL-terminated path to the archive file 116 * 117 * # Returns 118 * A pointer to the Bindle handle, or NULL on error. Must be freed with `bindle_close()`. 119 */ 120struct Bindle *bindle_load(const char *path); 121 122/** 123 * Adds data to the archive with the given name. 124 * 125 * # Parameters 126 * * `ctx` - Bindle handle from `bindle_open()` 127 * * `name` - NUL-terminated entry name 128 * * `data` - Data bytes (may contain NUL bytes) 129 * * `data_len` - Length of data in bytes 130 * * `compress` - Compression mode (BindleCompressNone, BindleCompressZstd, or BindleCompressAuto) 131 * 132 * # Returns 133 * True on success. Call `bindle_save()` to commit changes. 134 */ 135bool bindle_add(struct Bindle *ctx, 136 const char *name, 137 const uint8_t *data, 138 size_t data_len, 139 enum BindleCompress compress); 140 141/** 142 * Adds a file from the filesystem to the archive. 143 * 144 * # Parameters 145 * * `ctx` - Bindle handle from `bindle_open()` 146 * * `name` - NUL-terminated entry name 147 * * `path` - NUL-terminated path to file on disk 148 * * `compress` - Compression mode 149 * 150 * # Returns 151 * True on success. Call `bindle_save()` to commit changes. 152 */ 153bool bindle_add_file(struct Bindle *ctx, 154 const char *name, 155 const char *path, 156 enum BindleCompress compress); 157 158/** 159 * Commits all pending changes to disk. 160 * 161 * Writes the index and footer. Must be called after add/remove operations. 162 */ 163bool bindle_save(struct Bindle *ctx); 164 165/** 166 * Closes the archive and frees the handle. 167 * 168 * After calling this, the ctx pointer is no longer valid. 169 */ 170void bindle_close(struct Bindle *ctx); 171 172/** 173 * Reads an entry from the archive, decompressing if needed. 174 * 175 * # Parameters 176 * * `ctx_ptr` - Bindle handle 177 * * `name` - NUL-terminated entry name 178 * * `out_len` - Output parameter for data length 179 * 180 * # Returns 181 * Pointer to data buffer, or NULL if not found or CRC32 check fails. 182 * Must be freed with `bindle_free_buffer()`. 183 */ 184uint8_t *bindle_read_buffer(struct Bindle *ctx_ptr, const char *name, size_t *out_len); 185 186/** 187 * Frees a buffer returned by `bindle_read()`. 188 */ 189void bindle_free_buffer(uint8_t *ptr); 190 191/** 192 * Reads an uncompressed entry without allocating. 193 * 194 * Returns a pointer directly into the memory-mapped archive. Only works for uncompressed entries. 195 * 196 * # Parameters 197 * * `ctx` - Bindle handle 198 * * `name` - NUL-terminated entry name 199 * * `out_len` - Output parameter for data length 200 * 201 * # Returns 202 * Pointer into the mmap, or NULL if entry is compressed or doesn't exist. 203 * The pointer is valid as long as the Bindle handle is open. Do NOT free this pointer. 204 */ 205const uint8_t *bindle_read_uncompressed_direct(struct Bindle *ctx, 206 const char *name, 207 size_t *out_len); 208 209/** 210 * Returns the number of entries in the archive. 211 */ 212size_t bindle_length(const struct Bindle *ctx); 213 214/** 215 * Returns the name of the entry at the given index as a null-terminated C string. 216 * 217 * Use with `bindle_length()` to iterate over all entries. The pointer is valid as long as the Bindle handle is open. 218 * Do NOT free the returned pointer. 219 */ 220const char *bindle_entry_name(const struct Bindle *ctx, 221 size_t index); 222 223/** 224 * Reclaims space by removing shadowed data. 225 * 226 * Rebuilds the archive with only live entries. 227 */ 228bool bindle_vacuum(struct Bindle *ctx); 229 230/** 231 * Extracts all entries to a destination directory. 232 */ 233bool bindle_unpack(struct Bindle *ctx, const char *dest_path); 234 235/** 236 * Recursively adds all files from a directory to the archive. 237 * 238 * Call `bindle_save()` to commit changes. 239 */ 240bool bindle_pack(struct Bindle *ctx, const char *src_path, enum BindleCompress compress); 241 242/** 243 * Returns true if an entry with the given name exists. 244 */ 245bool bindle_exists(const struct Bindle *ctx, const char *name); 246 247/** 248 * Removes an entry from the index. 249 * 250 * Returns true if the entry existed. Data remains in the file until `bindle_vacuum()` is called. 251 * Call `bindle_save()` to commit changes. 252 */ 253bool bindle_remove(struct Bindle *ctx, const char *name); 254 255/** 256 * Creates a streaming writer for adding an entry. 257 * 258 * The writer must be closed with `bindle_writer_close()`, then call `bindle_save()` to commit. 259 * Do not access the Bindle handle while the writer is active. 260 */ 261struct BindleWriter *bindle_writer_new(struct Bindle *ctx, 262 const char *name, 263 enum BindleCompress compress); 264 265/** 266 * Writes data to the writer. 267 */ 268bool bindle_writer_write(struct BindleWriter *stream, const uint8_t *data, size_t len); 269 270/** 271 * Closes the writer and finalizes the entry. 272 */ 273bool bindle_writer_close(struct BindleWriter *stream); 274 275/** 276 * Creates a streaming reader for an entry. 277 * 278 * Automatically decompresses if needed. Must be freed with `bindle_reader_close()`. 279 * Call `bindle_reader_verify_crc32()` after reading to verify integrity. 280 */ 281struct BindleReader *bindle_reader_new(const struct Bindle *ctx, const char *name); 282 283/** 284 * Reads data from the reader into the provided buffer. 285 * 286 * Returns the number of bytes read, or -1 on error. Returns 0 on EOF. 287 */ 288ptrdiff_t bindle_reader_read(struct BindleReader *reader, uint8_t *buffer, size_t buffer_len); 289 290/** 291 * Verify the CRC32 of data read from the reader. 292 * Should be called after reading all data to ensure integrity. 293 * Returns true if CRC32 matches, false otherwise. 294 */ 295bool bindle_reader_verify_crc32(const struct BindleReader *reader); 296 297/** 298 * Closes the reader and frees the handle. 299 */ 300void bindle_reader_close(struct BindleReader *reader); 301 302/** 303 * Gets the uncompressed size of an entry by name. 304 * 305 * # Parameters 306 * * `ctx` - Bindle handle 307 * * `name` - NUL-terminated entry name 308 * 309 * # Returns 310 * The uncompressed size in bytes, or 0 if the entry doesn't exist. 311 * Note: Returns 0 for both non-existent entries and zero-length entries. 312 */ 313size_t bindle_entry_size(const struct Bindle *ctx, const char *name); 314 315/** 316 * Gets the compression type of an entry by name. 317 * 318 * # Parameters 319 * * `ctx` - Bindle handle 320 * * `name` - NUL-terminated entry name 321 * 322 * # Returns 323 * The Compress value (0 = None, 1 = Zstd), or 0 if the entry doesn't exist. 324 */ 325enum BindleCompress bindle_entry_compress(const struct Bindle *ctx, const char *name); 326 327/** 328 * Reads an entry into a pre-existing buffer. 329 * 330 * Decompresses if needed and verifies CRC32. Reads up to `buffer_len` bytes. 331 * 332 * # Parameters 333 * * `ctx` - Bindle handle 334 * * `name` - NUL-terminated entry name 335 * * `buffer` - Pre-allocated buffer to read into 336 * * `buffer_len` - Maximum number of bytes to read 337 * 338 * # Returns 339 * The number of bytes actually read, or 0 if the entry doesn't exist or CRC32 check fails. 340 * If the entry is larger than `buffer_len`, only `buffer_len` bytes are read. 341 */ 342size_t bindle_read(const struct Bindle *ctx, const char *name, uint8_t *buffer, size_t buffer_len); 343 344#endif /* BINDLE_H */