Reimplementation of Pijul in C, for education, fun and absolutely no profit
#ifndef ANI_CHANGE_H
#define ANI_CHANGE_H

/**
 * Required headers
 *  * stdint.h
 */

#define VERSION 6
#define VERSION_NOENC 4

/**
 * A table of contents for a change, indicating where each section is, to allow
 * seeking inside a change file.
 */
struct offsets {
	uint64_t version;
	uint64_t hashed_len; /* length of hashed contents */
	uint64_t unhashed_off;
	uint64_t unhashed_len; /* length of unhashed contents */
	uint64_t contents_off;
	uint64_t contents_len; /* length of contents (uncompressed) */
	uint64_t total;	       /* contents_off + length(compressed contents) */
};

/**
 * Errors that can arise when working with change files
 */
enum error {
	/* all good */
	CHANGEFILE_OK,

	/* .change file is too short */
	CHANGEFILE_TOOSHORT,

	/* .change file length mismatch */
	CHANGEFILE_LENGTHMISMATCH,

	/* version specified in file is not supported */
	CHANGEFILE_UNSUPPORTEDVERSION,

	/* hash mismatch */
	CHANGEFILE_HASHMISMATCH,
};

enum error changefileoffsets(struct mbuf *, struct offsets *);

/* sizeof(struct offsets) */
#define OFFSETS_SIZE 56

struct authorentry {
	str key;
	str value;
};

/** An "author" is (strangely) a list of key-value pairs */
struct author {
	size_t len;
	struct authorentry *entries;
};

/**
 * A list of key-value collections (BTreeMap)
 */
struct authors {
	size_t len;
	struct author *map;
};

void authorsfree(struct authors *);

struct changeheader {
	str message;		/* the "commit" message */
	str description;	/* the other undescribed part of a change */
	str timestamp;		/* yes, as a string */
	struct authors authors; /* a list of "key"="value" collections */
};

/**
 * The parts of a given change that is blake3-hashed.
 *
 * The actual hashing happens on the serialized (w/bincode) version of this
 * struct. Decoding the 'changes' field will take quite a bit of doing, it's a
 * fairly convoluted field.
 */
struct hashed {
	uint64_t version; /* same as in offsets? here to be hashed! */
	struct changeheader header;
	struct hashlist dependencies; /* array of hashes */
	struct hashlist extraknown;   /* another array of hashes */
	uint8_t *metadata;
	struct hunklist hunks;
};

void hashedfree(struct hashed *);

/**
 * Decode the 'struct offsets' from the given fd
 *
 * Return 0 if decoding completed successfully, a negative number indicates an
 * error.
 */
int decode_offsets(int fd, struct offsets *);

/**
 * Decompress and decode the hashed parts of a .change file. The
 * struct hashed pointer argument is populated with the result.
 * 
 */
enum error change_decodehashed(u8 *, usize, u8 *, struct hashed *);

struct change {
	struct offsets offsets;
	struct hashed hashed;
	uint8_t *contents;
};

struct changeentry {
	size_t num;
	struct hash hash;
	struct change change;
};

/**
 * structure for keeping track of multiple changes
 */
struct changestore {
	char *repodir; /* absolute path to the changestore */
	size_t len;
	size_t cap;
	struct changeentry *entries;
};

void changestoreinit(struct changestore *, size_t cap, const char *);
void changestorefree(struct changestore *);

/**
 * either fetch a change that's already loaded, or load a change into
 * the changestore.
 */
struct change *changestoreget(struct changestore *, struct hash *);
int changestoreload(struct changestore *, struct hash *);

#endif