#include "manifest.h" #include #include #include #include static const char *value_id_names[] = { [ROPKG_MANIFEST_VALUE_N_NAME] = "Name", [ROPKG_MANIFEST_VALUE_N_ARCHITECTURE] = "Architecture", [ROPKG_MANIFEST_VALUE_N_VERSION] = "Version", [ROPKG_MANIFEST_VALUE_N_PRIORITY] = "Priority", [ROPKG_MANIFEST_VALUE_N_CATEGORY] = "Category", [ROPKG_MANIFEST_VALUE_N_MAINTAINER] = "Maintainer", [ROPKG_MANIFEST_VALUE_N_PROVIDES] = "Provides", [ROPKG_MANIFEST_VALUE_N_DEPENDS] = "Depends", [ROPKG_MANIFEST_VALUE_N_RECOMMENDS] = "Recommends", [ROPKG_MANIFEST_VALUE_N_SUGGESTS] = "Suggests", [ROPKG_MANIFEST_VALUE_N_CONFLICTS] = "Conflicts", [ROPKG_MANIFEST_VALUE_N_ENHANCES] = "Enhances", [ROPKG_MANIFEST_VALUE_N_INSTALLED_SIZE] = "Installed-Size", [ROPKG_MANIFEST_VALUE_N_DESCRIPTION] = "Description", }; static const size_t nr_value_id_names = sizeof value_id_names / sizeof value_id_names[0]; static enum ropkg_manifest_value_id value_id_from_string(const char *s) { for (size_t i = 0; i < nr_value_id_names; i++) { const char *name = value_id_names[i]; if (name && !strcmp(name, s)) { return i; } } return ROPKG_MANIFEST_VALUE_N_NONE; } enum ropkg_status ropkg_manifest_create(struct ropkg_manifest **out) { struct ropkg_manifest *manifest = malloc(sizeof *manifest); if (!manifest) { return ROPKG_ERR_NO_MEMORY; } memset(manifest, 0x0, sizeof *manifest); *out = manifest; return ROPKG_SUCCESS; } void ropkg_manifest_destroy(struct ropkg_manifest *manifest) { b_queue_entry *entry = b_queue_pop_back(&manifest->m_values); while (entry) { struct ropkg_manifest_value *value = b_unbox(struct ropkg_manifest_value, entry, v_entry); ropkg_manifest_value_destroy(value); entry = b_queue_pop_back(&manifest->m_values); } free(manifest); } static b_result create_manifest_value( b_string *name, b_string *value, struct ropkg_manifest_value **out) { const char *name_cstr = b_string_ptr(name); enum ropkg_manifest_value_id id = value_id_from_string(name_cstr); const char *value_cstr = b_string_ptr(value); char *ep; size_t v = strtoull(value_cstr, &ep, 10); struct ropkg_manifest_value *result = NULL; enum ropkg_status status = ROPKG_SUCCESS; if (*ep == 0) { if (id != ROPKG_MANIFEST_VALUE_N_NONE) { status = ropkg_manifest_value_create_int_with_id( v, id, &result); } else { status = ropkg_manifest_value_create_int_with_name( v, name_cstr, &result); } } else { if (id != ROPKG_MANIFEST_VALUE_N_NONE) { status = ropkg_manifest_value_create_string_with_id( value_cstr, id, &result); } else { status = ropkg_manifest_value_create_string_with_name( value_cstr, name_cstr, &result); } } if (status != ROPKG_SUCCESS) { return b_error_with_code(ROPKG_ERROR_VENDOR, status); } *out = result; return B_RESULT_SUCCESS; } b_result ropkg_manifest_parse(FILE *fp, struct ropkg_manifest *dest) { enum parser_state { PARSER_STATE_NAME, PARSER_STATE_VALUE, } parser_state = PARSER_STATE_NAME; enum ropkg_status status = ROPKG_SUCCESS; b_result result = B_RESULT_SUCCESS; b_string *name = b_string_create(); b_string *value_string = b_string_create(); struct ropkg_manifest_value *value = NULL; char s[2] = {0}; bool done = false; while (!done) { char c = fgetc(fp); switch (c) { case ':': if (parser_state == PARSER_STATE_NAME) { parser_state = PARSER_STATE_VALUE; continue; } s[0] = c; b_string_append_cstr(value_string, s); continue; case '\n': if (parser_state == PARSER_STATE_NAME) { done = true; break; } result = create_manifest_value( name, value_string, &value); if (b_result_is_error(result)) { done = true; break; } status = ropkg_manifest_put(dest, value); if (status != ROPKG_SUCCESS) { result = b_error_with_code( ROPKG_ERROR_VENDOR, status); done = true; break; } b_string_clear(name); b_string_clear(value_string); parser_state = PARSER_STATE_NAME; break; case ' ': case '\t': if (parser_state == PARSER_STATE_NAME && b_string_get_size(name, 0) == 0) { break; } if (parser_state == PARSER_STATE_VALUE && b_string_get_size(value_string, 0) == 0) { break; } default: s[0] = c; if (parser_state == PARSER_STATE_NAME) { b_string_append_cstr(name, s); } else { b_string_append_cstr(value_string, s); } break; } } b_string_release(name); b_string_release(value_string); return result; } enum ropkg_status ropkg_manifest_get_by_name( struct ropkg_manifest *manifest, const char *name, struct ropkg_manifest_value **out) { b_queue_iterator it; b_queue_foreach(&it, &manifest->m_values) { struct ropkg_manifest_value *value = b_unbox( struct ropkg_manifest_value, it.entry, v_entry); if (value->v_name && !strcmp(value->v_name, name)) { *out = value; return ROPKG_SUCCESS; } } return ROPKG_ERR_NO_ENTRY; } enum ropkg_status ropkg_manifest_get_by_id( struct ropkg_manifest *manifest, enum ropkg_manifest_value_id id, struct ropkg_manifest_value **out) { b_queue_iterator it; b_queue_foreach(&it, &manifest->m_values) { struct ropkg_manifest_value *value = b_unbox( struct ropkg_manifest_value, it.entry, v_entry); if (value->v_id != ROPKG_MANIFEST_VALUE_N_NONE && value->v_id == id) { *out = value; return ROPKG_SUCCESS; } } return ROPKG_ERR_NO_ENTRY; } enum ropkg_status ropkg_manifest_put( struct ropkg_manifest *manifest, struct ropkg_manifest_value *value) { enum ropkg_status status = ROPKG_ERR_NO_ENTRY; struct ropkg_manifest_value *tmp; if (value->v_name) { status = ropkg_manifest_get_by_name( manifest, value->v_name, &tmp); } else if (value->v_id != ROPKG_MANIFEST_VALUE_N_NONE) { status = ropkg_manifest_get_by_id(manifest, value->v_id, &tmp); } else { return ROPKG_ERR_INVALID_ARGUMENT; } if (status == ROPKG_SUCCESS) { return ROPKG_ERR_NAME_EXISTS; } b_queue_push_back(&manifest->m_values, &value->v_entry); return ROPKG_SUCCESS; } const struct ropkg_manifest_value *ropkg_manifest_get_first_value( const struct ropkg_manifest *manifest) { b_queue_entry *entry = b_queue_first(&manifest->m_values); if (!entry) { return NULL; } return b_unbox(struct ropkg_manifest_value, entry, v_entry); } const struct ropkg_manifest_value *ropkg_manifest_get_next_value( const struct ropkg_manifest *manifest, const struct ropkg_manifest_value *value) { b_queue_entry *entry = b_queue_next(&value->v_entry); if (!entry) { return NULL; } return b_unbox(struct ropkg_manifest_value, entry, v_entry); } enum ropkg_status ropkg_manifest_value_create_int_with_name( size_t value, const char *name, struct ropkg_manifest_value **out) { struct ropkg_manifest_value *vp = malloc(sizeof *vp); if (!vp) { return ROPKG_ERR_NO_MEMORY; } memset(vp, 0x0, sizeof *vp); vp->v_type = ROPKG_MANIFEST_VALUE_T_INT; vp->v_name = b_strdup(name); if (!vp->v_name) { free(vp); return ROPKG_ERR_NO_MEMORY; } vp->v_value.i = value; *out = vp; return ROPKG_SUCCESS; } enum ropkg_status ropkg_manifest_value_create_int_with_id( size_t value, enum ropkg_manifest_value_id id, struct ropkg_manifest_value **out) { struct ropkg_manifest_value *vp = malloc(sizeof *vp); if (!vp) { return ROPKG_ERR_NO_MEMORY; } memset(vp, 0x0, sizeof *vp); vp->v_type = ROPKG_MANIFEST_VALUE_T_INT; vp->v_id = id; vp->v_value.i = value; *out = vp; return ROPKG_SUCCESS; } enum ropkg_status ropkg_manifest_value_create_string_with_name( const char *value, const char *name, struct ropkg_manifest_value **out) { struct ropkg_manifest_value *vp = malloc(sizeof *vp); if (!vp) { return ROPKG_ERR_NO_MEMORY; } memset(vp, 0x0, sizeof *vp); vp->v_type = ROPKG_MANIFEST_VALUE_T_STRING; vp->v_name = b_strdup(vp->v_name); if (!vp->v_name) { free(vp); return ROPKG_ERR_NO_MEMORY; } vp->v_value.s = b_strdup(value); if (!vp->v_value.s) { free(vp); return ROPKG_ERR_NO_MEMORY; } *out = vp; return ROPKG_SUCCESS; } enum ropkg_status ropkg_manifest_value_create_string_with_id( const char *value, enum ropkg_manifest_value_id id, struct ropkg_manifest_value **out) { struct ropkg_manifest_value *vp = malloc(sizeof *vp); if (!vp) { return ROPKG_ERR_NO_MEMORY; } memset(vp, 0x0, sizeof *vp); vp->v_type = ROPKG_MANIFEST_VALUE_T_STRING; vp->v_id = id; vp->v_value.s = b_strdup(value); if (!vp->v_value.s) { free(vp); return ROPKG_ERR_NO_MEMORY; } *out = vp; return ROPKG_SUCCESS; } void ropkg_manifest_value_destroy(struct ropkg_manifest_value *value) { if (value->v_type == ROPKG_MANIFEST_VALUE_T_STRING && value->v_value.s) { free(value->v_value.s); } if (value->v_name) { free(value->v_name); } free(value); } enum ropkg_manifest_value_type ropkg_manifest_value_get_type( const struct ropkg_manifest_value *value) { return value->v_type; } const char *ropkg_manifest_value_get_name( const struct ropkg_manifest_value *value) { if (value->v_name) { return value->v_name; } if (value->v_id == ROPKG_MANIFEST_VALUE_N_NONE) { return NULL; } return value_id_names[value->v_id]; } enum ropkg_manifest_value_id ropkg_manifest_value_get_id( const struct ropkg_manifest_value *value) { return value->v_id; } const char *ropkg_manifest_value_get_string( const struct ropkg_manifest_value *value) { if (value->v_type != ROPKG_MANIFEST_VALUE_T_STRING) { return NULL; } return value->v_value.s; } size_t ropkg_manifest_value_get_int(const struct ropkg_manifest_value *value) { if (value->v_type != ROPKG_MANIFEST_VALUE_T_INT) { return 0; } return value->v_value.i; }