From: <ny...@us...> - 2006-12-28 14:52:17
|
Revision: 217 http://svn.sourceforge.net/pmplib/?rev=217&view=rev Author: nyaochi Date: 2006-12-28 06:52:13 -0800 (Thu, 28 Dec 2006) Log Message: ----------- An extended game: db.idx and db.dat do not have a fixed size. These files are found to be (n*0x00020000) bytes long if the database has a large number of entries. This commit fixes database dump. The fix for database writer follows later. Modified Paths: -------------- trunk/pmplib/lib/pmp_iriverplus3/dat.c trunk/pmplib/lib/pmp_iriverplus3/dat.h trunk/pmplib/lib/pmp_iriverplus3/dic.c trunk/pmplib/lib/pmp_iriverplus3/dic.h trunk/pmplib/lib/pmp_iriverplus3/idx.c trunk/pmplib/lib/pmp_iriverplus3/ip3db.c trunk/pmplib/lib/pmp_iriverplus3/ip3db.h Modified: trunk/pmplib/lib/pmp_iriverplus3/dat.c =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/dat.c 2006-12-28 05:46:51 UTC (rev 216) +++ trunk/pmplib/lib/pmp_iriverplus3/dat.c 2006-12-28 14:52:13 UTC (rev 217) @@ -46,6 +46,15 @@ #include "dic.h" #include "dat.h" +#define PAGESIZE 0x00020000 + +typedef struct { + uint32_t size; + uint32_t num_entries; + uint32_t unknown1; + uint32_t next_page; +} page_header_t; + static void dat_entry_init(dat_entry_t* entry, const dic_table_t* dic_list) { memset(entry, 0, sizeof(*entry)); @@ -71,6 +80,30 @@ } } +static size_t dat_entry_size(dat_entry_t* entry) +{ + int i; + size_t size = 0; + for (i = 0;i < entry->num_fields;++i) { + ip3db_variant_t* var = &entry->fields[i]; + switch (var->type) { + case IP3DBVT_STRING: + size += var->value.str ? sizeof(ucs2char_t) * (ucs2len(var->value.str) + 1) : sizeof(ucs2char_t); + break; + case IP3DBVT_BYTE: + size += sizeof(uint8_t); + break; + case IP3DBVT_WORD: + size += sizeof(uint16_t); + break; + case IP3DBVT_DWORD: + size += sizeof(uint32_t); + break; + } + } + return size; +} + static size_t dat_entry_serialize(dat_entry_t* entry, uint8_t* block, uint8_t* q, uint32_t start, int is_storing) { int i; @@ -177,62 +210,78 @@ return &list->entries[list->num_entries++]; } -static size_t dat_list_serialize(dat_list_t* list, const dic_table_t* dic_list, uint8_t* buffer, uint32_t start, int is_storing) +static size_t dat_list_read(dat_list_t* list, page_header_t* header, const dic_table_t* dic_list, uint8_t* buffer, uint32_t start) { uint32_t i; uint8_t *p = buffer + start; - uint8_t *q = buffer + start + 0x00020000 - sizeof(uint32_t); + uint8_t *q = buffer + start + PAGESIZE - sizeof(uint32_t); - if (!is_storing) { - /* Read the header. */ - p += serialize_uint32be(p, &list->size, is_storing); - p += serialize_uint32be(p, &list->num_entries, is_storing); - p += serialize_uint32be(p, &list->unknown1, is_storing); - p += serialize_uint32be(p, &list->unknown2, is_storing); - } else { - /* Skip the header for now when writing. */ - p += sizeof(uint32_t) * 4; + /* Read the header. */ + p += serialize_uint32be(p, &header->size, 0); + p += serialize_uint32be(p, &header->num_entries, 0); + p += serialize_uint32be(p, &header->unknown1, 0); + p += serialize_uint32be(p, &header->next_page, 0); + + /* Expand the array of records. */ + list->entries = (dat_entry_t*)realloc(list->entries, sizeof(dat_entry_t) * (list->num_entries + header->num_entries)); + for (i = 0;i < header->num_entries;++i) { + dat_entry_init(&list->entries[list->num_entries+i], dic_list); } - /* Initialize fields according to db.dic when reading. */ - if (!is_storing) { - free(list->entries); - list->entries = (dat_entry_t*)calloc(list->num_entries, sizeof(dat_entry_t)); - for (i = 0;i < list->num_entries;++i) { - dat_entry_init(&list->entries[i], dic_list); - } + /* Read the new records. */ + for (i = 0;i < header->num_entries;++i) { + dat_entry_t* entry = &list->entries[list->num_entries+i]; + entry->offset = (uint32_t)(p - buffer); /* compute the current offset address */ + p += dat_entry_serialize(entry, p, q, start, 0); + q -= sizeof(uint32_t); } - /* Serialize entries in this table. */ - for (i = 0;i < list->num_entries;++i) { + list->num_entries += header->num_entries; + return (size_t)(header->size); +} + +static size_t dat_list_write(dat_list_t* list, uint32_t i, page_header_t* header, uint8_t* buffer, uint32_t start) +{ + uint8_t *p = buffer + start; + uint8_t *q = buffer + start + PAGESIZE - sizeof(uint32_t); + + header->size = 0; + header->num_entries = 0; + + /* Skip the header for now when writing. */ + p += sizeof(uint32_t) * 4; + + /* Write records. */ + while (i < list->num_entries) { + size_t free_space = (size_t)(q-p); dat_entry_t* entry = &list->entries[i]; + if (free_space < dat_entry_size(entry)) { + break; + } entry->offset = (uint32_t)(p - buffer); /* compute the current offset address */ - p += dat_entry_serialize(entry, p, q, start, is_storing); + p += dat_entry_serialize(entry, p, q, start, 1); q -= sizeof(uint32_t); + header->num_entries++; + i++; } - if (is_storing) { - /* Compute the block size and write the header. */ - list->size = (uint32_t)(p - (buffer + start)); - p = buffer + start; - p += serialize_uint32be(p, &list->size, is_storing); - p += serialize_uint32be(p, &list->num_entries, is_storing); - p += serialize_uint32be(p, &list->unknown1, is_storing); - p += serialize_uint32be(p, &list->unknown2, is_storing); + /* Compute the block size and write the header. */ + header->size = (uint32_t)(p - (buffer + start)); + if (list->num_entries <= i) { + header->next_page = 0; } - return (size_t)(list->size); + p = buffer + start; + p += serialize_uint32be(p, &header->size, 1); + p += serialize_uint32be(p, &header->num_entries, 1); + p += serialize_uint32be(p, &header->unknown1, 1); + p += serialize_uint32be(p, &header->next_page, 1); + return header->size; } static void dat_list_dump(dat_list_t* list, const dic_table_t* dic_list, FILE *fp) { uint32_t i; - - fprintf(fp, " size: 0x%08X\n", list->size); - fprintf(fp, " num_entries: %d\n", list->num_entries); - fprintf(fp, " unknown1: 0x%08X\n", list->unknown1); - fprintf(fp, " unknown2: 0x%08X\n", list->unknown2); - for (i = 0;i < list->num_entries;++i) { dat_entry_t* entry = &list->entries[i]; fprintf(fp, " ENTRY %d (0x%08X) = {\n", i, entry->offset); @@ -281,37 +330,73 @@ int dat_read(dat_t* dat, const dic_t* dic, FILE *fpi) { + page_header_t ph; long buffer_size = 0; uint8_t* buffer = NULL; + /* Read the whole image. */ fread_all(fpi, &buffer, &buffer_size); if (!buffer) { return 1; } - if (dat_serialize(dat, dic, buffer, 0) != 0) { - free(buffer); - return 1; + /* Clear Object records. */ + dat_list_finish(&dat->objects); + + /* Read Objects page(s) */ + dat_list_read(&dat->objects, &ph, &dic->objects, buffer, PAGESIZE * 0); + while (ph.next_page) { + dat_list_read(&dat->objects, &ph, &dic->objects, buffer, PAGESIZE * (ph.next_page - 1)); } + /* Clear Music records. */ + dat_list_finish(&dat->musics); + + /* Read Music page(s) */ + dat_list_read(&dat->musics, &ph, &dic->music, buffer, PAGESIZE * 1); + while (ph.next_page) { + dat_list_read(&dat->musics, &ph, &dic->music, buffer, PAGESIZE * (ph.next_page - 1)); + } + free(buffer); return 0; } int dat_write(dat_t* dat, const dic_t* dic, FILE *fpo) { - long buffer_size = 0x00040000; + uint32_t i = 0; + page_header_t ph; + long buffer_size = PAGESIZE * 2; uint8_t* buffer = (uint8_t*)calloc(buffer_size, sizeof(uint8_t)); if (!buffer) { return 1; } - if (dat_serialize(dat, dic, buffer, 1) != 0) { - free(buffer); - return 1; + /* Write Objects page(s) */ + i = 0; + memset(&ph, 0, sizeof(ph)); + ph.next_page = 3; + dat_list_write(&dat->objects, i, &ph, buffer, PAGESIZE * 0); + while (ph.next_page) { + uint32_t page = ph.next_page++; + buffer_size = PAGESIZE * page; + buffer = (uint8_t*)realloc(buffer, sizeof(uint8_t) * buffer_size); + i += ph.num_entries; + dat_list_write(&dat->objects, i, &ph, buffer, PAGESIZE * (page - 1)); } + /* Read Music page(s) */ + i = 0; + dat_list_write(&dat->musics, i, &ph, buffer, PAGESIZE * 1); + while (ph.next_page) { + uint32_t page = ph.next_page++; + buffer_size = PAGESIZE * page; + buffer = (uint8_t*)realloc(buffer, sizeof(uint8_t) * buffer_size); + i += ph.num_entries; + dat_list_write(&dat->objects, i, &ph, buffer, PAGESIZE * (page - 1)); + } + if (fwrite(buffer, 1, buffer_size, fpo) != buffer_size) { free(buffer); return 1; Modified: trunk/pmplib/lib/pmp_iriverplus3/dat.h =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/dat.h 2006-12-28 05:46:51 UTC (rev 216) +++ trunk/pmplib/lib/pmp_iriverplus3/dat.h 2006-12-28 14:52:13 UTC (rev 217) @@ -31,10 +31,7 @@ } dat_entry_t; typedef struct { - uint32_t size; uint32_t num_entries; - uint32_t unknown1; - uint32_t unknown2; dat_entry_t* entries; } dat_list_t; Modified: trunk/pmplib/lib/pmp_iriverplus3/dic.c =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/dic.c 2006-12-28 05:46:51 UTC (rev 216) +++ trunk/pmplib/lib/pmp_iriverplus3/dic.c 2006-12-28 14:52:13 UTC (rev 217) @@ -194,7 +194,13 @@ { int i; uint32_t next = 0; - + uint8_t* p = buffer; + + p += serialize_uint32be(p, &dic->header.size, is_storing); + p += serialize_uint32be(p, &dic->header.num_dat_pages, is_storing); + p += serialize_uint32be(p, &dic->header.num_idx_pages, is_storing); + p += serialize_uint32be(p, &dic->header.unknown1, is_storing); + next = 0x0000003C; for (i = 0;i < dic->music.num_fields;++i) { dic_field_serialize(buffer + next, &dic->music.fields[i], is_storing); Modified: trunk/pmplib/lib/pmp_iriverplus3/dic.h =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/dic.h 2006-12-28 05:46:51 UTC (rev 216) +++ trunk/pmplib/lib/pmp_iriverplus3/dic.h 2006-12-28 14:52:13 UTC (rev 217) @@ -25,6 +25,13 @@ #define __IP3DB_DIC_H__ typedef struct { + uint32_t size; + uint32_t num_dat_pages; + uint32_t num_idx_pages; + uint32_t unknown1; +} dic_header_t; + +typedef struct { uint32_t next; uint32_t type; uint32_t idx_root; @@ -45,8 +52,9 @@ } dic_table_t; struct tag_dic_t { - dic_table_t music; - dic_table_t objects; + dic_header_t header; + dic_table_t music; + dic_table_t objects; uint8_t* buffer; long size; Modified: trunk/pmplib/lib/pmp_iriverplus3/idx.c =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/idx.c 2006-12-28 05:46:51 UTC (rev 216) +++ trunk/pmplib/lib/pmp_iriverplus3/idx.c 2006-12-28 14:52:13 UTC (rev 217) @@ -619,9 +619,8 @@ idx_header_t* header = (idx_header_t*)idx->buffer; /* Read the whole data at a time. */ - if (fread(idx->buffer, 1, idx->max_size, fpi) != idx->max_size) { - return 1; - } + fread_all(fpi, &idx->buffer, &idx->max_size); + idx->avl->buffer = idx->buffer; /* Convert the byte order of the header from big endian to the native one. */ from_uint32be(&header->size); Modified: trunk/pmplib/lib/pmp_iriverplus3/ip3db.c =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/ip3db.c 2006-12-28 05:46:51 UTC (rev 216) +++ trunk/pmplib/lib/pmp_iriverplus3/ip3db.c 2006-12-28 14:52:13 UTC (rev 217) @@ -78,7 +78,7 @@ { var->type = IP3DBVT_STRING; ucs2free(var->value.str); - var->value.str = ucs2dup(val); + var->value.str = val ? ucs2dup(val) : ucs2calloc(sizeof(ucs2char_t)); } void ip3db_variant_clone(ip3db_variant_t* dst, const ip3db_variant_t* src) Modified: trunk/pmplib/lib/pmp_iriverplus3/ip3db.h =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/ip3db.h 2006-12-28 05:46:51 UTC (rev 216) +++ trunk/pmplib/lib/pmp_iriverplus3/ip3db.h 2006-12-28 14:52:13 UTC (rev 217) @@ -116,8 +116,10 @@ * Fields chunks in db.dat. */ enum { + IP3DBIDX_NONE = -1, IP3DBIDX_MUSIC = 0, IP3DBIDX_OBJECTS, + IP3DBIDX_LAST, }; /** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |