Palm::PDB - Parse Palm database files. |
Palm::PDB - Parse Palm database files.
use Palm::PDB; use SomeHelperClass;
$pdb = new Palm::PDB; $pdb->Load("myfile.pdb");
# Manipulate records in $pdb
$pdb->Write("myotherfile.pdb");
The Palm::PDB module provides a framework for reading and writing
database files for use on PalmOS devices such as the PalmPilot. It can
read and write both Palm Database (.pdb
) and Palm Resource
(.prc
) files.
By itself, the PDB module is not terribly useful; it is intended to be used in conjunction with supplemental modules for specific types of databases, such as Palm::Raw or Palm::Memo.
The Palm::PDB module encapsulates the common work of parsing the structure of a Palm database. The Load() function reads the file, then passes the individual chunks (header, records, etc.) to application-specific functions for processing. Similarly, the Write() function calls application-specific functions to get the individual chunks, then writes them to a file.
$new = new Palm::PDB();
Creates a new PDB. $new is a reference to an anonymous hash. Some of its elements have special significance. See Load().
&Palm::PDB::RegisterPDBHandlers("classname", typespec...);
Typically:
&Palm::PDB::RegisterPDBHandlers(__PACKAGE__, [ "FooB", "DATA" ], );
The $pdb->Load() method acts as a virtual constructor. When
it reads the header of a .pdb
file, it looks up the file's creator
and type in a set of tables, and reblesses $pdb into a class capable
of parsing the application-specific parts of the file (AppInfo block,
records, etc.)
RegisterPDBHandlers()
adds entries to these tables; it says that any
file whose creator and/or type match any of the typespecs (there
may be several) should be reblessed into the class classname.
Note that RegisterPDBHandlers()
applies only to record databases
(.pdb
files). For resource databases, see
RegisterPRCHandlers().
RegisterPDBHandlers()
is typically called in the import()
function of
a helper class. In this case, the class is registering itself, and it
is simplest just to use __PACKAGE__
for the package name:
package PalmFoo; use Palm::PDB;
sub import { &Palm::PDB::RegisterPDBHandlers(__PACKAGE__, [ "FooZ", "DATA" ] ); }
A typespec can be either a string, or an anonymous array with two elements. If it is an anonymous array, then the first element is the file's creator; the second element is its type. If a typespec is a string, it is equivalent to specifying that string as the database's creator, and a wildcard as its type.
The creator and type should be either four-character strings, or the empty string. An empty string represents a wildcard. Thus:
&Palm::PDB::RegisterPDBHandlers("MyClass", [ "fOOf", "DATA" ], [ "BarB", "" ], [ "", "BazQ" ], "Fred" );
Class MyClass will handle:
fOOf
and whose type is DATA
.
BarB
, of any type.
BazQ
.
Fred
, of any type.
&Palm::PDB::RegisterPRCHandlers("classname", typespec...);
Typically:
&Palm::PDB::RegisterPRCHandlers(__PACKAGE__, [ "FooZ", "CODE" ], );
RegisterPRCHandlers()
is similar to
RegisterPDBHandlers(), but specifies a class
to handle resource database (.prc
) files.
A class for parsing applications should begin with:
package PalmApps; use Palm::PDB;
sub import { &Palm::PDB::RegisterPRCHandlers(__PACKAGE__, [ "", "appl" ] ); }
$pdb->Load("filename");
Reads the file filename, parses it, reblesses $pdb to the appropriate class, and invokes appropriate methods to parse the application-specific parts of the database (see HELPER CLASSES).
Load()
uses the typespecs given to RegisterPDBHandlers()
and
RegisterPRCHandlers()
when deciding how to rebless $pdb. For record
databases, it uses the typespecs passed to RegisterPDBHandlers(),
and for resource databases, it uses the typespecs passed to
RegisterPRCHandlers().
Load()
looks for matching typespecs in the following order, from
most to least specific:
Thus, if the database has creator ``FooZ'' and type ``DATA'', Load()
will
first look for ``FooZ''/``DATA'', then ``''/``DATA'', then ``FooZ''/``'', and
finally will fall back on ``''/``'' (the universal default).
After Load()
returns, $pdb may contain the following fields:
time_t
format (seconds since Jan. 1, 1970).
ParseAppInfoBlock()
helper
method.
ParseSortBlock()
helper
method.
ParseRecord()
helper method. Resource databases do not have
this.
ParseResource()
helper method. Record databases do not have
this.
All of these fields may be set by hand, but should conform to the format given above.
$pdb->Write("filename");
Invokes methods in helper classes to get the application-specific parts of the database, then writes the database to the file filename.
Write()
uses the following helper methods:
PackAppInfoBlock()
PackSortBlock()
PackResource()
or PackRecord()
See also HELPER CLASSES.
$record = Palm::PDB->new_Record(); $record = new_Record Palm::PDB;
Creates a new record, with the bare minimum needed:
$record->{category} $record->{attributes}{expunged} $record->{attributes}{dirty} $record->{attributes}{deleted} $record->{attributes}{private} $record->{id}
The ``dirty'' attribute is originally set, since this function will usually be called to create records to be added to a database.
$record = $pdb->append_Record; $record2 = $pdb->append_Record($record1);
If called without any arguments, creates a new record with new_Record(), and appends it to $pdb.
If given a reference to a record, appends that record to @{$pdb->{records}}.
Returns a reference to the newly-appended record.
This method updates $pdb's ``last modification'' time.
$resource = Palm::PDB->new_Resource(); $resource = new_Resource Palm::PDB;
Creates a new resource and initializes
$resource->{type} $resource->{id}
$resource = $pdb->append_Resource; $resource2 = $pdb->append_Resource($resource1);
If called without any arguments, creates a new resource with new_Resource(), and appends it to $pdb.
If given a reference to a resource, appends that resource to @{$pdb->{resources}}.
Returns a reference to the newly-appended resource.
This method updates $pdb's ``last modification'' time.
$record = $pdb->findRecordByID($id);
Looks through the list of records in $pdb, and returns a reference to the record with ID $id, or the undefined value if no such record was found.
$pdb->delete_Record($record, $expunge);
Marks $record for deletion, so that it will be deleted from the database at the next sync.
If $expunge is false or omitted, the record will be marked for deletion with archival. If $expunge is true, the record will be marked for deletion without archival.
This method updates $pdb's ``last modification'' time.
$pdb->Load()
reblesses $pdb into a new class. This helper class is
expected to convert raw data from the database into parsed
representations of it, and vice-versa.
A helper class must have all of the methods listed below. The Palm::Raw class is useful if you don't want to define all of the required methods.
$appinfo = $pdb->ParseAppInfoBlock($buf);
$buf is a string of raw data. ParseAppInfoBlock()
should parse this
data and return it, typically in the form of a reference to an object
or to an anonymous hash.
This method will not be called if the database does not have an AppInfo block.
The return value from ParseAppInfoBlock()
will be accessible as
$pdb->{appinfo}.
$buf = $pdb->PackAppInfoBlock();
This is the converse of ParseAppInfoBlock(). It takes $pdb's AppInfo block, $pdb->{appinfo}, and returns a string of binary data that can be written to the database file.
$sort = $pdb->ParseSortBlock($buf);
$buf is a string of raw data. ParseSortBlock()
should parse this data
and return it, typically in the form of a reference to an object or to
an anonymous hash.
This method will not be called if the database does not have a sort block.
The return value from ParseSortBlock()
will be accessible as
$pdb->{sort}.
$buf = $pdb->PackSortBlock();
This is the converse of ParseSortBlock(). It takes $pdb's sort block, $pdb->{sort}, and returns a string of raw data that can be written to the database file.
$record = $pdb->ParseRecord( offset => $offset, # Record's offset in file attributes => # Record attributes { expunged => bool, # True iff expunged dirty => bool, # True iff dirty deleted => bool, # True iff deleted private => bool, # True iff private }, category => $category, # Record's category number id => $id, # Record's unique ID data => $buf, # Raw record data );
ParseRecord()
takes the arguments listed above and returns a parsed
representation of the record, typically as a reference to a record
object or anonymous hash.
The output from ParseRecord()
will be appended to
@{$pdb->{records}}. The records appear in this list in the
same order as they appear in the file.
$offset argument is not normally useful, but is included for completeness.
The fields in %$attributes are boolean values. They are true iff the record has the corresponding flag set.
$category is an integer in the range 0-15, which indicates which category the record belongs to. This is normally an index into a table given at the beginning of the AppInfo block.
A typical ParseRecord()
method has this general form:
sub ParseRecord { my $self = shift my %record = @_;
# Parse $self->{data} and put the fields into new fields in # $self.
delete $record{data}; # No longer useful return \%record; }
$buf = $pdb->PackRecord($record);
The converse of ParseRecord(). PackRecord()
takes a record as returned
by ParseRecord()
and returns a string of raw data that can be written
to the database file.
PackRecord()
is never called when writing a resource database.
$record = $pdb->ParseResource( type => $type, # Resource type id => $id, # Resource ID offset => $offset, # Resource's offset in file data => $buf, # Raw resource data );
ParseResource()
takes the arguments listed above and returns a parsed
representation of the resource, typically as a reference to a resource
object or anonymous hash.
The output from ParseResource()
will be appended to
@{$pdb->{resources}}. The resources appear in this list in
the same order as they appear in the file.
$type is a four-character string giving the resource's type.
$id is an integer that uniquely identifies the resource amongst others of its type.
$offset is not normally useful, but is included for completeness.
$buf = $pdb->PackResource($resource);
The converse of ParseResource(). PackResource()
takes a resource as
returned by PackResource()
and returns a string of raw data that can
be written to the database file.
PackResource()
is never called when writing a record database.
These functions die too easily. They should return an error code.
Database manipulation is still an arcane art.
It may be possible to parse sort blocks further.
Andrew Arensburger <arensb@ooblick.com>
Palm::Raw(3)
Palm::Address(3)
Palm::Datebook(3)
Palm::Mail(3)
Palm::Memo(3)
Palm::ToDo(3)
Palm Database Files, in the ColdSync distribution.
The Virtual Constructor (aka Factory Method) pattern is described in Design Patterns, by Erich Gamma et al., Addison-Wesley.
Palm::PDB - Parse Palm database files. |