#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);
if (dt->nestdb >= ARRAY_SIZE(dt->idb)) return -E2BIG;
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) {
dt->stored_object = 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,
};