summaryrefslogtreecommitdiff
path: root/src/adb.h
blob: 3372c07f273336ecfcfcd4e566a0289ad922c252 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#ifndef ADB_H
#define ADB_H

#include <endian.h>
#include <stdint.h>
#include <sys/types.h>
#include "apk_io.h"
#include "apk_trust.h"

struct adb;
struct adb_obj;
struct adb_verify_ctx;

typedef uint32_t adb_val_t;

#define ADB_TYPE_SPECIAL	0x00000000
#define ADB_TYPE_INT		0x10000000
#define ADB_TYPE_INT_32		0x20000000
#define ADB_TYPE_INT_64		0x30000000
#define ADB_TYPE_BLOB_8		0x80000000
#define ADB_TYPE_BLOB_16	0x90000000
#define ADB_TYPE_BLOB_32	0xa0000000
#define ADB_TYPE_ARRAY		0xd0000000
#define ADB_TYPE_OBJECT		0xe0000000
#define ADB_TYPE_ERROR		0xf0000000
#define ADB_TYPE_MASK		0xf0000000
#define ADB_VALUE_MASK		0x0fffffff
#define ADB_VAL_TYPE(x)		((le32toh(x))&ADB_TYPE_MASK)
#define ADB_VAL_VALUE(x)	((le32toh(x))&ADB_VALUE_MASK)
#define ADB_IS_ERROR(x)		(ADB_VAL_TYPE(x) == ADB_TYPE_ERROR)
#define ADB_VAL(type, val)	(htole32((type) | (val)))
#define ADB_ERROR(val)		ADB_VAL(ADB_TYPE_ERROR, val)

/* ADB_TYPE_SPECIAL */
#define ADB_VAL_NULL		0x00000000
#define ADB_VAL_TRUE		0x00000001
#define ADB_VAL_FALSE		0x00000002

#define ADB_NULL		ADB_VAL(ADB_TYPE_SPECIAL, ADB_VAL_NULL)

/* Generic */
#define ADBI_NUM_ENTRIES	0x00
#define ADBI_FIRST		0x01

/* File Header */
#define ADB_FORMAT_MAGIC	0x2e424441	// ADB.
#define ADB_SCHEMA_ANY		0
#define ADB_SCHEMA_IMPLIED	0x80000000

struct adb_file_header {
	uint32_t magic;
	uint32_t schema;
};

/* Blocks */
#define ADB_BLOCK_ALIGNMENT	8
#define ADB_BLOCK_ADB		0
#define ADB_BLOCK_SIG		1
#define ADB_BLOCK_DATA		2
#define ADB_BLOCK_DATAX		3

struct adb_block {
	uint32_t type_size;
};

static inline struct adb_block adb_block_init(uint32_t type, uint32_t length) {
	return (struct adb_block) { .type_size = htole32((type << 30) + sizeof(struct adb_block) + length)};
}
static inline uint32_t adb_block_type(struct adb_block *b) { return le32toh((b)->type_size) >> 30; }
static inline uint32_t adb_block_rawsize(struct adb_block *b) { return le32toh((b)->type_size) & 0x3fffffff; }
static inline uint32_t adb_block_size(struct adb_block *b) { return ROUND_UP(adb_block_rawsize(b), ADB_BLOCK_ALIGNMENT); }
static inline uint32_t adb_block_length(struct adb_block *b) { return adb_block_rawsize(b) - sizeof(struct adb_block); }
static inline uint32_t adb_block_padding(struct adb_block *b) { return adb_block_size(b) - adb_block_rawsize(b); }
static inline void *adb_block_payload(struct adb_block *b) { return b + 1; }
static inline apk_blob_t adb_block_blob(struct adb_block *b) {
	return APK_BLOB_PTR_LEN(adb_block_payload(b), adb_block_length(b));
}

#define ADB_MAX_SIGNATURE_LEN 2048

struct adb_hdr {
	uint8_t adb_compat_ver;
	uint8_t adb_ver;
	uint16_t reserved;
	adb_val_t root;
};

struct adb_sign_hdr {
	uint8_t sign_ver, hash_alg;
};

struct adb_sign_v0 {
	struct adb_sign_hdr hdr;
	uint8_t id[16];
	uint8_t sig[0];
};

/* Schema */
#define ADB_KIND_ADB	1
#define ADB_KIND_OBJECT	2
#define ADB_KIND_ARRAY	3
#define ADB_KIND_BLOB	4
#define ADB_KIND_INT	5

#define ADB_ARRAY_ITEM(_t) { { .kind = &(_t).kind } }
#define ADB_FIELD(_i, _n, _t) [(_i)-1] = { .name = _n, .kind = &(_t).kind }

