org.WeaselReader.PalmIO
Class PalmDB

java.lang.Object
  extended by java.io.RandomAccessFile
      extended by org.WeaselReader.PalmIO.PalmDB
All Implemented Interfaces:
java.io.Closeable, java.io.DataInput, java.io.DataOutput
Direct Known Subclasses:
PalmDocDB, ZtxtDB

public class PalmDB
extends java.io.RandomAccessFile

Base class for reading Palm database files. PalmDB extends RandomAccessFile because it needs the various readXXX methods, as in DataInputStream, but it is also necessary to randomly seek which is not available in DataInputStream.

This class is useful for only the basic structure inherent in any Palm database. New classes should extend this class to handle features/formats specific to databases used by applications, such as the ZtxtDB class which reads zTXT Palm databases (which are read by Weasel Reader and others).

The Palm database header is a packed structure of Big Endian values. Its structure conforms to the following C struct definitions:

typedef struct {
UInt8 name[dmDBNameLength];
UInt16 attributes;
UInt16 version;
UInt32 creationDate;
UInt32 modificationDate;
UInt32 lastBackupDate;
UInt32 modificationNumber;
LocalID appInfoID;
LocalID sortInfoID;
UInt32 type;
UInt32 creator;
UInt32 uniqueIDSeed;
RecordListType recordList;
} DatabaseHdrType;

typedef struct {
LocalID nextRecordListID;
UInt16 numRecords;
UInt16 firstEntry;
} RecordListType;

typedef struct {
LocalID localChunkID;
UInt8 attributes;
UInt8 uniqueID[3];
} RecordEntryType;

All of these values are unsigned. A LocalID is a type of Palm OS pointer which is equivalent to a UInt32. See the comments on the private fields of this class for more information on what these values mean.

Version:
$Id$
Author:
John Gruenenfelder

Field Summary
private  long applicationInfoIDPtr
          Byte offset from beginning of the file to the appInfoArea block.
private  long creationTime
          Creation time in seconds of the database.
static int DB_FLAG_BACKUP
          Set if the database should be backed up during the next sync procedure.
static int DB_FLAG_DIRTY_APPINFO
          Set if the appInfoArea has changed.
static int DB_FLAG_NEWER_OKAY
          Set if it is acceptable for a database with the same name but higher version number to be installed over this database.
static int DB_FLAG_NO_COPY
          Set if the device should not permit this database to be beamed or copied to another device.
static int DB_FLAG_READ_ONLY
          Database is read-only while in Palm memory.
static int DB_FLAG_RESET_ON_INSTALL
          Set if the device must be reset after this database has been installed.
static int DB_HEADER_LENGTH
          The length of a Palm OS database header up to and including the numRecords field.
static int DB_NAME_LENGTH
          The length of the database name field in the Palm OS database header.
private  long dbCreatorID
          Palm OS database creator ID string.
private  java.lang.String dbName
          The Palm database name.
private  long dbTypeID
          Palm OS database type ID string.
private  int flags
          Palm database flags.
private  long lastBackupTime
          Time of the last database backup in seconds.
private  long modificationNumber
          Database's modification number, defined by the application.
private  long modificationTime
          Last modification time in seconds of the database.
private  long nextRecordListIDPtr
          In memory a Palm database can have multiple record list structures, though in practice there is never more than one.
private  int numRecords
          Number of records in this database.
static int PALM_CTIME_OFFSET
          This is the offset from the Palm OS epoch to the standard UNIX epoch.
static short REC_FLAG_BUSY
          On a device, it means the record is open for writing.
static short REC_FLAG_DELETE
          Set if the record has been marked for deletion.
static short REC_FLAG_DIRTY
          Set if the record has been modified and must be backed up during the next sync procedure.
static short REC_FLAG_SECRET
          If set, Record is marked as "secret" and some Palm apps can selectively hide secret records unless a password is entered.
private  java.util.Vector<java.lang.Integer> recordFlags
          This array contains the attribute flags for each record in the database.
private  java.util.Vector<java.lang.Integer> recordIDs
          This array contains the unique IDs for each record in the database.
private  java.util.Vector<java.lang.Long> recordOffsets
          This array contains the byte offsets for the beginning of each record in this database.
