int menu_entries_push_query(libretrodb_t *db, libretrodb_cursor_t *cur, file_list_t *list) { unsigned i; struct rmsgpack_dom_value item; while (libretrodb_cursor_read_item(cur, &item) == 0) { if (item.type != RDT_MAP) continue; for (i = 0; i < item.map.len; i++) { struct rmsgpack_dom_value *key = &item.map.items[i].key; struct rmsgpack_dom_value *val = &item.map.items[i].value; if (!key || !val) continue; if (!strcmp(key->string.buff, "name")) { menu_list_push(list, val->string.buff, db->path, MENU_FILE_RDB_ENTRY, 0); break; } } } return 0; }
static int cursor_read(lua_State *L) { libretrodb_cursor_t *cursor = checkcursor(L); struct rmsgpack_dom_value value; if (libretrodb_cursor_read_item(cursor, &value) == 0) push_rmsgpack_value(L, &value); else lua_pushnil(L); return 1; }
int main(int argc, char ** argv) { int rv; libretrodb_t db; libretrodb_cursor_t cur; libretrodb_query_t *q; struct rmsgpack_dom_value item; const char *command, *path, *query_exp, *error; if (argc < 3) { printf("Usage: %s <db file> <command> [extra args...]\n", argv[0]); printf("Available Commands:\n"); printf("\tlist\n"); printf("\tcreate-index <index name> <field name>\n"); printf("\tfind <query expression>\n"); return 1; } command = argv[2]; path = argv[1]; if ((rv = libretrodb_open(path, &db)) != 0) { printf("Could not open db file '%s': %s\n", path, strerror(-rv)); return 1; } else if (strcmp(command, "list") == 0) { if ((rv = libretrodb_cursor_open(&db, &cur, NULL)) != 0) { printf("Could not open cursor: %s\n", strerror(-rv)); return 1; } if (argc != 3) { printf("Usage: %s <db file> list\n", argv[0]); return 1; } while (libretrodb_cursor_read_item(&cur, &item) == 0) { rmsgpack_dom_value_print(&item); printf("\n"); rmsgpack_dom_value_free(&item); } } else if (strcmp(command, "find") == 0) { if (argc != 4) { printf("Usage: %s <db file> find <query expression>\n", argv[0]); return 1; } query_exp = argv[3]; error = NULL; q = libretrodb_query_compile(&db, query_exp, strlen(query_exp), &error); if (error) { printf("%s\n", error); return 1; } if ((rv = libretrodb_cursor_open(&db, &cur, q)) != 0) { printf("Could not open cursor: %s\n", strerror(-rv)); return 1; } while (libretrodb_cursor_read_item(&cur, &item) == 0) { rmsgpack_dom_value_print(&item); printf("\n"); rmsgpack_dom_value_free(&item); } } else if (strcmp(command, "create-index") == 0) { const char * index_name, * field_name; if (argc != 5) { printf("Usage: %s <db file> create-index <index name> <field name>\n", argv[0]); return 1; } index_name = argv[3]; field_name = argv[4]; libretrodb_create_index(&db, index_name, field_name); } else { printf("Unknown command %s\n", argv[2]); return 1; } libretrodb_close(&db); return 1; }
static int database_cursor_iterate(libretrodb_cursor_t *cur, database_info_t *db_info) { unsigned i; struct rmsgpack_dom_value item; const char* str = NULL; if (libretrodb_cursor_read_item(cur, &item) != 0) return -1; if (item.type != RDT_MAP) { rmsgpack_dom_value_free(&item); return 1; } db_info->analog_supported = -1; db_info->rumble_supported = -1; db_info->coop_supported = -1; for (i = 0; i < item.val.map.len; i++) { struct rmsgpack_dom_value *key = &item.val.map.items[i].key; struct rmsgpack_dom_value *val = &item.val.map.items[i].value; const char *val_string = NULL; if (!key || !val) continue; val_string = val->val.string.buff; str = key->val.string.buff; if (string_is_equal(str, "publisher")) { if (!string_is_empty(val_string)) db_info->publisher = strdup(val_string); } else if (string_is_equal(str, "developer")) { if (!string_is_empty(val_string)) db_info->developer = string_split(val_string, "|"); } else if (string_is_equal(str, "serial")) { if (!string_is_empty(val_string)) db_info->serial = strdup(val_string); } else if (string_is_equal(str, "rom_name")) { if (!string_is_empty(val_string)) db_info->rom_name = strdup(val_string); } else if (string_is_equal(str, "name")) { if (!string_is_empty(val_string)) db_info->name = strdup(val_string); } else if (string_is_equal(str, "description")) { if (!string_is_empty(val_string)) db_info->description = strdup(val_string); } else if (string_is_equal(str, "genre")) { if (!string_is_empty(val_string)) db_info->genre = strdup(val_string); } else if (string_is_equal(str, "origin")) { if (!string_is_empty(val_string)) db_info->origin = strdup(val_string); } else if (string_is_equal(str, "franchise")) { if (!string_is_empty(val_string)) db_info->franchise = strdup(val_string); } else if (string_is_equal(str, "bbfc_rating")) { if (!string_is_empty(val_string)) db_info->bbfc_rating = strdup(val_string); } else if (string_is_equal(str, "esrb_rating")) { if (!string_is_empty(val_string)) db_info->esrb_rating = strdup(val_string); } else if (string_is_equal(str, "elspa_rating")) { if (!string_is_empty(val_string)) db_info->elspa_rating = strdup(val_string); } else if (string_is_equal(str, "cero_rating")) { if (!string_is_empty(val_string)) db_info->cero_rating = strdup(val_string); } else if (string_is_equal(str, "pegi_rating")) { if (!string_is_empty(val_string)) db_info->pegi_rating = strdup(val_string); } else if (string_is_equal(str, "enhancement_hw")) { if (!string_is_empty(val_string)) db_info->enhancement_hw = strdup(val_string); } else if (string_is_equal(str, "edge_review")) { if (!string_is_empty(val_string)) db_info->edge_magazine_review = strdup(val_string); } else if (string_is_equal(str, "edge_rating")) db_info->edge_magazine_rating = (unsigned)val->val.uint_; else if (string_is_equal(str, "edge_issue")) db_info->edge_magazine_issue = (unsigned)val->val.uint_; else if (string_is_equal(str, "famitsu_rating")) db_info->famitsu_magazine_rating = (unsigned)val->val.uint_; else if (string_is_equal(str, "tgdb_rating")) db_info->tgdb_rating = (unsigned)val->val.uint_; else if (string_is_equal(str, "users")) db_info->max_users = (unsigned)val->val.uint_; else if (string_is_equal(str, "releasemonth")) db_info->releasemonth = (unsigned)val->val.uint_; else if (string_is_equal(str, "releaseyear")) db_info->releaseyear = (unsigned)val->val.uint_; else if (string_is_equal(str, "rumble")) db_info->rumble_supported = (int)val->val.uint_; else if (string_is_equal(str, "coop")) db_info->coop_supported = (int)val->val.uint_; else if (string_is_equal(str, "analog")) db_info->analog_supported = (int)val->val.uint_; else if (string_is_equal(str, "size")) db_info->size = (unsigned)val->val.uint_; else if (string_is_equal(str, "crc")) db_info->crc32 = swap_if_little32( *(uint32_t*)val->val.binary.buff); else if (string_is_equal(str, "sha1")) db_info->sha1 = bin_to_hex_alloc( (uint8_t*)val->val.binary.buff, val->val.binary.len); else if (string_is_equal(str, "md5")) db_info->md5 = bin_to_hex_alloc( (uint8_t*)val->val.binary.buff, val->val.binary.len); else { RARCH_LOG("Unknown key: %s\n", str); } } rmsgpack_dom_value_free(&item); return 0; }
int libretrodb_create_index(libretrodb_t *db, const char *name, const char *field_name) { int rv; struct node_iter_ctx nictx; struct rmsgpack_dom_value key; libretrodb_index_t idx; struct rmsgpack_dom_value item; struct rmsgpack_dom_value * field; struct bintree tree; libretrodb_cursor_t cur; uint64_t idx_header_offset; void * buff = NULL; uint64_t * buff_u64 = NULL; uint8_t field_size = 0; uint64_t item_loc = libretrodb_tell(db); bintree_new(&tree, node_compare, &field_size); if (libretrodb_cursor_open(db, &cur, NULL) != 0) { rv = -1; goto clean; } key.type = RDT_STRING; key.string.len = strlen(field_name); /* We know we aren't going to change it */ key.string.buff = (char *) field_name; while (libretrodb_cursor_read_item(&cur, &item) == 0) { if (item.type != RDT_MAP) { rv = -EINVAL; printf("Only map keys are supported\n"); goto clean; } field = rmsgpack_dom_value_map_value(&item, &key); if (!field) { rv = -EINVAL; printf("field not found in item\n"); goto clean; } if (field->type != RDT_BINARY) { rv = -EINVAL; printf("field is not binary\n"); goto clean; } if (field->binary.len == 0) { rv = -EINVAL; printf("field is empty\n"); goto clean; } if (field_size == 0) field_size = field->binary.len; else if (field->binary.len != field_size) { rv = -EINVAL; printf("field is not of correct size\n"); goto clean; } buff = malloc(field_size + sizeof(uint64_t)); if (!buff) { rv = -ENOMEM; goto clean; } memcpy(buff, field->binary.buff, field_size); buff_u64 = (uint64_t *)buff + field_size; memcpy(buff_u64, &item_loc, sizeof(uint64_t)); if (bintree_insert(&tree, buff) != 0) { printf("Value is not unique: "); rmsgpack_dom_value_print(field); printf("\n"); rv = -EINVAL; goto clean; } buff = NULL; rmsgpack_dom_value_free(&item); item_loc = libretrodb_tell(db); } (void)rv; (void)idx_header_offset; idx_header_offset = lseek(db->fd, 0, SEEK_END); strncpy(idx.name, name, 50); idx.name[49] = '\0'; idx.key_size = field_size; idx.next = db->count * (field_size + sizeof(uint64_t)); libretrodb_write_index_header(db->fd, &idx); nictx.db = db; nictx.idx = &idx; bintree_iterate(&tree, node_iter, &nictx); bintree_free(&tree); clean: rmsgpack_dom_value_free(&item); if (buff) free(buff); if (cur.is_valid) libretrodb_cursor_close(&cur); return 0; }
static int database_cursor_iterate(libretrodb_cursor_t *cur, database_info_t *db_info) { unsigned i; struct rmsgpack_dom_value item; const char* str = NULL; if (libretrodb_cursor_read_item(cur, &item) != 0) return -1; if (item.type != RDT_MAP) { rmsgpack_dom_value_free(&item); return 1; } db_info->analog_supported = -1; db_info->rumble_supported = -1; db_info->coop_supported = -1; for (i = 0; i < item.val.map.len; i++) { uint32_t value = 0; struct rmsgpack_dom_value *key = &item.val.map.items[i].key; struct rmsgpack_dom_value *val = &item.val.map.items[i].value; if (!key || !val) continue; str = key->val.string.buff; value = msg_hash_calculate(str); switch (value) { case DB_CURSOR_SERIAL: db_info->serial = strdup(val->val.string.buff); break; case DB_CURSOR_ROM_NAME: db_info->rom_name = strdup(val->val.string.buff); break; case DB_CURSOR_NAME: db_info->name = strdup(val->val.string.buff); break; case DB_CURSOR_DESCRIPTION: db_info->description = strdup(val->val.string.buff); break; case DB_CURSOR_GENRE: db_info->genre = strdup(val->val.string.buff); break; case DB_CURSOR_PUBLISHER: db_info->publisher = strdup(val->val.string.buff); break; case DB_CURSOR_DEVELOPER: db_info->developer = string_split(val->val.string.buff, "|"); break; case DB_CURSOR_ORIGIN: db_info->origin = strdup(val->val.string.buff); break; case DB_CURSOR_FRANCHISE: db_info->franchise = strdup(val->val.string.buff); break; case DB_CURSOR_BBFC_RATING: db_info->bbfc_rating = strdup(val->val.string.buff); break; case DB_CURSOR_ESRB_RATING: db_info->esrb_rating = strdup(val->val.string.buff); break; case DB_CURSOR_ELSPA_RATING: db_info->elspa_rating = strdup(val->val.string.buff); break; case DB_CURSOR_CERO_RATING: db_info->cero_rating = strdup(val->val.string.buff); break; case DB_CURSOR_PEGI_RATING: db_info->pegi_rating = strdup(val->val.string.buff); break; case DB_CURSOR_ENHANCEMENT_HW: db_info->enhancement_hw = strdup(val->val.string.buff); break; case DB_CURSOR_EDGE_MAGAZINE_REVIEW: db_info->edge_magazine_review = strdup(val->val.string.buff); break; case DB_CURSOR_EDGE_MAGAZINE_RATING: db_info->edge_magazine_rating = val->val.uint_; break; case DB_CURSOR_EDGE_MAGAZINE_ISSUE: db_info->edge_magazine_issue = val->val.uint_; break; case DB_CURSOR_FAMITSU_MAGAZINE_RATING: db_info->famitsu_magazine_rating = val->val.uint_; break; case DB_CURSOR_TGDB_RATING: db_info->tgdb_rating = val->val.uint_; break; case DB_CURSOR_MAX_USERS: db_info->max_users = val->val.uint_; break; case DB_CURSOR_RELEASEDATE_MONTH: db_info->releasemonth = val->val.uint_; break; case DB_CURSOR_RELEASEDATE_YEAR: db_info->releaseyear = val->val.uint_; break; case DB_CURSOR_RUMBLE_SUPPORTED: db_info->rumble_supported = val->val.uint_; break; case DB_CURSOR_COOP_SUPPORTED: db_info->coop_supported = val->val.uint_; break; case DB_CURSOR_ANALOG_SUPPORTED: db_info->analog_supported = val->val.uint_; break; case DB_CURSOR_SIZE: db_info->size = val->val.uint_; break; case DB_CURSOR_CHECKSUM_CRC32: db_info->crc32 = swap_if_little32(*(uint32_t*)val->val.binary.buff); break; case DB_CURSOR_CHECKSUM_SHA1: db_info->sha1 = bin_to_hex_alloc((uint8_t*)val->val.binary.buff, val->val.binary.len); break; case DB_CURSOR_CHECKSUM_MD5: db_info->md5 = bin_to_hex_alloc((uint8_t*)val->val.binary.buff, val->val.binary.len); break; default: RARCH_LOG("Unknown key: %s\n", str); break; } } rmsgpack_dom_value_free(&item); return 0; }