#define ADB_OBJCMP_EXACT	0	// match all fields
#define ADB_OBJCMP_TEMPLATE	1	// match fields set on template
#define ADB_OBJCMP_INDEX	2	// match fields until first non-set one

struct adb_object_schema {
	uint8_t kind;
	uint16_t num_fields;
	uint16_t num_compare;

	apk_blob_t (*tostring)(struct adb_obj *, char *, size_t);
	int (*fromstring)(struct adb_obj *, apk_blob_t);
	void (*pre_commit)(struct adb_obj *);

	struct {
		const char *name;
		const uint8_t *kind;
	} fields[];
};

struct adb_scalar_schema {
	uint8_t kind;
	uint8_t multiline : 1;

	apk_blob_t (*tostring)(struct adb*, adb_val_t, char *, size_t);
	adb_val_t (*fromstring)(struct adb*, apk_blob_t);
	int (*compare)(struct adb*, adb_val_t, struct adb*, adb_val_t);
};

struct adb_adb_schema {
	uint8_t kind;
	uint32_t schema_id;
	const struct adb_object_schema *schema;
};

/* Database read interface */
struct adb_w_bucket {
	struct list_head node;
	struct adb_w_bucket_entry {
		uint32_t hash;
		uint32_t offs;
		uint32_t len;
	} entries[40];
};

struct adb {
	struct apk_istream *is;
	apk_blob_t adb;
	uint32_t schema;
	uint32_t num_buckets;
	size_t alloc_len;
	struct list_head *bucket;
};

struct adb_obj {
	struct adb *db;
	const struct adb_object_schema *schema;
	uint32_t num;
	adb_val_t *obj;
};

/* Container read interface */
static inline void adb_init(struct adb *db) { memset(db, 0, sizeof *db); }
int adb_free(struct adb *);
void adb_reset(struct adb *);

int adb_m_blob(struct adb *, apk_blob_t, struct apk_trust *);
int adb_m_process(struct adb *db, struct apk_istream *is, uint32_t expected_schema, struct apk_trust *trust, int (*cb)(struct adb *, struct adb_block *, struct apk_istream *));
static inline int adb_m_open(struct adb *db, struct apk_istream *is, uint32_t expected_schema, struct apk_trust *trust) {
	return adb_m_process(db, is, expected_schema, trust, 0);
}
#define adb_w_init_alloca(db, schema, num_buckets) adb_w_init_dynamic(db, schema, alloca(sizeof(struct list_head[num_buckets])), num_buckets)
#define adb_w_init_tmp(db, size) adb_w_init_static(db, alloca(size), size)
int adb_w_init_dynamic(struct adb *db, uint32_t schema, void *buckets, size_t num_buckets);
int adb_w_init_static(struct adb *db, void *buf, size_t bufsz);

/* Primitive read */
adb_val_t adb_r_root(const struct adb *);
struct adb_obj *adb_r_rootobj(struct adb *a, struct adb_obj *o, const struct adb_object_schema *);
uint32_t adb_r_int(const struct adb *, adb_val_t);
apk_blob_t adb_r_blob(const struct adb *, adb_val_t);
struct adb_obj *adb_r_obj(struct adb *, adb_val_t, struct adb_obj *o, const struct adb_object_schema *);

/* Object read */
static inline uint32_t adb_ro_num(const struct adb_obj *o) { return o->num; }
static inline uint32_t adb_ra_num(const struct adb_obj *o) { return (o->num ?: 1) - 1; }

const uint8_t *adb_ro_kind(const struct adb_obj *o, unsigned i);
adb_val_t adb_ro_val(const struct adb_obj *o, unsigned i);
uint32_t adb_ro_int(const struct adb_obj *o, unsigned i);
apk_blob_t adb_ro_blob(const struct adb_obj *o, unsigned i);
struct adb_obj *adb_ro_obj(const struct adb_obj *o, unsigned i, struct adb_obj *);
int adb_ro_cmpobj(const struct adb_obj *o1, const struct adb_obj *o2, unsigned mode);
int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i, unsigned mode);
int adb_ra_find(struct adb_obj *arr, int cur, struct adb_obj *tmpl);

/* Primitive write */
void adb_w_root(struct adb *, adb_val_t);
void adb_w_rootobj(struct adb_obj *);
adb_val_t adb_w_blob(struct adb *, apk_blob_t);
adb_val_t adb_w_int(struct adb *, uint32_t);
adb_val_t adb_w_copy(struct adb *, struct adb *, adb_val_t);
adb_val_t adb_w_adb(struct adb *, struct adb *);
adb_val_t adb_w_fromstring(struct adb *, const uint8_t *kind, apk_blob_t);

