an efficient binary archive format
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 */