private  long sortInfoIDPtr
          Byte offset from beginning of the file to the sortInfoArea block.
private  long uniqueIDSeed
          Used as the base index for the record LocalID values.
private  int version
          Database version number, defined by the application.
 
Constructor Summary
PalmDB(java.io.File pdbFile)
          Create a complete PalmDB object from the contents of the specified pdb file.
 
Method Summary
 long getApplicationInfoIDPtr()
           
 long getCreationTime()
           
 long getDbCreatorID()
           
 java.lang.String getDbName()
           
 long getDbTypeID()
           
 int getFlags()
           
 long getLastBackupTime()
           
 long getModificationNumber()
           
 long getModificationTime()
           
 long getNextRecordListIDPtr()
           
 int getNumRecords()
           
 java.util.Vector<java.lang.Integer> getRecordFlags()
           
 java.util.Vector<java.lang.Integer> getRecordIDs()
           
 java.util.Vector<java.lang.Long> getRecordOffsets()
           
 long getSortInfoIDPtr()
           
 long getUniqueIDSeed()
           
 int getVersion()
           
static void main(java.lang.String[] args)
          Useful for loading and testing the PalmDB class from the command line.
private  void readHeader()
          Read in a Palm OS database header and set the appropriate fields with data from the header.
 byte[] readRecord(int recIndex)
          Read the specified record and return it as a byte array.
 long readUInt32()
          Read an unsigned 32 bit integer from the input stream and zero extend it to a long to not lose any precision.
 int readUniqueID()
          Read a three byte record unique ID value and return it as an int value.
 java.lang.String toString()
          Show something semi-useful for this Palm database when the object is printed.
 
Methods inherited from class java.io.RandomAccessFile
close, getChannel, getFD, getFilePointer, length, read, read, read, readBoolean, readByte, readChar, readDouble, readFloat, readFully, readFully, readInt, readLine, readLong, readShort, readUnsignedByte, readUnsignedShort, readUTF, seek, setLength, skipBytes, write, write, write, writeBoolean, writeByte, writeBytes, writeChar, writeChars, writeDouble, writeFloat, writeInt, writeLong, writeShort, writeUTF
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

DB_FLAG_READ_ONLY

public static final int DB_FLAG_READ_ONLY
Database is read-only while in Palm memory.

See Also:
Constant Field Values

DB_FLAG_DIRTY_APPINFO

public static final int DB_FLAG_DIRTY_APPINFO
Set if the appInfoArea has changed. Treated separately because the appInfoArea is not a normal database record. This flag should never be set in a database file; it has meaning only on a device.

See Also:
Constant Field Values

DB_FLAG_BACKUP

public static final int DB_FLAG_BACKUP
Set if the database should be backed up during the next sync procedure.

See Also:
Constant Field Values

DB_FLAG_NEWER_OKAY

public static final int DB_FLAG_NEWER_OKAY
Set if it is acceptable for a database with the same name but higher version number to be installed over this database.

See Also:
Constant Field Values

DB_FLAG_RESET_ON_INSTALL

public static final int DB_FLAG_RESET_ON_INSTALL
Set if the device must be reset after this database has been installed.

See Also:
Constant Field Values

DB_FLAG_NO_COPY

public static final int DB_FLAG_NO_COPY
Set if the device should not permit this database to be beamed or copied to another device. A form of simple and easily bypassed copy control.

See Also:
Constant Field Values

REC_FLAG_SECRET

public static final short REC_FLAG_SECRET
If set, Record is marked as "secret" and some Palm apps can selectively hide secret records unless a password is entered. Just a convenience feature as it offers no real security. This is the only record flag which should ever need to be (optionally) set in the database file. The other flags only have meaning at runtime on the device.

See Also:
Constant Field Values

REC_FLAG_BUSY

public static final short REC_FLAG_BUSY
On a device, it means the record is open for writing. Should never be set for a record in a database file.

See Also:
Constant Field Values

REC_FLAG_DIRTY

public static final short REC_FLAG_DIRTY
Set if the record has been modified and must be backed up during the next sync procedure.

See Also:
Constant Field Values

REC_FLAG_DELETE

public static final short REC_FLAG_DELETE
Set if the record has been marked for deletion. During the next sync procedure, this record will be removed from the on-device database and will be saved in some other location on the PC side.

See Also:
Constant Field Values

DB_NAME_LENGTH

public static final int DB_NAME_LENGTH
The length of the database name field in the Palm OS database header.

See Also:
Constant Field Values

DB_HEADER_LENGTH

public static final int DB_HEADER_LENGTH
The length of a Palm OS database header up to and including the numRecords field. Does not include the length of the record entry array which follows.

See Also:
Constant Field Values

PALM_CTIME_OFFSET

public static final int PALM_CTIME_OFFSET
This is the offset from the Palm OS epoch to the standard UNIX epoch. It corresponds to 2,082,844,800 seconds. Add this value to a UNIX time value to get the corresponding Palm OS time value.

See Also:
Constant Field Values

dbName

private java.lang.String dbName
The Palm database name. Required to be unique on a Palm OS device and limited to a length of 0x20 characters. Name may occupy all 0x20 bytes in which case it will not be NUL terminated.


flags

private int flags
Palm database flags. Stored in a UInt16.


version

private int version
Database version number, defined by the application. Stored in a UInt16.


creationTime

private long creationTime
Creation time in seconds of the database. Time is based on the Palm OS epoch of January 1, 1904. Value is stored in a UInt32.


modificationTime

private long modificationTime
Last modification time in seconds of the database. Time is based on the Palm OS epoch of January 1, 1904. Value is stored in a UInt32.


lastBackupTime

private long lastBackupTime
Time of the last database backup in seconds. Time is based on the Palm OS epoch of January 1, 1904. Value is stored in a UInt32.


modificationNumber

private long modificationNumber
Database's modification number, defined by the application. Value is stored in a UInt32.


applicationInfoIDPtr

private long applicationInfoIDPtr
Byte offset from beginning of the file to the appInfoArea block. If one is present it will be the first block in the data area. Rarely used. Value type is a "LocalID" stored in a UInt32.


sortInfoIDPtr

private long sortInfoIDPtr
Byte offset from beginning of the file to the sortInfoArea block. If one is present it will occur immediately after the appInfoArea (if present). Rarely, if ever, used and Palm OS does not support backing up this area during a sync. Value type is a "LocalID" stored in a UInt32.


dbTypeID

private long dbTypeID
Palm OS database type ID string. Stored as a four byte literal, such as 'zTXT' or 'appl'.


dbCreatorID

private long dbCreatorID
Palm OS database creator ID string. Stored as a four byte literal, such as 'GPlm' or 'PALM'.


uniqueIDSeed

private long uniqueIDSeed
Used as the base index for the record LocalID values. Record uniqueIDs are not guaranteed to persist through a sync or backup so this value is fairly arbitrary. Value is stored in a UInt32.


nextRecordListIDPtr

private long nextRecordListIDPtr
In memory a Palm database can have multiple record list structures, though in practice there is never more than one. This would be the localID of the next record list, but in a database file it should always be 0. Value type is a "LocalID" stored in a UInt32.


numRecords

private int numRecords
Number of records in this database. Stored in a UInt16.


recordOffsets

private java.util.Vector<java.lang.Long> recordOffsets
This array contains the byte offsets for the beginning of each record in this database. Offsets are counted from the start of the file. Value type is a "LocalID" stored in a UInt32.


recordFlags

private java.util.Vector<java.lang.Integer> recordFlags
This array contains the attribute flags for each record in the database. See the REC_FLAG_* values for the meanings of these flags. Value is stored in a byte after the record's offset value.


recordIDs

private java.util.Vector<java.lang.Integer> recordIDs
This array contains the unique IDs for each record in the database. For a newly created database file, these will all be zero. On the device, each of these values will be unique. For a database backed up off a device, these values may or may not be set. In any case, they have meaning only to Palm OS and should not be used by anyone else. Value type is a "LocalID" and, together with the recordFlags byte, is stored in a single UInt32. The recordFlags byte occupies the MSB and the uniqueID bytes occupy the three LSBs.

Constructor Detail

PalmDB