/* Object write */
#define adb_wo_alloca(o, schema, db) adb_wo_init(o, alloca(sizeof(adb_val_t[(schema)->num_fields])), schema, db)

struct adb_obj *adb_wo_init(struct adb_obj *, adb_val_t *, const struct adb_object_schema *, struct adb *);
struct adb_obj *adb_wo_init_val(struct adb_obj *, adb_val_t *, const struct adb_obj *, unsigned i);
void adb_wo_reset(struct adb_obj *);
void adb_wo_resetdb(struct adb_obj *);
adb_val_t adb_w_obj(struct adb_obj *);
adb_val_t adb_w_arr(struct adb_obj *);
int adb_wo_fromstring(struct adb_obj *o, apk_blob_t);
int adb_wo_copyobj(struct adb_obj *o, struct adb_obj *);
adb_val_t adb_wo_val(struct adb_obj *o, unsigned i, adb_val_t);
adb_val_t adb_wo_val_fromstring(struct adb_obj *o, unsigned i, apk_blob_t);
adb_val_t adb_wo_int(struct adb_obj *o, unsigned i, uint32_t);
adb_val_t adb_wo_blob(struct adb_obj *o, unsigned i, apk_blob_t);
adb_val_t adb_wo_blob_raw(struct adb_obj *o, unsigned i, apk_blob_t);
adb_val_t adb_wo_obj(struct adb_obj *o, unsigned i, struct adb_obj *);
adb_val_t adb_wo_arr(struct adb_obj *o, unsigned i, struct adb_obj *);
adb_val_t adb_wa_append(struct adb_obj *o, adb_val_t);
adb_val_t adb_wa_append_obj(struct adb_obj *o, struct adb_obj *);
adb_val_t adb_wa_append_fromstring(struct adb_obj *o, apk_blob_t);
void adb_wa_sort(struct adb_obj *);
void adb_wa_sort_unique(struct adb_obj *);

/* Schema helpers */
int adb_s_field_by_name_blob(const struct adb_object_schema *schema, apk_blob_t blob);
int adb_s_field_by_name(const struct adb_object_schema *, const char *);

/* Creation */
int adb_c_header(struct apk_ostream *os, struct adb *db);
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t);
int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is);
int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *);
int adb_c_adb(struct apk_ostream *os, struct adb *db, struct apk_trust *t);
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t);

/* Trust */
struct adb_verify_ctx {
	uint32_t calc;
	struct apk_digest sha512;
};

int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, struct apk_ostream *os);
int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, apk_blob_t sigb);

/* SAX style event based handling of ADB */

struct adb_db_schema {
	unsigned long magic;
	const struct adb_object_schema *root;
};

struct adb_walk;
struct adb_walk_ops {
	int (*schema)(struct adb_walk *, uint32_t schema_id);
	int (*comment)(struct adb_walk *, apk_blob_t comment);
	int (*start_array)(struct adb_walk *, unsigned int num_items);
	int (*start_object)(struct adb_walk *);
	int (*end)(struct adb_walk *);
	int (*key)(struct adb_walk *, apk_blob_t key_name);
	int (*scalar)(struct adb_walk *, apk_blob_t scalar, int multiline);
};

extern const struct adb_walk_ops adb_walk_gentext_ops, adb_walk_genadb_ops;

struct adb_walk {
	const struct adb_walk_ops *ops;
	const struct adb_db_schema *schemas;
};

struct adb_walk_gentext {
	struct adb_walk d;
	FILE *out;
	int nest;
	int line_started : 1;
	int key_printed : 1;
};

#define ADB_WALK_GENADB_MAX_IDB		2
#define ADB_WALK_GENADB_MAX_NESTING	32
#define ADB_WALK_GENADB_MAX_VALUES	100000

struct adb_walk_genadb {
	struct adb_walk d;
	struct adb db;
	adb_val_t stored_object;
	struct adb idb[ADB_WALK_GENADB_MAX_IDB];
	int nest, nestdb, num_vals;
	struct adb_obj objs[ADB_WALK_GENADB_MAX_NESTING];
	unsigned int curkey[ADB_WALK_GENADB_MAX_NESTING];
	adb_val_t vals[ADB_WALK_GENADB_MAX_VALUES];
};

int adb_walk_adb(struct adb_walk *d, struct apk_istream *is, struct apk_trust *trust);
int adb_walk_text(struct adb_walk *d, struct apk_istream *is);

// Seamless compression support

typedef unsigned int adb_comp_t;

#define ADB_COMP_NONE		0
#define ADB_COMP_DEFLATE	1

struct apk_istream *adb_decompress(struct apk_istream *is, adb_comp_t *compression);
struct apk_ostream *adb_compress(struct apk_ostream *os, adb_comp_t compression);

#endif