.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Palm::PDB 3pm" .TH Palm::PDB 3pm "2021-01-02" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Palm::PDB \- Parse Palm database files .SH "VERSION" .IX Header "VERSION" This document describes version 1.400 of Palm::PDB, released March 7, 2015 as part of Palm-PDB version 1.400. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use Palm::PDB; \& use SomeHelperClass; \& \& $pdb = Palm::PDB\->new; \& $pdb\->Load("myfile.pdb"); \& \& # Manipulate records in $pdb \& \& $pdb\->Write("myotherfile.pdb"); .Ve .PP (Note: yes, you do want to use \f(CW\*(C`Palm::PDB\*(C'\fR, even if you're dealing with some other type of database. \f(CW$pdb\fR will be reblessed to the appropriate type by \f(CW\*(C`$pdb\->Load\*(C'\fR.) .SH "DESCRIPTION" .IX Header "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 (\f(CW\*(C`.pdb\*(C'\fR) and Palm Resource (\f(CW\*(C`.prc\*(C'\fR) files. .PP By itself, the \s-1PDB\s0 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. .PP The Palm::PDB module encapsulates the common work of parsing the structure of a Palm database. The \fBLoad()\fR function reads the file, then passes the individual chunks (header, records, etc.) to application-specific functions for processing. Similarly, the \&\fBWrite()\fR function calls application-specific functions to get the individual chunks, then writes them to a file. .SH "METHODS" .IX Header "METHODS" .SS "new" .IX Subsection "new" .Vb 1 \& $new = Palm::PDB\->new; .Ve .PP Creates a new \s-1PDB.\s0 \f(CW$new\fR is a reference to an anonymous hash. Some of its elements have special significance. See \fBLoad()\fR. .SS "RegisterPDBHandlers" .IX Subsection "RegisterPDBHandlers" .Vb 1 \& &Palm::PDB::RegisterPDBHandlers("classname", typespec...); .Ve .PP Typically: .PP .Vb 3 \& &Palm::PDB::RegisterPDBHandlers(_\|_PACKAGE_\|_, \& [ "FooB", "DATA" ], \& ); .Ve .PP The \f(CW$pdb\fR\->\fBLoad()\fR method acts as a virtual constructor. When it reads the header of a \f(CW\*(C`.pdb\*(C'\fR file, it looks up the file's creator and type in a set of tables, and reblesses \f(CW$pdb\fR into a class capable of parsing the application-specific parts of the file (AppInfo block, records, etc.) .PP \&\fBRegisterPDBHandlers()\fR adds entries to these tables; it says that any file whose creator and/or type match any of the \fItypespec\fRs (there may be several) should be reblessed into the class \fIclassname\fR. .PP Note that \fBRegisterPDBHandlers()\fR applies only to record databases (\f(CW\*(C`.pdb\*(C'\fR files). For resource databases, see \&\fBRegisterPRCHandlers()\fR. .PP \&\fBRegisterPDBHandlers()\fR is typically called in the \fBimport()\fR function of a helper class. In this case, the class is registering itself, and it is simplest just to use \f(CW\*(C`_\|_PACKAGE_\|_\*(C'\fR for the package name: .PP .Vb 2 \& package PalmFoo; \& use Palm::PDB; \& \& sub import \& { \& &Palm::PDB::RegisterPDBHandlers(_\|_PACKAGE_\|_, \& [ "FooZ", "DATA" ] \& ); \& } .Ve .PP A \fItypespec\fR 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 \fItypespec\fR is a string, it is equivalent to specifying that string as the database's creator, and a wildcard as its type. .PP The creator and type should be either four-character strings, or the empty string. An empty string represents a wildcard. Thus: .PP .Vb 6 \& &Palm::PDB::RegisterPDBHandlers("MyClass", \& [ "fOOf", "DATA" ], \& [ "BarB", "" ], \& [ "", "BazQ" ], \& "Fred" \& ); .Ve .PP Class MyClass will handle: .IP "\(bu" 4 Databases whose creator is \f(CW\*(C`fOOf\*(C'\fR and whose type is \f(CW\*(C`DATA\*(C'\fR. .IP "\(bu" 4 Databases whose creator is \f(CW\*(C`BarB\*(C'\fR, of any type. .IP "\(bu" 4 Databases with any creator whose type is \f(CW\*(C`BazQ\*(C'\fR. .IP "\(bu" 4 Databases whose creator is \f(CW\*(C`Fred\*(C'\fR, of any type. .SS "RegisterPRCHandlers" .IX Subsection "RegisterPRCHandlers" .Vb 1 \& &Palm::PDB::RegisterPRCHandlers("classname", typespec...); .Ve .PP Typically: .PP .Vb 3 \& &Palm::PDB::RegisterPRCHandlers(_\|_PACKAGE_\|_, \& [ "FooZ", "CODE" ], \& ); .Ve .PP \&\fBRegisterPRCHandlers()\fR is similar to \&\fBRegisterPDBHandlers()\fR, but specifies a class to handle resource database (\f(CW\*(C`.prc\*(C'\fR) files. .PP A class for parsing applications should begin with: .PP .Vb 2 \& package PalmApps; \& use Palm::PDB; \& \& sub import \& { \& &Palm::PDB::RegisterPRCHandlers(_\|_PACKAGE_\|_, \& [ "", "appl" ] \& ); \& } .Ve .SS "Load" .IX Subsection "Load" .Vb 1 \& $pdb\->Load($filename); .Ve .PP Reads the file \f(CW$filename\fR, parses it, reblesses \f(CW$pdb\fR to the appropriate class, and invokes appropriate methods to parse the application-specific parts of the database (see \*(L"\s-1HELPER CLASS METHODS\*(R"\s0). .PP \&\f(CW$filename\fR may also be an open file handle (as long as it's seekable). This allows for manipulating databases in memory structures. .PP \&\fBLoad()\fR uses the \fItypespec\fRs given to \fBRegisterPDBHandlers()\fR and \&\fBRegisterPRCHandlers()\fR when deciding how to rebless \f(CW$pdb\fR. For record databases, it uses the \fItypespec\fRs passed to \fBRegisterPDBHandlers()\fR, and for resource databases, it uses the \fItypespec\fRs passed to \&\fBRegisterPRCHandlers()\fR. .PP \&\fBLoad()\fR looks for matching \fItypespec\fRs in the following order, from most to least specific: .IP "1." 4 A \fItypespec\fR that specifies both the database's creator and its type exactly. .IP "2." 4 A \fItypespec\fR that specifies the database's type and has a wildcard for the creator (this is rarely used). .IP "3." 4 A \fItypespec\fR that specifies the database's creator and has a wildcard for the type. .IP "4." 4 A \fItypespec\fR that has wildcards for both the creator and type. .PP Thus, if the database has creator \*(L"FooZ\*(R" and type \*(L"\s-1DATA\*(R",\s0 \fBLoad()\fR will first look for \*(L"FooZ\*(R"/\*(L"\s-1DATA\*(R",\s0 then "\*(L"/\*(R"\s-1DATA\*(L",\s0 then \*(R"FooZ\*(L"/\*(R"\*(L", and finally will fall back on \*(R"\*(L"/\*(R"" (the universal default). .PP After \fBLoad()\fR returns, \f(CW$pdb\fR may contain the following fields: .ie n .IP "$pdb\->{""name""}" 4 .el .IP "\f(CW$pdb\fR\->{``name''}" 4 .IX Item "$pdb->{name}" The name of the database. .ie n .IP "$pdb\->{""attributes""}{""ResDB""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``ResDB''}" 4 .IX Item "$pdb->{attributes}{ResDB}" .PD 0 .ie n .IP "$pdb\->{""attributes""}{""ReadOnly""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``ReadOnly''}" 4 .IX Item "$pdb->{attributes}{ReadOnly}" .ie n .IP "$pdb\->{""attributes""}{""AppInfoDirty""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``AppInfoDirty''}" 4 .IX Item "$pdb->{attributes}{AppInfoDirty}" .ie n .IP "$pdb\->{""attributes""}{""Backup""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``Backup''}" 4 .IX Item "$pdb->{attributes}{Backup}" .ie n .IP "$pdb\->{""attributes""}{""OKToInstallNewer""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``OKToInstallNewer''}" 4 .IX Item "$pdb->{attributes}{OKToInstallNewer}" .ie n .IP "$pdb\->{""attributes""}{""ResetAfterInstall""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``ResetAfterInstall''}" 4 .IX Item "$pdb->{attributes}{ResetAfterInstall}" .ie n .IP "$pdb\->{""attributes""}{""CopyPrevention""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``CopyPrevention''}" 4 .IX Item "$pdb->{attributes}{CopyPrevention}" .ie n .IP "$pdb\->{""attributes""}{""Stream""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``Stream''}" 4 .IX Item "$pdb->{attributes}{Stream}" .ie n .IP "$pdb\->{""attributes""}{""Hidden""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``Hidden''}" 4 .IX Item "$pdb->{attributes}{Hidden}" .ie n .IP "$pdb\->{""attributes""}{""LaunchableData""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``LaunchableData''}" 4 .IX Item "$pdb->{attributes}{LaunchableData}" .ie n .IP "$pdb\->{""attributes""}{""Recyclable""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``Recyclable''}" 4 .IX Item "$pdb->{attributes}{Recyclable}" .ie n .IP "$pdb\->{""attributes""}{""Bundle""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``Bundle''}" 4 .IX Item "$pdb->{attributes}{Bundle}" .ie n .IP "$pdb\->{""attributes""}{""Open""}" 4 .el .IP "\f(CW$pdb\fR\->{``attributes''}{``Open''}" 4 .IX Item "$pdb->{attributes}{Open}" .PD These are the attribute flags from the database header. Each is true iff the corresponding flag is set. .Sp The \*(L"LaunchableData\*(R" attribute is set on PQAs. .ie n .IP "$pdb\->{""version""}" 4 .el .IP "\f(CW$pdb\fR\->{``version''}" 4 .IX Item "$pdb->{version}" The database's version number. An integer. .ie n .IP "$pdb\->{""ctime""}" 4 .el .IP "\f(CW$pdb\fR\->{``ctime''}" 4 .IX Item "$pdb->{ctime}" .PD 0 .ie n .IP "$pdb\->{""mtime""}" 4 .el .IP "\f(CW$pdb\fR\->{``mtime''}" 4 .IX Item "$pdb->{mtime}" .ie n .IP "$pdb\->{""baktime""}" 4 .el .IP "\f(CW$pdb\fR\->{``baktime''}" 4 .IX Item "$pdb->{baktime}" .PD The database's creation time, last modification time, and time of last backup, in Unix \f(CW\*(C`time_t\*(C'\fR format (seconds since Jan. 1, 1970). .ie n .IP "$pdb\->{""modnum""}" 4 .el .IP "\f(CW$pdb\fR\->{``modnum''}" 4 .IX Item "$pdb->{modnum}" The database's modification number. An integer. .ie n .IP "$pdb\->{""type""}" 4 .el .IP "\f(CW$pdb\fR\->{``type''}" 4 .IX Item "$pdb->{type}" The database's type. A four-character string. .ie n .IP "$pdb\->{""creator""}" 4 .el .IP "\f(CW$pdb\fR\->{``creator''}" 4 .IX Item "$pdb->{creator}" The database's creator. A four-character string. .ie n .IP "$pdb\->{""uniqueIDseed""}" 4 .el .IP "\f(CW$pdb\fR\->{``uniqueIDseed''}" 4 .IX Item "$pdb->{uniqueIDseed}" The database's unique \s-1ID\s0 seed. An integer. .ie n .IP "$pdb\->{""2NULs""}" 4 .el .IP "\f(CW$pdb\fR\->{``2NULs''}" 4 .IX Item "$pdb->{2NULs}" The two \s-1NUL\s0 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. .ie n .IP "$pdb\->{""appinfo""}" 4 .el .IP "\f(CW$pdb\fR\->{``appinfo''}" 4 .IX Item "$pdb->{appinfo}" The AppInfo block, as returned by the \f(CW$pdb\fR\->\fBParseAppInfoBlock()\fR helper method. .ie n .IP "$pdb\->{""sort""}" 4 .el .IP "\f(CW$pdb\fR\->{``sort''}" 4 .IX Item "$pdb->{sort}" The sort block, as returned by the \f(CW$pdb\fR\->\fBParseSortBlock()\fR helper method. .ie n .IP "@{$pdb\->{""records""}}" 4 .el .IP "@{$pdb\->{``records''}}" 4 .IX Item "@{$pdb->{records}}" The list of records in the database, as returned by the \&\f(CW$pdb\fR\->\fBParseRecord()\fR helper method. Resource databases do not have this. .ie n .IP "@{$pdb\->{""resources""}}" 4 .el .IP "@{$pdb\->{``resources''}}" 4 .IX Item "@{$pdb->{resources}}" The list of resources in the database, as returned by the \&\f(CW$pdb\fR\->\fBParseResource()\fR helper method. Record databases do not have this. .PP All of these fields may be set by hand, but should conform to the format given above. .SS "Write" .IX Subsection "Write" .Vb 1 \& $pdb\->Write($filename); .Ve .PP Invokes methods in helper classes to get the application-specific parts of the database, then writes the database to the file \&\f(CW$filename\fR. .PP \&\f(CW$filename\fR may also be an open file handle (as long as it's seekable). This allows for manipulating databases in memory structures. .PP \&\fBWrite()\fR uses the following helper methods: .IP "\fBPackAppInfoBlock()\fR" 4 .IX Item "PackAppInfoBlock()" .PD 0 .IP "\fBPackSortBlock()\fR" 4 .IX Item "PackSortBlock()" .IP "\fBPackResource()\fR or \fBPackRecord()\fR" 4 .IX Item "PackResource() or PackRecord()" .PD .PP See also \*(L"\s-1HELPER CLASS METHODS\*(R"\s0. .SS "new_Record" .IX Subsection "new_Record" .Vb 1 \& $record = Palm::PDB\->new_Record(); .Ve .PP Creates a new record, with the bare minimum needed: .PP .Vb 3 \& $record\->{\*(Aqcategory\*(Aq} \& $record\->{\*(Aqattributes\*(Aq}{\*(AqDirty\*(Aq} \& $record\->{\*(Aqid\*(Aq} .Ve .PP The ``Dirty'' attribute is originally set, since this function will usually be called to create records to be added to a database. .PP \&\f(CW\*(C`new_Record\*(C'\fR does \fBnot\fR add the new record to a \s-1PDB.\s0 For that, you want \f(CW\*(C`append_Record\*(C'\fR. .SS "is_Dirty" .IX Subsection "is_Dirty" .Vb 1 \& $pdb\->Write( $fname ) if $pdb\->is_Dirty(); .Ve .PP 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 \f(CW$pdb\fR's \*(L"last modification\*(R" time) as well as testing the \&\*(L"dirty\*(R" status of attributes where possible (i.e. AppInfo, records, but not resource entries). .SS "append_Record" .IX Subsection "append_Record" .Vb 2 \& $record = $pdb\->append_Record; \& $record2 = $pdb\->append_Record($record1); .Ve .PP If called without any arguments, creates a new record with \&\fBnew_Record()\fR, and appends it to \f(CW$pdb\fR. .PP If given a reference to a record, appends that record to @{$pdb\->{records}}. .PP Returns a reference to the newly-appended record. .PP This method updates \f(CW$pdb\fR's \*(L"last modification\*(R" time. .SS "new_Resource" .IX Subsection "new_Resource" .Vb 1 \& $resource = Palm::PDB\->new_Resource(); .Ve .PP Creates a new resource and initializes .PP .Vb 2 \& $resource\->{type} \& $resource\->{id} .Ve .SS "append_Resource" .IX Subsection "append_Resource" .Vb 2 \& $resource = $pdb\->append_Resource; \& $resource2 = $pdb\->append_Resource($resource1); .Ve .PP If called without any arguments, creates a new resource with \&\fBnew_Resource()\fR, and appends it to \f(CW$pdb\fR. .PP If given a reference to a resource, appends that resource to @{$pdb\->{resources}}. .PP Returns a reference to the newly-appended resource. .PP This method updates \f(CW$pdb\fR's \*(L"last modification\*(R" time. .SS "findRecordByID" .IX Subsection "findRecordByID" .Vb 1 \& $record = $pdb\->findRecordByID($id); .Ve .PP Looks through the list of records in \f(CW$pdb\fR, and returns a reference to the record with \s-1ID\s0 \f(CW$id\fR, or the undefined value if no such record was found. .SS "delete_Record" .IX Subsection "delete_Record" .Vb 1 \& $pdb\->delete_Record($record, $expunge); .Ve .PP Marks \f(CW$record\fR for deletion, so that it will be deleted from the database at the next sync. .PP If \f(CW$expunge\fR is false or omitted, the record will be marked for deletion with archival. If \f(CW$expunge\fR is true, the record will be marked for deletion without archival. .PP This method updates \f(CW$pdb\fR's \*(L"last modification\*(R" time. .SS "remove_Record" .IX Subsection "remove_Record" .Vb 4 \& for (@{ $pdb\->{\*(Aqrecords\*(Aq} }) \& { \& $pdb\->remove_Record( $_ ) if $_\->{attributes}{deleted}; \& } .Ve .PP Removes \f(CW$record\fR from the database. This differs from \f(CW\*(C`delete_Record\*(C'\fR in that it's an actual deletion rather than just setting a flag. .PP This method updates \f(CW$pdb\fR's \*(L"last modification\*(R" time. .SH "HELPER CLASS METHODS" .IX Header "HELPER CLASS METHODS" \&\f(CW\*(C`$pdb\->Load()\*(C'\fR reblesses \f(CW$pdb\fR into a new class. This helper class is expected to convert raw data from the database into parsed representations of it, and vice-versa. .PP 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. .SS "ParseAppInfoBlock" .IX Subsection "ParseAppInfoBlock" .Vb 1 \& $appinfo = $pdb\->ParseAppInfoBlock($buf); .Ve .PP \&\f(CW$buf\fR is a string of raw data. \fBParseAppInfoBlock()\fR should parse this data and return it, typically in the form of a reference to an object or to an anonymous hash. .PP This method will not be called if the database does not have an AppInfo block. .PP The return value from \fBParseAppInfoBlock()\fR will be accessible as \&\f(CW\*(C`$pdb\->{appinfo}\*(C'\fR. .SS "PackAppInfoBlock" .IX Subsection "PackAppInfoBlock" .Vb 1 \& $buf = $pdb\->PackAppInfoBlock(); .Ve .PP This is the converse of \fBParseAppInfoBlock()\fR. It takes \f(CW$pdb\fR's AppInfo block, \f(CW\*(C`$pdb\->{appinfo}\*(C'\fR, and returns a string of binary data that can be written to the database file. .SS "ParseSortBlock" .IX Subsection "ParseSortBlock" .Vb 1 \& $sort = $pdb\->ParseSortBlock($buf); .Ve .PP \&\f(CW$buf\fR is a string of raw data. \fBParseSortBlock()\fR should parse this data and return it, typically in the form of a reference to an object or to an anonymous hash. .PP This method will not be called if the database does not have a sort block. .PP The return value from \fBParseSortBlock()\fR will be accessible as \&\f(CW\*(C`$pdb\->{sort}\*(C'\fR. .SS "PackSortBlock" .IX Subsection "PackSortBlock" .Vb 1 \& $buf = $pdb\->PackSortBlock(); .Ve .PP This is the converse of \fBParseSortBlock()\fR. It takes \f(CW$pdb\fR's sort block, \&\f(CW\*(C`$pdb\->{sort}\*(C'\fR, and returns a string of raw data that can be written to the database file. .SS "ParseRecord" .IX Subsection "ParseRecord" .Vb 10 \& $record = $pdb\->ParseRecord( \& offset => $offset, # Record\*(Aqs 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\*(Aqs category number \& id => $id, # Record\*(Aqs unique ID \& data => $buf, # Raw record data \& ); .Ve .PP \&\fBParseRecord()\fR takes the arguments listed above and returns a parsed representation of the record, typically as a reference to a record object or anonymous hash. .PP The output from \fBParseRecord()\fR will be appended to \&\f(CW\*(C`@{$pdb\->{records}}\*(C'\fR. The records appear in this list in the same order as they appear in the file. .PP \&\f(CW$offset\fR argument is not normally useful, but is included for completeness. .PP The fields in \f(CW%$attributes\fR are boolean values. They are true iff the record has the corresponding flag set. .PP \&\f(CW$category\fR 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. .PP A typical \fBParseRecord()\fR method has this general form: .PP .Vb 4 \& 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 \e%record; \& } .Ve .SS "PackRecord" .IX Subsection "PackRecord" .Vb 1 \& $buf = $pdb\->PackRecord($record); .Ve .PP The converse of \fBParseRecord()\fR. \fBPackRecord()\fR takes a record as returned by \fBParseRecord()\fR and returns a string of raw data that can be written to the database file. .PP \&\fBPackRecord()\fR is never called when writing a resource database. .SS "ParseResource" .IX Subsection "ParseResource" .Vb 6 \& $record = $pdb\->ParseResource( \& type => $type, # Resource type \& id => $id, # Resource ID \& offset => $offset, # Resource\*(Aqs offset in file \& data => $buf, # Raw resource data \& ); .Ve .PP \&\fBParseResource()\fR takes the arguments listed above and returns a parsed representation of the resource, typically as a reference to a resource object or anonymous hash. .PP The output from \fBParseResource()\fR will be appended to \&\f(CW\*(C`@{$pdb\->{resources}}\*(C'\fR. The resources appear in this list in the same order as they appear in the file. .PP \&\f(CW$type\fR is a four-character string giving the resource's type. .PP \&\f(CW$id\fR is an integer that uniquely identifies the resource amongst others of its type. .PP \&\f(CW$offset\fR is not normally useful, but is included for completeness. .SS "PackResource" .IX Subsection "PackResource" .Vb 1 \& $buf = $pdb\->PackResource($resource); .Ve .PP The converse of \fBParseResource()\fR. \fBPackResource()\fR takes a resource as returned by \fBPackResource()\fR and returns a string of raw data that can be written to the database file. .PP \&\fBPackResource()\fR is never called when writing a record database. .SH "SEE ALSO" .IX Header "SEE ALSO" Palm::Raw .PP Palm::Address .PP Palm::Datebook .PP Palm::Mail .PP Palm::Memo .PP Palm::ToDo .PP \&\fIPalm Database Files\fR, in the ColdSync distribution. .PP The Virtual Constructor (aka Factory Method) pattern is described in \&\fIDesign Patterns\fR, by Erich Gamma \fIet al.\fR, Addison-Wesley. .SH "CONFIGURATION AND ENVIRONMENT" .IX Header "CONFIGURATION AND ENVIRONMENT" Palm::PDB requires no configuration files or environment variables. .SH "INCOMPATIBILITIES" .IX Header "INCOMPATIBILITIES" None reported. .SH "BUGS AND LIMITATIONS" .IX Header "BUGS AND LIMITATIONS" These functions die too easily. They should return an error code. .PP Database manipulation is still an arcane art. .PP It may be possible to parse sort blocks further. .SH "AUTHORS" .IX Header "AUTHORS" Andrew Arensburger \f(CW\*(C`\*(C'\fR .PP Currently maintained by Christopher J. Madsen \f(CW\*(C`\*(C'\fR .PP Please report any bugs or feature requests to \f(CW\*(C`\*(C'\fR or through the web interface at . .PP You can follow or contribute to Palm-PDB's development at . .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is copyright (c) 2000 by Andrew Arensburger. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. .SH "DISCLAIMER OF WARRANTY" .IX Header "DISCLAIMER OF WARRANTY" \&\s-1BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE \*(L"AS IS\*(R" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.\s0 .PP \&\s-1IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENSE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE\s0 (\s-1INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE\s0), \s-1EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\s0