MobileDB uses the same structure for every record in the database. The type of data in each record is defined by the PalmOS category for that record. The following is a list of the categories and the type of data in that record.
Header | Data | End |
ff ff ff 01 ff 00 | 00 00 data for field 1 00 01 data for field 2 ...00 nn data for field n | 00 ff |
<*>= #include <stdio.h> #include <assert.h> #include <ctype.h> #include "pdblua.h" #include "pdbconv.h" #include "pdbrep.h" <functions>
<functions>= (<-U) [D->] static void fail(char *msg, int n) { fprintf(stdout, "Malformed MobileDB database: %s %d\n", msg, n); exit(1); }
Definesfail
(links are to index).
<functions>+= (<-U) [<-D->]
struct rheader {
unsigned char reserved[3];
unsigned char version;
unsigned char reserved2;
unsigned char encryption;
};
static char *categories[] = { 0, "Field names", "Data record", "Filtered out record",
"Preferences", "Field Types", "Column Widths", 0 };
static void dumpr(FILE *out, struct pdb *db, int recnum) {
Record *r = db->records + recnum;
struct rheader *h = (struct rheader *)r->data.chars;
Text t = r->data;
int i;
char *p;
assert(h);
<check for valid header h
>
fprintf(out, "\n {");
fprintf(out, " version = %d, encryption = %d,\n", h->version, h->encryption);
<check category>
fprintf(out, " type = %s,\n", QUOTE(categories[r->category]));
fprintf(out, " fields = { ");
p = t.chars + sizeof (*h);
for (i = 0; p < t.chars + t.len; i++) {
if (*p++) fail("bad field zero", i);
if (*(unsigned char *)p == 0xff) break;
if (*(unsigned char *)p++ != i) fail("bad field number", i);
if (i > 0) fprintf(out, ", ");
switch (r->category) {
case 4:
fprintf(out, "%d", *p++);
break;
case 6:
{ char *s;
for (s = p; *s && (isspace(*s) || isdigit(*s)); s++);
if (*s) fail("bad column width in field", i);
fprintf(out, "%s", p);
p = s;
}
break;
default:
fprintf(out, "%s", QUOTE(p));
p += strlen(p);
break;
}
}
if (p + 1 != t.chars + t.len)
fprintf(stderr, "Warning: %d garbage characters at end of record %d (uid %d)\n",
t.len - (p + 1 - t.chars), recnum, r->uid);
fprintf(out, " }\n");
fprintf(out, " }");
}
Definescategories
,dumpr
(links are to index).
<check for valid header h
>= (<-U)
if (h->reserved[0] != 0xff || h->reserved[1] != 0xff || h->reserved[2] != 0xff
|| h->reserved2 != 0xff)
fail("bad reserved bits in header", 99);
<check category>= (<-U) if (1 <= r->category && r->category <= 6) { } else fail("bad category", r->category);
<functions>+= (<-U) [<-D->] static int packr(FILE *pdb, int i) { struct rheader hdr; int cat; int j, n; lua_pushnumber((double)(i+1)); lua_setglobal("i"); if (lua_dostring( "$debug\n" "thisrecord = Database.records[i].data")) assert(0); dbcheck("istable(thisrecord)", "record data is not a table"); hdr.version = intopt("thisrecord.version", 1); hdr.encryption = intopt("thisrecord.encryption", 0); hdr.reserved[0] = hdr.reserved[1] = hdr.reserved[2] = hdr.reserved2 = 0xff; if (pdb) put_chars(pdb, &hdr, sizeof(hdr)); n = sizeof(hdr); cat = intval("Database.records[i].category"); for (j = 0; ; j++) { lua_pushnumber((double)(j+1)); lua_setglobal("j"); if (lua_isnil(objectval("thisrecord.fields[j]"))) break; if (pdb) {putc(0, pdb); putc(j, pdb);} n += 2; switch (cat) { case 4: if (pdb) putc(intopt("thisrecord.fields[j]", 0) & 0xff, pdb); n++; break; default: { char *s = stringval("thisrecord.fields[j]"); if (pdb) put_chars(pdb, s, strlen(s)); /* no trailing null */ n += strlen(s); } break; } } if (pdb) { putc(0, pdb); fputc(0xff, pdb); } n += 2; return n; }
Definespackr
(links are to index).
<functions>+= (<-U) [<-D->] typedef struct { struct PDBCategoryAppInfo categories; unsigned char reserved1; unsigned short reserved2; } MobileAppInfoType; static void dumpi(FILE *out, struct pdb *db, Text txt) { Text *t = &txt; MobileAppInfoType info; info.categories = catread(t); fprintf(out, "\n {"); fprintf(out, "\n categories = "); unpack_categories(out, &info.categories, 1); info.reserved1 = get_byte(t); info.reserved2 = get_short(t); fprintf(out, ",\n reserved = { %d, %d }", info.reserved1, info.reserved2); fprintf(out, "\n }"); if (chars_remaining(t) > 0) fprintf(stderr, "Warning: %d unused bytes in application info for MobileDB", chars_remaining(t)); } static int packi(FILE *out, int appinfo) { int n; MobileAppInfoType info; info.categories = pack_categories(); n = catwrite(out, &info.categories); if (out) { info.reserved1 = intopt("istable(Database.appInfo.reserved) and " "Database.appInfo.reserved[1]", 0); info.reserved2 = intopt("istable(Database.appInfo.reserved) and " "Database.appInfo.reserved[2]", 0); put_byte(out, info.reserved1); put_short(out, info.reserved2); } return n+3; }
Definesdumpi
,MobileAppInfoType
,packi
(links are to index).
<functions>+= (<-U) [<-D] struct PDBConv mobileDB = { "MobileDB database", "Mdb1", "Mdb1", { 0, dumpi, packi }, { 0, generic_unpackInfo, generic_packInfo }, { 0, dumpr, packr }, 0 };
DefinesmobileDB
(links are to index).
h
>: U1, D2