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