public PalmDB(java.io.File pdbFile)
       throws java.io.IOException
Create a complete PalmDB object from the contents of the specified pdb file.

Parameters:
pdbFile - an existing pdb file to load and parse into a PalmDB.
Throws:
java.io.IOException - if an error occurs while reading the header.
Method Detail

getDbName

public java.lang.String getDbName()
Returns:
the database name

getFlags

public int getFlags()
Returns:
the database flags

getVersion

public int getVersion()
Returns:
the database version

getCreationTime

public long getCreationTime()
Returns:
the database creation time in seconds, measured from the standard Palm OS epoch

getModificationTime

public long getModificationTime()
Returns:
the database modification time in seconds, measured from the standard Palm OS epoch

getLastBackupTime

public long getLastBackupTime()
Returns:
the time of the last database backup in seconds, measured from the standard Palm OS epoch

getModificationNumber

public long getModificationNumber()
Returns:
the application defined modification number

getDbTypeID

public long getDbTypeID()
Returns:
the database type ID, stored as an int but interpreted as a four byte character literal, such as 'appl'

getDbCreatorID

public long getDbCreatorID()
Returns:
the database creator ID, stored as an int but interpreted as a four byte character literal, such as 'GPlm'

getUniqueIDSeed

public long getUniqueIDSeed()
Returns:
the unique ID seed used by Palm OS when generating record unique ID values

getNumRecords

public int getNumRecords()
Returns:
the number of records in this database

getApplicationInfoIDPtr

public long getApplicationInfoIDPtr()
Returns:
the applicationInfoID pointer for this database

getSortInfoIDPtr

public long getSortInfoIDPtr()
Returns:
the sortInfoID pointer for this database

getNextRecordListIDPtr

public long getNextRecordListIDPtr()
Returns:
the LocalID of the next record list structure in this database

getRecordOffsets

public java.util.Vector<java.lang.Long> getRecordOffsets()
Returns:
the vector of record byte offsets with one element for each record in this database

getRecordFlags

public java.util.Vector<java.lang.Integer> getRecordFlags()
Returns:
the vector of record flags with one element for each database record

getRecordIDs

public java.util.Vector<java.lang.Integer> getRecordIDs()
Returns:
the vector of unique record ID values with one element for each record in this database

readRecord

public byte[] readRecord(int recIndex)
                  throws java.io.IOException,
                         java.lang.ArrayIndexOutOfBoundsException
Read the specified record and return it as a byte array.

Parameters:
recIndex - the zero-based record index to read.
Returns:
the requested record data in a byte array.
Throws:
java.io.IOException - if an I/O error occurs such as all bytes of a record not being read in.
java.lang.ArrayIndexOutOfBoundsException - if the requested record index does not exist.

readUInt32

public long readUInt32()
                throws java.io.IOException
Read an unsigned 32 bit integer from the input stream and zero extend it to a long to not lose any precision.

Returns:
an unsigned 32 bit int zero extended to a long.
Throws:
java.io.IOException - for any I/O error while reading the input stream.

readUniqueID

public int readUniqueID()
                 throws java.io.IOException
Read a three byte record unique ID value and return it as an int value.

Returns:
a three byte unique ID stored in an int.
Throws:
java.io.IOException - for any I/O error while reading the input stream.

toString

public java.lang.String toString()
Show something semi-useful for this Palm database when the object is printed.

Overrides:
toString in class java.lang.Object
Returns:
a String representation of this database.

readHeader

private void readHeader()
                 throws java.io.IOException
Read in a Palm OS database header and set the appropriate fields with data from the header. This method will read all values up to the number of records field as well as the record entry array which follows. This data is common to both PDB and PRC files.

Throws:
java.io.IOException - if an I/O error occurs while reading the header.

main

public static void main(java.lang.String[] args)
Useful for loading and testing the PalmDB class from the command line. Prints the header values from a database. Optionally it will print the values from the record entry array (offsets, flags, ids). And, also optionally, it can output the contents of a specified record in both hex and printable ASCII.

Parameters:
args - the first argument is the input filename, the second is an optional boolean (0/1) toggling whether to print the record entry array, and the third is an optional index of a record to print.