Tech Note 02: NS Basic/Palm PDB File Structure

Oct 27, 2002

© NSB Corporation. All rights reserved.

Contributed by mizuno-ami and Jeffrey VanderWal.
"PDB" is the abbreviation of "Palm Database".  It is not a difficult structure to understand and figure out with the correct tools. Once you know this structure, you can easily make pdb files using VB or other tools.

In this short Tech note, I'll explain the structure of the most simple PDB file. Once you understand this, you will be able to understand other, more advanced cases more easily.

Getting Started

We will be using a Non-keyed database in NS Basic/Palm.
This database is created using the NSBasic commands DbPut() and DbGet().
Here is the code used to make a simple PDB file:

    Dim Db as Database
    Dim res as Integer

    res=DbCreate(Db,"DB-CREATE-TEST",0,"Test")    'Creator ID is "Test"
    If res=0 then				  'Created successfully
        res=DbOpen(Db,"DB-CREATE-TEST",0)
        res=DbPosition(Db,1,0)			  'Position pointer to record 1
        res=DbPut(Db,"NS BASIC")		  'Write it
        res=DbPosition(Db,2,0)			  'Position pointer to record 2
        res=DbPut(Db,"mizuno-ami")
        res=DbPosition(Db,3,0)
        res=DbPut(Db,"Simple Sample")
        res=DbClose(Db)
    End if

Reading the database can be done through this code:
(Field1008 shows the data which specified record at Field1006.)
    Dim Db as Database
    Dim res as Integer
    Dim intSet as Integer
    Dim strData as String

    intSet=Val(Field1006.Text)
    res=DbOpen(Db,"DB-CREATE-TEST",0)
    res=DbPosition(Db,intSet,0)		'Position pointer to the value in field1006
    res=DbGet(Db,strData)
    res=DbClose(Db)
    Field1008.text=strData		'Display your db data

After inputting this code into a sample project, you can create a sample database.
(A very simple example is included in this ZIP file)

After compiling, and running the program, create a database by clicking on "Create"
Now "Export the database" by right clicking on POSE and selecting "Export Database".  Select the file we created, called "DB-CREAT-TEST", and export it to a location that we can easily find (the desktop).  To check to ensure the database has been made correctly, type in "1" in the "Record" field and then read.  We created 3 records.



To see the "inside" of the PDB file you will need a hex editor.  I will be using Hex Workshop 3.11 (actually another hex editor is shown, but Hex Workshop works well for this purpose), but any hex or binary editor will do. 



