NAME¶
Palm::PDB - Parse Palm database files.
SYNOPSIS¶
    use Palm::PDB;
    use SomeHelperClass;
    $pdb = new Palm::PDB;
    $pdb->Load("myfile.pdb");
    # Manipulate records in $pdb
    $pdb->Write("myotherfile.pdb");
(Note: yes, you do want to use "Palm::PDB", even if you're dealing
  with some other type of database. $pdb will be reblessed to the appropriate
  type by "$pdb->Load".)
DESCRIPTION¶
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.
METHODS¶
new¶
  $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().
RegisterPDBHandlers¶
  &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:
  - 
  
  
 
  - Databases whose creator is "fOOf" and whose type is
      "DATA".
 
  - 
  
  
 
  - Databases whose creator is "BarB", of any type.
 
  - 
  
  
 
  - Databases with any creator whose type is "BazQ".
 
  - 
  
  
 
  - Databases whose creator is "Fred", of any type.
 
RegisterPRCHandlers¶
  &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" ]
            );
    }
Load¶
  $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").
$filename may also be an open file handle (as long as it's seekable). This
  allows for manipulating databases in memory structures.
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:
  - 1.
 
  - A typespec that specifies both the database's creator and its type
      exactly.
 
  - 2.
 
  - A typespec that specifies the database's type and has a wildcard
      for the creator (this is rarely used).
 
  - 3.
 
  - A typespec that specifies the database's creator and has a wildcard
      for the type.
 
  - 4.
 
  - A typespec that has wildcards for both the creator and type.
 
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:
  - $pdb->{"name"}
 
  - The name of the database.
 
  - $pdb->{"attributes"}{"ResDB"}
 
  
  - $pdb->{"attributes"}{"ReadOnly"}
 
  
  - $pdb->{"attributes"}{"AppInfoDirty"}
 
  
  - $pdb->{"attributes"}{"Backup"}
 
  
  - $pdb->{"attributes"}{"OKToInstallNewer"}
 
  
  - $pdb->{"attributes"}{"ResetAfterInstall"}
 
  
  - $pdb->{"attributes"}{"CopyPrevention"}
 
  
  - $pdb->{"attributes"}{"Stream"}
 
  
  - $pdb->{"attributes"}{"Hidden"}
 
  
  - $pdb->{"attributes"}{"LaunchableData"}
 
  
  - $pdb->{"attributes"}{"Recyclable"}
 
  
  - $pdb->{"attributes"}{"Bundle"}
 
  
  - $pdb->{"attributes"}{"Open"}
 
  - These are the attribute flags from the database header. Each is true iff
      the corresponding flag is set.
    
    The "LaunchableData" attribute is set on PQAs.
 
  - $pdb->{"version"}
 
  - The database's version number. An integer.
 
  - $pdb->{"ctime"}
 
  
  - $pdb->{"mtime"}
 
  
  - $pdb->{"baktime"}
 
  - The database's creation time, last modification time, and time of last
      backup, in Unix "time_t" format (seconds since Jan. 1,
    1970).
 
  - $pdb->{"modnum"}
 
  - The database's modification number. An integer.
 
  - $pdb->{"type"}
 
  - The database's type. A four-character string.
 
  - $pdb->{"creator"}
 
  - The database's creator. A four-character string.
 
  - $pdb->{"uniqueIDseed"}
 
  - The database's unique ID seed. An integer.
 
  - $pdb->{"2NULs"}
 
  - The two NUL bytes that appear after the record index and the AppInfo
      block. Included here because every once in a long while, they are not
      NULs, for some reason.
 
  - $pdb->{"appinfo"}
 
  - The AppInfo block, as returned by the $pdb->ParseAppInfoBlock()
      helper method.
 
  - $pdb->{"sort"}
 
  - The sort block, as returned by the $pdb->ParseSortBlock() helper
      method.
 
  - @{$pdb->{"records"}}
 
  - The list of records in the database, as returned by the $pdb->
      ParseRecord() helper method. Resource databases do not have
    this.
 
  - @{$pdb->{"resources"}}
 
  - The list of resources in the database, as returned by the $pdb->
      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.
Write¶
  $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.
$filename may also be an open file handle (as long as it's seekable). This
  allows for manipulating databases in memory structures.
Write() uses the following helper methods:
  - 
  
  
 
  - PackAppInfoBlock()
 
  - 
  
  
 
  - PackSortBlock()
 
  - 
  
  
 
  - PackResource() or PackRecord()
 
See also "HELPER CLASSES".
new_Record¶
  $record = Palm::PDB->new_Record();
  $record = new_Record Palm::PDB;
Creates a new record, with the bare minimum needed:
        $record->{'category'}
        $record->{'attributes'}{'Dirty'}
        $record->{'id'}
The ``Dirty'' attribute is originally set, since this function will usually be
  called to create records to be added to a database.
"new_Record" does 
not add the new record to a PDB. For that,
  you want "append_Record".
is_Dirty¶
  $pdb->Write( $fname ) if $pdb->is_Dirty();
Returns non-zero if any of the in-memory elements of the database have been
  changed. This includes changes via function calls (any call that changes the
  $pdb's "last modification" time) as well as testing the
  "dirty" status of attributes where possible (i.e. AppInfo, records,
  but not resource entries).
append_Record¶
  $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.
new_Resource¶
  $resource = Palm::PDB->new_Resource();
  $resource = new_Resource Palm::PDB;
Creates a new resource and initializes
        $resource->{type}
        $resource->{id}
append_Resource¶
  $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.
findRecordByID¶
  $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.
delete_Record¶
  $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.
remove_Record¶
        for (@{$pdb->{'records'}})
        {
                $pdb->remove_Record( $_ ) if $_->{attributes}{deleted};
        }
Removes $record from the database. This differs from "delete_Record"
  in that it's an actual deletion rather than just setting a flag.
This method updates $pdb's "last modification" time.
HELPER CLASSES¶
$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.
ParseAppInfoBlock¶
  $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}.
PackAppInfoBlock¶
  $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.
ParseSortBlock¶
  $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}.
PackSortBlock¶
  $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.
ParseRecord¶
  $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
                archive  => bool,       # True iff to be archived
              },
          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;
    }
PackRecord¶
  $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.
ParseResource¶
  $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.
PackResource¶
  $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.
BUGS¶
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.
SOURCE CONTROL¶
The source is in Github:
        http://github.com/briandfoy/p5-Palm/tree/master
AUTHOR¶
Alessandro Zummo, "<a.zummo@towertech.it>"
Currently maintained by brian d foy, "<bdfoy@cpan.org>"
SEE ALSO¶
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.