summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/adb.c38
-rw-r--r--src/adb.h19
-rw-r--r--src/adb_walk_adb.c14
-rw-r--r--src/adb_walk_genadb.c138
-rw-r--r--src/adb_walk_gentext.c1
-rw-r--r--src/adb_walk_istream.c131
-rw-r--r--src/apk_adb.c41
-rw-r--r--src/apk_blob.h1
-rw-r--r--src/apk_io.h1
-rw-r--r--src/apk_print.h1
-rw-r--r--src/app_adbdump.c34
-rw-r--r--src/blob.c6
-rw-r--r--src/meson.build2
-rw-r--r--src/print.c11
14 files changed, 430 insertions, 8 deletions
diff --git a/src/adb.c b/src/adb.c
index e86e243..b33799c 100644
--- a/src/adb.c
+++ b/src/adb.c
@@ -252,6 +252,14 @@ struct adb_obj *adb_r_rootobj(struct adb *db, struct adb_obj *obj, const struct
return adb_r_obj(db, adb_r_root(db), obj, schema);
}
+const uint8_t *adb_ro_kind(const struct adb_obj *o, unsigned i)
+{
+ if (o->schema->kind == ADB_KIND_ADB ||
+ o->schema->kind == ADB_KIND_ARRAY)
+ i = 1;
+ return o->schema->fields[i-1].kind;
+}
+
adb_val_t adb_ro_val(const struct adb_obj *o, unsigned i)
{
if (i >= o->num) return ADB_NULL;
@@ -593,6 +601,7 @@ adb_val_t adb_w_fromstring(struct adb *db, const uint8_t *kind, apk_blob_t val)
struct adb_obj obj;
struct adb_object_schema *schema = container_of(kind, struct adb_object_schema, kind);
adb_wo_alloca(&obj, schema, db);
+ if (!schema->fromstring) return ADB_ERROR(EAPKDBFORMAT);
r = schema->fromstring(&obj, val);
if (r) return ADB_ERROR(r);
return adb_w_obj(&obj);
@@ -618,6 +627,25 @@ struct adb_obj *adb_wo_init(struct adb_obj *o, adb_val_t *p, const struct adb_ob
return o;
}
+struct adb_obj *adb_wo_init_val(struct adb_obj *o, adb_val_t *p, const struct adb_obj *parent, unsigned i)
+{
+ const uint8_t *kind = adb_ro_kind(parent, i);
+ const struct adb_object_schema *schema = 0;
+ switch (*kind) {
+ case ADB_KIND_OBJECT:
+ case ADB_KIND_ARRAY:
+ schema = container_of(kind, struct adb_object_schema, kind);
+ break;
+ case ADB_KIND_ADB:
+ schema = container_of(kind, struct adb_adb_schema, kind)->schema;
+ break;
+ default:
+ assert(1);
+ }
+
+ return adb_wo_init(o, p, schema, parent->db);
+}
+
void adb_wo_reset(struct adb_obj *o)
{
uint32_t max = o->obj[ADBI_NUM_ENTRIES];
@@ -765,9 +793,17 @@ void adb_wa_sort_unique(struct adb_obj *arr)
}
/* Schema helpers */
+int adb_s_field_by_name_blob(const struct adb_object_schema *schema, apk_blob_t blob)
+{
+ for (int i = 0; i < schema->num_fields-1 && schema->fields[i].name; i++)
+ if (apk_blob_compare(APK_BLOB_STR(schema->fields[i].name), blob) == 0)
+ return i + 1;
+ return 0;
+}
+
int adb_s_field_by_name(const struct adb_object_schema *schema, const char *name)
{
- for (int i = 0; i < schema->num_fields; i++)
+ for (int i = 0; i < schema->num_fields-1 && schema->fields[i].name; i++)
if (strcmp(schema->fields[i].name, name) == 0)
return i + 1;
return 0;
diff --git a/src/adb.h b/src/adb.h
index cf3da69..10b46ac 100644
--- a/src/adb.h
+++ b/src/adb.h
@@ -172,6 +172,7 @@ struct adb_obj *adb_r_obj(struct adb *, adb_val_t, struct adb_obj *o, const stru
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);
@@ -192,6 +193,7 @@ adb_val_t adb_w_fromstring(struct adb *, const uint8_t *kind, apk_blob_t);
#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 *);
@@ -210,6 +212,7 @@ 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 */
@@ -254,7 +257,7 @@ struct adb_walk_ops {
int (*scalar)(struct adb_walk *, apk_blob_t scalar, int multiline);
};
-extern const struct adb_walk_ops adb_walk_gentext_ops;
+extern const struct adb_walk_ops adb_walk_gentext_ops, adb_walk_genadb_ops;
struct adb_walk {
const struct adb_walk_ops *ops;
@@ -269,6 +272,20 @@ struct adb_walk_gentext {
int key_printed : 1;
};
+#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;
+ struct adb idb[2];
+ 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 adb *db, struct apk_trust *trust);
+int adb_walk_istream(struct adb_walk *d, struct apk_istream *is);
#endif
diff --git a/src/adb_walk_adb.c b/src/adb_walk_adb.c
index 713d5a7..4f99d85 100644
--- a/src/adb_walk_adb.c
+++ b/src/adb_walk_adb.c
@@ -51,10 +51,15 @@ static int dump_item(struct adb_walk_ctx *ctx, const char *name, const uint8_t *
d->ops->end(d);
ctx->db = origdb;
break;
- case ADB_KIND_OBJECT:
- d->ops->start_object(d);
- dump_object(ctx, container_of(kind, struct adb_object_schema, kind), v);
- d->ops->end(d);
+ case ADB_KIND_OBJECT:;
+ struct adb_object_schema *object = container_of(kind, struct adb_object_schema, kind);
+ if (!object->tostring) {
+ d->ops->start_object(d);
+ dump_object(ctx, object, v);
+ d->ops->end(d);
+ } else {
+ dump_object(ctx, object, v);
+ }
break;
case ADB_KIND_BLOB:
case ADB_KIND_INT:;
@@ -162,5 +167,6 @@ int adb_walk_adb(struct adb_walk *d, struct adb *db, struct apk_trust *trust)
.db = db,
.trust = trust,
};
+ d->ops->schema(d, db->hdr.schema);
return dump_adb(&ctx);
}
diff --git a/src/adb_walk_genadb.c b/src/adb_walk_genadb.c
new file mode 100644
index 0000000..a15aa82
--- /dev/null
+++ b/src/adb_walk_genadb.c
@@ -0,0 +1,138 @@
+#include <errno.h>
+#include "adb.h"
+#include "apk_print.h"
+
+static int adb_walk_genadb_schema(struct adb_walk *d, uint32_t schema_id)
+{
+ struct adb_walk_genadb *dt = container_of(d, struct adb_walk_genadb, d);
+ const struct adb_db_schema *s;
+
+ dt->db.hdr.schema = htole32(schema_id);
+ for (s = d->schemas; s->magic; s++)
+ if (s->magic == schema_id) break;
+ if (!s) return -EAPKDBFORMAT;
+
+ adb_wo_init(&dt->objs[0], &dt->vals[0], s->root, &dt->db);
+ dt->num_vals += s->root->num_fields;
+ if (dt->num_vals >= ARRAY_SIZE(dt->vals)) return -E2BIG;
+ dt->nest = 0;
+
+ return 0;
+}
+
+static int adb_walk_genadb_comment(struct adb_walk *d, apk_blob_t comment)
+{
+ return 0;
+}
+
+static int adb_walk_genadb_start_object(struct adb_walk *d)
+{
+ struct adb_walk_genadb *dt = container_of(d, struct adb_walk_genadb, d);
+
+ if (!dt->db.hdr.schema) return -EAPKDBFORMAT;
+ if (dt->nest >= ARRAY_SIZE(dt->objs)) return -EAPKDBFORMAT;
+
+ if (dt->curkey[dt->nest] == 0 &&
+ dt->objs[dt->nest].schema->kind == ADB_KIND_OBJECT)
+ return -EAPKDBFORMAT;
+
+ dt->nest++;
+ adb_wo_init_val(
+ &dt->objs[dt->nest], &dt->vals[dt->num_vals],
+ &dt->objs[dt->nest-1], dt->curkey[dt->nest-1]);
+
+ if (*adb_ro_kind(&dt->objs[dt->nest-1], dt->curkey[dt->nest-1]) == ADB_KIND_ADB) {
+ struct adb_adb_schema *schema = container_of(&dt->objs[dt->nest-1].schema->kind, struct adb_adb_schema, kind);
+ adb_reset(&dt->idb[dt->nestdb]);
+ dt->idb[dt->nestdb].hdr.schema = htole32(schema->schema_id);
+ dt->objs[dt->nest].db = &dt->idb[dt->nestdb];
+ dt->nestdb++;
+ }
+
+ dt->num_vals += dt->objs[dt->nest].schema->num_fields;
+ if (dt->num_vals >= ARRAY_SIZE(dt->vals)) return -E2BIG;
+
+ return 0;
+}
+
+static int adb_walk_genadb_start_array(struct adb_walk *d, unsigned int num)
+{
+ return adb_walk_genadb_start_object(d);
+}
+
+static int adb_walk_genadb_end(struct adb_walk *d)
+{
+ struct adb_walk_genadb *dt = container_of(d, struct adb_walk_genadb, d);
+ adb_val_t val;
+
+ val = adb_w_obj(&dt->objs[dt->nest]);
+ if (ADB_IS_ERROR(val))
+ return -ADB_VAL_VALUE(val);
+
+ dt->curkey[dt->nest] = 0;
+ dt->num_vals -= dt->objs[dt->nest].schema->num_fields;
+
+ if (dt->nest == 0) {
+ adb_w_root(&dt->db, val);
+ return 0;
+ }
+
+ dt->nest--;
+
+ if (*adb_ro_kind(&dt->objs[dt->nest], dt->curkey[dt->nest]) == ADB_KIND_ADB) {
+ dt->nestdb--;
+ adb_w_root(&dt->idb[dt->nestdb], val);
+ val = adb_w_adb(&dt->db, &dt->idb[dt->nestdb]);
+ }
+
+ if (dt->curkey[dt->nest] == 0) {
+ adb_wa_append(&dt->objs[dt->nest], val);
+ } else {
+ adb_wo_val(&dt->objs[dt->nest], dt->curkey[dt->nest], val);
+ dt->curkey[dt->nest] = 0;
+ }
+
+ return 0;
+}
+
+static int adb_walk_genadb_key(struct adb_walk *d, apk_blob_t key)
+{
+ struct adb_walk_genadb *dt = container_of(d, struct adb_walk_genadb, d);
+ uint8_t kind = dt->objs[dt->nest].schema->kind;
+
+ if (kind != ADB_KIND_OBJECT && kind != ADB_KIND_ADB)
+ return -EAPKDBFORMAT;
+
+ dt->curkey[dt->nest] = adb_s_field_by_name_blob(dt->objs[dt->nest].schema, key);
+ if (dt->curkey[dt->nest] == 0)
+ return -EAPKDBFORMAT;
+
+ return 0;
+}
+
+static int adb_walk_genadb_scalar(struct adb_walk *d, apk_blob_t scalar, int multiline)
+{
+ struct adb_walk_genadb *dt = container_of(d, struct adb_walk_genadb, d);
+
+ if (dt->objs[dt->nest].schema->kind == ADB_KIND_ARRAY) {
+ adb_wa_append_fromstring(&dt->objs[dt->nest], scalar);
+ } else {
+ if (dt->curkey[dt->nest] == 0)
+ adb_wo_fromstring(&dt->objs[dt->nest], scalar);
+ else
+ adb_wo_val_fromstring(&dt->objs[dt->nest], dt->curkey[dt->nest], scalar);
+ }
+ dt->curkey[dt->nest] = 0;
+
+ return 0;
+}
+
+const struct adb_walk_ops adb_walk_genadb_ops = {
+ .schema = adb_walk_genadb_schema,
+ .comment = adb_walk_genadb_comment,
+ .start_array = adb_walk_genadb_start_array,
+ .start_object = adb_walk_genadb_start_object,
+ .end = adb_walk_genadb_end,
+ .key = adb_walk_genadb_key,
+ .scalar = adb_walk_genadb_scalar,
+};
diff --git a/src/adb_walk_gentext.c b/src/adb_walk_gentext.c
index 995dda3..477cacd 100644
--- a/src/adb_walk_gentext.c
+++ b/src/adb_walk_gentext.c
@@ -111,6 +111,7 @@ static int adb_walk_gentext_scalar(struct adb_walk *d, apk_blob_t scalar, int mu
fprintf(out, "|\n");
adb_walk_gentext_newline(dt);
+
dt->nest++;
while (apk_blob_split(scalar, nl, &l, &scalar)) {
adb_walk_gentext_indent(dt);
diff --git a/src/adb_walk_istream.c b/src/adb_walk_istream.c
new file mode 100644
index 0000000..b85565f
--- /dev/null
+++ b/src/adb_walk_istream.c
@@ -0,0 +1,131 @@
+#include <errno.h>
+#include "adb.h"
+
+//#define DEBUG_PRINT
+#ifdef DEBUG_PRINT
+#include <stdio.h>
+#define dbg_printf(args...) fprintf(stderr, args)
+#else
+#define dbg_printf(args...)
+#endif
+
+int adb_walk_istream(struct adb_walk *d, struct apk_istream *is)
+{
+ const apk_blob_t token = APK_BLOB_STR("\n");
+ const apk_blob_t comment = APK_BLOB_STR(" #");
+ const apk_blob_t key_sep = APK_BLOB_STR(": ");
+ char mblockdata[1024*4];
+ apk_blob_t l, comm, mblock = APK_BLOB_BUF(mblockdata);
+ int r = 0, i, multi_line = 0, nesting = 0, new_item = 0;
+ uint8_t started[64] = {0};
+
+ if (IS_ERR_OR_NULL(is)) return PTR_ERR(is);
+ l = apk_istream_get_delim(is, token);
+ apk_blob_pull_blob_match(&l, APK_BLOB_STR("#%SCHEMA: "));
+ if ((r = d->ops->schema(d, apk_blob_pull_uint(&l, 16))) != 0) goto err;
+
+ started[0] = 1;
+ while (!APK_BLOB_IS_NULL(l = apk_istream_get_delim(is, token))) {
+ for (i = 0; l.len >= 2 && l.ptr[0] == ' ' && l.ptr[1] == ' '; i++, l.ptr += 2, l.len -= 2)
+ if (multi_line && i >= multi_line) break;
+
+ for (; nesting > i; nesting--) {
+ if (multi_line) {
+ apk_blob_t data = apk_blob_pushed(APK_BLOB_BUF(mblockdata), mblock);
+ if (APK_BLOB_IS_NULL(data)) {
+ r = -E2BIG;
+ goto err;
+ }
+ if (data.len && data.ptr[data.len-1] == '\n') data.len--;
+ dbg_printf("Multiline-Scalar >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(data));
+ if ((r = d->ops->scalar(d, data, 1)) != 0) goto err;
+ mblock = APK_BLOB_BUF(mblockdata);
+ multi_line = 0;
+ }
+ if (started[nesting]) {
+ dbg_printf("End %d\n", nesting);
+ if ((r = d->ops->end(d)) != 0) goto err;
+ }
+ }
+ if (l.ptr[0] == '-' && l.ptr[1] == ' ') {
+ l.ptr += 2, l.len -= 2;
+ if (!started[nesting]) {
+ dbg_printf("Array %d\n", nesting);
+ if ((r = d->ops->start_array(d, 0)) != 0) goto err;
+ started[nesting] = 1;
+ }
+ new_item = 1;
+ }
+ dbg_printf(" >%d/%d< >"BLOB_FMT"<\n", nesting, i, BLOB_PRINTF(l));
+
+ if (multi_line) {
+ dbg_printf("Scalar-Block:>%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(l));
+ apk_blob_push_blob(&mblock, l);
+ apk_blob_push_blob(&mblock, APK_BLOB_STR("\n"));
+ new_item = 0;
+ continue;
+ }
+
+ if (l.ptr[0] == '#') {
+ if ((r = d->ops->comment(d, l)) != 0) goto err;
+ continue;
+ }
+
+ // contains ' #' -> comment
+ if (!apk_blob_split(l, comment, &l, &comm))
+ comm.len = 0;
+
+ if (l.len) {
+ apk_blob_t key = APK_BLOB_NULL, scalar = APK_BLOB_NULL;
+ int start = 0;
+
+ if (apk_blob_split(l, key_sep, &key, &scalar)) {
+ // contains ': ' -> key + scalar
+ } else if (l.ptr[l.len-1] == ':') {
+ // ends ':' -> key + indented object/array
+ key = APK_BLOB_PTR_LEN(l.ptr, l.len-1);
+ start = 1;
+ } else {
+ scalar = l;
+ }
+ if (key.len) {
+ if (new_item) {
+ started[++nesting] = 0;
+ dbg_printf("Array-Object %d\n", nesting);
+ }
+ if (!started[nesting]) {
+ dbg_printf("Object %d\n", nesting);
+ if ((r = d->ops->start_object(d)) != 0) goto err;
+ started[nesting] = 1;
+ }
+ dbg_printf("Key >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(key));
+ if ((r = d->ops->key(d, key)) != 0) goto err;
+ if (start) started[++nesting] = 0;
+ }
+
+ if (scalar.len) {
+ if (scalar.ptr[0] == '|') {
+ dbg_printf("Scalar-block >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(scalar));
+ // scalar '|' -> starts string literal block
+ started[++nesting] = 0;
+ multi_line = nesting;
+ } else {
+ dbg_printf("Scalar >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(scalar));
+ if ((r = d->ops->scalar(d, scalar, 0)) != 0) goto err;
+ }
+ }
+ new_item = 0;
+ }
+
+ if (comm.len) {
+ if ((r = d->ops->comment(d, comm)) != 0) goto err;
+ }
+
+ //fprintf(stderr, ">%d> "BLOB_FMT"\n", indent, BLOB_PRINTF(l));
+ }
+ d->ops->end(d);
+
+err:
+ if (r) apk_istream_error(is, r);
+ return apk_istream_close(is);
+}
diff --git a/src/apk_adb.c b/src/apk_adb.c
index 0e08848..0785455 100644
--- a/src/apk_adb.c
+++ b/src/apk_adb.c
@@ -146,9 +146,27 @@ static apk_blob_t hexblob_tostring(struct adb *db, adb_val_t val, char *buf, siz
return APK_BLOB_PTR_LEN(buf, snprintf(buf, bufsz, "(%ld bytes)", b.len));
}
+static adb_val_t hexblob_fromstring(struct adb *db, apk_blob_t val)
+{
+ char buf[256];
+
+ if (val.len & 1)
+ return ADB_ERROR(EINVAL);
+ if (val.len > sizeof buf)
+ return ADB_ERROR(E2BIG);
+
+ apk_blob_t b = APK_BLOB_PTR_LEN(buf, val.len / 2);
+ apk_blob_pull_hexdump(&val, b);
+ if (APK_BLOB_IS_NULL(val))
+ return ADB_ERROR(EINVAL);
+
+ return adb_w_blob(db, b);
+}
+
static struct adb_scalar_schema scalar_hexblob = {
.kind = ADB_KIND_BLOB,
.tostring = hexblob_tostring,
+ .fromstring = hexblob_fromstring,
};
static apk_blob_t int_tostring(struct adb *db, adb_val_t val, char *buf, size_t bufsz)
@@ -184,9 +202,17 @@ static apk_blob_t oct_tostring(struct adb *db, adb_val_t val, char *buf, size_t
return APK_BLOB_PTR_LEN(buf, snprintf(buf, bufsz, "%o", adb_r_int(db, val)));
}
+static adb_val_t oct_fromstring(struct adb *db, apk_blob_t val)
+{
+ uint32_t n = apk_blob_pull_uint(&val, 8);
+ if (val.len) return ADB_ERROR(EINVAL);
+ return adb_w_int(db, n) ?: ADB_VAL_NULL;
+}
+
static struct adb_scalar_schema scalar_oct = {
.kind = ADB_KIND_INT,
.tostring = oct_tostring,
+ .fromstring = oct_fromstring,
};
static apk_blob_t hsize_tostring(struct adb *db, adb_val_t val, char *buf, size_t bufsz)
@@ -197,10 +223,23 @@ static apk_blob_t hsize_tostring(struct adb *db, adb_val_t val, char *buf, size_
return APK_BLOB_PTR_LEN(buf, snprintf(buf, bufsz, "%jd %s", (intmax_t)v, unit));
}
+static adb_val_t hsize_fromstring(struct adb *db, apk_blob_t val)
+{
+ apk_blob_t l, r;
+
+ if (!apk_blob_split(val, APK_BLOB_STR(" "), &l, &r))
+ return int_fromstring(db, val);
+
+ uint64_t n = apk_blob_pull_uint(&l, 10);
+ int sz = apk_get_human_size_unit(r);
+ n *= sz;
+ return adb_w_int(db, n);
+}
+
static struct adb_scalar_schema scalar_hsize = {
.kind = ADB_KIND_INT,
.tostring = hsize_tostring,
- .fromstring = int_fromstring,
+ .fromstring = hsize_fromstring,
.compare = int_compare,
};
diff --git a/src/apk_blob.h b/src/apk_blob.h
index 9426721..e222739 100644
--- a/src/apk_blob.h
+++ b/src/apk_blob.h
@@ -97,6 +97,7 @@ unsigned long apk_blob_hash_seed(apk_blob_t, unsigned long seed);
unsigned long apk_blob_hash(apk_blob_t str);
int apk_blob_compare(apk_blob_t a, apk_blob_t b);
int apk_blob_sort(apk_blob_t a, apk_blob_t b);
+int apk_blob_starts_with(apk_blob_t a, apk_blob_t b);
int apk_blob_ends_with(apk_blob_t str, apk_blob_t suffix);
int apk_blob_for_each_segment(apk_blob_t blob, const char *split,
apk_blob_cb cb, void *ctx);
diff --git a/src/apk_io.h b/src/apk_io.h
index eafb12f..8a243ac 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -81,6 +81,7 @@ struct apk_istream *apk_istream_from_file(int atfd, const char *file);
struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file);
struct apk_istream *apk_istream_from_fd(int fd);
struct apk_istream *apk_istream_from_fd_url_if_modified(int atfd, const char *url, time_t since);
+static inline int apk_istream_error(struct apk_istream *is, int err) { if (!is->err) is->err = err; return err; }
ssize_t apk_istream_read(struct apk_istream *is, void *ptr, size_t size);
apk_blob_t apk_istream_get(struct apk_istream *is, size_t len);
apk_blob_t apk_istream_get_max(struct apk_istream *is, size_t size);
diff --git a/src/apk_print.h b/src/apk_print.h
index 132fd8c..a8e734a 100644
--- a/src/apk_print.h
+++ b/src/apk_print.h
@@ -13,6 +13,7 @@
#include "apk_blob.h"
const char *apk_error_str(int error);
+int apk_get_human_size_unit(apk_blob_t b);
const char *apk_get_human_size(off_t size, off_t *dest);
struct apk_url_print {
diff --git a/src/app_adbdump.c b/src/app_adbdump.c
index 5020314..958c90f 100644
--- a/src/app_adbdump.c
+++ b/src/app_adbdump.c
@@ -53,3 +53,37 @@ static struct apk_applet apk_adbdump = {
};
APK_DEFINE_APPLET(apk_adbdump);
+
+static int adbgen_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
+{
+ struct apk_out *out = &ac->out;
+ char **arg;
+ int r;
+ struct adb_walk_genadb genadb = {
+ .d.ops = &adb_walk_genadb_ops,
+ .d.schemas = dbschemas,
+ };
+
+ adb_w_init_alloca(&genadb.db, 0, 1000);
+ adb_w_init_alloca(&genadb.idb[0], 0, 100);
+ foreach_array_item(arg, args) {
+ adb_reset(&genadb.db);
+ r = adb_walk_istream(&genadb.d, apk_istream_from_file(AT_FDCWD, *arg));
+ if (!r) {
+ r = adb_c_create(apk_ostream_to_fd(STDOUT_FILENO), &genadb.db,
+ apk_ctx_get_trust(ac));
+ }
+ adb_free(&genadb.db);
+ adb_free(&genadb.idb[0]);
+ if (r) apk_err(out, "%s: %s", *arg, apk_error_str(r));
+ }
+
+ return 0;
+}
+
+static struct apk_applet apk_adbgen = {
+ .name = "adbgen",
+ .main = adbgen_main,
+};
+APK_DEFINE_APPLET(apk_adbgen);
+
diff --git a/src/blob.c b/src/blob.c
index aa7ca83..32cd92e 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -263,6 +263,12 @@ int apk_blob_sort(apk_blob_t a, apk_blob_t b)
return a.len - b.len;
}
+int apk_blob_starts_with(apk_blob_t a, apk_blob_t b)
+{
+ if (a.len < b.len) return 0;
+ return memcmp(a.ptr, b.ptr, b.len) == 0;
+}
+
int apk_blob_ends_with(apk_blob_t a, apk_blob_t b)
{
if (a.len < b.len) return 0;
diff --git a/src/meson.build b/src/meson.build
index 43f6c38..6c5f6ca 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -2,7 +2,9 @@ libapk_so_version = '2.99.0'
libapk_src = [
'adb.c',
'adb_walk_adb.c',
+ 'adb_walk_genadb.c',
'adb_walk_gentext.c',
+ 'adb_walk_istream.c',
'apk_adb.c',
'atom.c',
'blob.c',
diff --git a/src/print.c b/src/print.c
index 0203cbb..26e31e2 100644
--- a/src/print.c
+++ b/src/print.c
@@ -65,9 +65,18 @@ const char *apk_error_str(int error)
}
}
+static const char *size_units[] = {"B", "KiB", "MiB", "GiB", "TiB"};
+
+int apk_get_human_size_unit(apk_blob_t b)
+{
+ for (int i = 0, s = 1; i < ARRAY_SIZE(size_units); i++, s *= 1024)
+ if (apk_blob_compare(b, APK_BLOB_STR(size_units[i])) == 0)
+ return s;
+ return 1;
+}
+
const char *apk_get_human_size(off_t size, off_t *dest)
{
- static const char *size_units[] = {"B", "KiB", "MiB", "GiB", "TiB"};
size_t i;
off_t s;