A PDB file is split up into 3 sections:
  • Header (Database Header - "Title Page)
  • Location information (Record Header - "Table of Contents")
  • Record Data (Actual data)

The Header

Let's look at the Database header.
The size of this is 78bytes and this structure is following:

Offset size
(byte)
name explanation
+0000H 32 Database Name Database name on Palm (Not file name on PC)
+0020H 2 flags attribute of this database
+0022H 2 version version number
+0024H 4 create time the number of seconds since '1904-01-01 00:00:00'
+0028H 4 modified time
+002CH 4 backup time
+0030H 4 modified number the number of modified times
+0034H 4 application info size The simplest database sets "00 00 00 00"
+0038H 4 sort info size
+003CH 4 type File type. database is "data"
+0040H 4 creatorID creator ID
+0044H 4 unique id seed Unique seed number (Don't mind!)
+0048H 4 next record list Next record number (Don't mind!)
+004CH 2 number of records number of records
There will be some data fields you had known already.
Let's look up these data in order.

The database name is typically 32 byte data, followed by a null terminator "00" (Each field we see will be terminated by null). In most cases, you will find other unusal strings (like "ANL") after the null that you did not write.  This is perfectly normal, depending on how the database was made.  Palm ignores data after "00".




The next 2 bytes, you can find "00 08", this is the attribute of the file.
If it is set to "00 08", then this file will be backed to your PC at Hotsync.
Usually, you must manually set this flag "00 08".

The next 2 bytes, is the version number.  This is the same number you would see by going to the info screen on the Palm and checking the version number there.  In our example, "00 00" is written here, so our version number is the decimal equivalent of "00 00" hex, also "0".

The next bit of information is the create time, the modify time and the backup time, all measured in seconds data (4 bytes)  Palm uses a unique format for all times, measured in seconds since '1904-01-01 00:00:00'.  We won't have to worry about this, so we'll skip it here.  You can find ample information on the internet about this if you wish. When doing Hotsync, this data is updated.



The next bit of  data is the 'modification number' a number that counts the numbe rof times a modification has been done.  When you will make a new PDB file, you can write "00 00 00 00" it.

The application info size and sort info size, is also something we need not worry about.  For our case, this is "00 00 00 00", simply meaning that this information is not present. The simplest database does not need this information.

The next 2 bytes of data may be familiar to you. The first 4 bytes is file type and next 4 bytes is creator ID. As a database , the type will be usually "data".
The creator ID will be set by you when you create this database file using DbCreate(). In our example case, "Test".


Next 8 bytes , I don't know in detail but I know these are not needed for our purpose.

The last 2 bytes of header is number of records. Records we wrote are 3 records, and so here is "00 03".(written in hex)  The data here is 2 bytes, meaning that the maximum number of records is 65535 records.



Those are the basic details of the header data of 78 bytes.
 

Location information (Record Header - "Table of Contents")

After the header, the Palm must know what record to lookup and where to look it up.  The Palm uses a technique very similar to a book's table of contents.  After knowing what "chapter" to look up, you go to the table of contents to look up the page number and then go quickly to the page number.  Can you skip the TOC and go directly to the page?  Sure you can, if you know where it is, otherwise you must scan each page for the information you want.  This is very slow.  It is slow on the Palm as well. 

In our example of 3 records, we should have a table of contents with 3 entries (records)in it and 3 page numbers (locations)



Let's look at the location information.

The location data is 8 byte piece of data structured as as follows:

offset size
(byte)
name explanation
+0000H 4 offset location of this record from the head of file
+0004H 1 attribute
attribute
attribute of this record
+0005H 3 uniquie ID
uniqueID
count number of this record

It may be helpful for you to understand that this is an index.

Let's start from the beginning. After the header (78bytes) we are at position 78 or in hex 4E.  The next four bytes are the location information for the first record number.  Reading in the four bytes, we get 00 00 00 68 (hex).  This is the address of the first record in our database.  If we go to address 68 (the leading zeros drop off), we find our first record, "NS BASIC".  If we want the second record, we read our next table of contents entry starting 4 bytes after our location of record 1 (note, each TOC entry is 8 bytes, so from byte 78, we would skip the first 8 bytes (rec#1) and then read at offset 78+8=86 dec or 56 hex which would read the beginning of record #2 (mizuno...)



The next byte is the attribute of the record. A PDB file has an attribute for the whole of file and an attribute for each record.  I belive at Hotsync, this structure is updated, because the Hotsync program can find updated records easily.

The last 3 bytes is the unique ID, this is for assigning a unique number to each record. You'll find these data are unique and continue in increasing progression. i.e.'1E 90 01' , '1E 90 02' ...

Record Data (Actual data)

Once we know the structure of the PDB header, we can theoretically find any record number we want.  All we have to do is a simple calculation and read the table of contents.  How?  As an example in this case, to read the 3rd record, the header is 78 byte, so 78 + 3 * 8 = 102 -> 066H, is the start of record #3's real data location.

In some cases, the beginning of real data is 068H and there is a gap of 2 bytes.
This is called "alignment".  In our case we don't need to make this alignment, because these 2 bytes are not used, but it may be something to be aware of if reading someone else's PDB.

Now that we know how to find the beginning of the data, how to we know the end?  As mentioned earlier, each field is null terminated.  Null is 00.  Each record is also null terminated, so in our sample database, a 00 00 means "end of field, end of record".  This of course, appears after the field (ie NS BASIC)




All of this information pertains to the the simplest PDB file structure.  If you would like to disassemble other databases, a similar procedure would be followed.

This tutorial was originally made by mizuno-ami and then modified/translated/cleaned up by Jeff VanderWal.