Click here to Skip to main content
Click here to Skip to main content

Generate PDB files in C#

By , 10 Jan 2006
 

PDB Generator

Basics of Palm databases

Palm devices use two types of database files: PRC and PDB (i.e., .prc and .pdb). PRC is used for Palm OS databases that are application programs, and stores resources of the application, while the PDB (Pilot Database) is used for Palm OS databases that contain only data. Both databases have a unique key that is unique for each application. These databases can be manipulated like stream reading and stream writing. It contains an attribute bit called the Backup Bit. Setting this bit indicates that no custom conduit will be backing up the database and that the database should be backed up during the HotSync process. If you create a database on the Palm Pilot and set the Backup Bit, you will find a copy of the database in PDB format in the Backup directory on the computer with which the HotSync was performed.

This application reads a CSV or an XML file and creates a .pdb file.

Major Sections of the PDB File

A PDB file format contains three sections:

  1. Header section
  2. Recordlist section
  3. Datalist section

i. Header Section

The header section contains 78 bytes, containing the name of the database and other information. Also, contained is the ID of the database that is unique for an application (the ID is globally unique, and can be obtained from the Palm OS site), the type of the database, and other attributes. The PDBHeader class is used to create headers.

class PDBHeader
{
    #region Declarations
    char[] databaseName={'\0','\0','\0','\0','\0','\0','\0', 
                         '\0','\0','\0','\0','\0','\0','\0','\0',
                         '\0','\0','\0','\0','\0','\0','\0','\0',
                         '\0','\0','\0','\0','\0','\0','\0',
                         '\0','\0'};   // 32 Bytes

    UInt16 fileAttributes = 0X0008;    // 2 Bytes
    UInt16 version = 0X0000;           // 2 Bytes
    UInt32 creationDate;               // 4 Bytes
    UInt32 modificationDate;           // 4 Bytes
    UInt32 lastBackupDate;             // 4 Bytes
    UInt32 modification=0X0000;        // 4 Bytes
    UInt32 appInfoArea=0X0000;         // 4 Bytes
    UInt32 sortInfoArea=0X0000;        // 4 Bytes
    char[]  type={'d','a','t','a'};    // 4 Bytes
    char[]  creatorID;                 // 4 Bytes
    UInt32 uniqueID=0X0000;            // 4 Bytes
    UInt32 nextRecord=0X0000;          // 4 Bytes
    UInt16 numRecords;                 // 2 Bytes
    #endregion 

    #region Properties
    public UInt16 NumRecords
    {
        set
        {
            numRecords=value;
        }
        get
        {
            return numRecords;
        }
    }
    public DateTime CreationDate
    {
        set
        {
            TimeSpan ts=DateTime.Now-value;
            creationDate=(UInt32)ts.TotalSeconds;
        }
    }
    public DateTime ModificationDate
    {
        set
        {
            TimeSpan ts=DateTime.Now-value;
            modificationDate=(UInt32)ts.TotalSeconds;
        }
    }
    public DateTime LastBackupDate
    {
        set
        {
            TimeSpan ts=DateTime.Now-value;
            lastBackupDate=(UInt32)ts.TotalSeconds;
        }
    }

    public string CreatorID
    {
        set
        {
            if (value.Length==4)
            {
                creatorID=value.ToCharArray();
            }
            else
            {
                throw new PDBException("Creator ID" + 
                  " is invalid (must be 4 charactors)");;
            }
        }
        get
        {
            return new String(creatorID);
        }
    }

    public string DataBaseName
    {
        set
        {
            if (value.Length<=32)
            {
                databaseName=value.ToCharArray();
            }
            else
            {
                
                throw new PDBException("Database Name" + 
                             " Exceeds 32 Charactors");;
            }
        }
        get
        {
            return new String(databaseName);
        }
    }

    #endregion 

    #region Functions

    public PDBHeader()
    {
        // Palm databse store total number
        // of seconds since 01-01-1904
        TimeSpan ts=
          DateTime.Now-DateTime.Parse("01-01-1904");
        creationDate=(UInt32)ts.TotalSeconds;
        modificationDate=(UInt32)ts.TotalSeconds;
        lastBackupDate=(UInt32)ts.TotalSeconds;
        numRecords=0;
    }

    public override string ToString()
    {
        string getAll="";
        getAll+=HexEncoding.GetStringToChar(databaseName,32);
        getAll+=fileAttributes.ToString("X4");
        getAll+=version.ToString("X4");
        getAll+=creationDate.ToString("X8");
        getAll+=modificationDate.ToString("X8");
        
        
        getAll+=lastBackupDate.ToString("X8");        
        getAll+=modification.ToString("X8");
        getAll+=appInfoArea.ToString("X8");    
        getAll+=sortInfoArea.ToString("X8");
        getAll+=HexEncoding.GetStringToChar(type,4);
        getAll+=HexEncoding.GetStringToChar(creatorID,4);
        getAll+=uniqueID.ToString("X8");
        getAll+=nextRecord.ToString("X8");
        getAll+=numRecords.ToString("X4");

        return getAll;
    }

ii. RecordList Section

The size of the recordlist section depends on the number of records. Each record uses 8 bits to store record information. The PDBRecordList class is used to represent a recordlist.

class PDBRecordList
{
    #region Declarations
    UInt32 offset=0;   // 4 Bytes (Offset of the record)
    byte recordAttribute=0X40;
    char[] uniqueID={'\0','\0','\0'}; // 3 Bytes (Unique ID for each record)
    string dataRecord=""; // Record data for current record
    #endregion 

    #region Properties
    public string DataRecord
    {
        set
        {
            dataRecord=value;
        }
        get
        {
            return dataRecord;
        }
    }
    public UInt32 RecordOffset
    {
        set
        {
            offset=value;
        }
        get
        {
            return offset;
        }
    }
    #endregion 

    #region Functions
    public PDBRecordList(string str)
    {
        dataRecord=str;
    }
    public override string ToString()
    {

        string getAll="";
        getAll+=offset.ToString("X8");
        getAll+=recordAttribute.ToString("X2");        
        getAll+=HexEncoding.GetStringToChar(uniqueID,3);
        return getAll;
    }

    #endregion
}

iii. Data Section

It is the main section to store information related to the records. Each record is separated by a null terminated character ('\0'). The size of each record may vary but the number of columns should be the same.

Using the code

The PDBCreators class is used to create databases.

class PDBCreators
{
    PDBHeader header=new PDBHeader();
    ArrayList pdbRecord=new ArrayList();
    public PDBCreators()
    {
    }
    public PDBHeader PDBHeaders
    {
        set
        {
            header=value;
        }
        get
        {
            return header;
        }
    }
    public Object[] AddRecord
    {
        set
        {
            string row="";
            for (int i=0; i<value.Length; i++)
            {
                if (value[i].GetType().ToString()=="System.Int32")  
                    continue;
                row+=value[i].ToString().Trim()+'\0';
            }
            pdbRecord.Add(new PDBRecordList(row));
        }
    }

    public void GeneratePDB(string fileName)
    {
        try
        {
            FileStream fs=new FileStream(fileName,FileMode.Create);
            BinaryWriter bw=new BinaryWriter(fs);
            int discard=0;
            UInt32 index=78;     // Header length is 78 Bytes
            header.NumRecords=(UInt16)pdbRecord.Count;

            bw.Write(HexEncoding.GetBytes(header.ToString(), 
                                              out discard));

            // start index of Data List Area
            index+=(UInt32)(pdbRecord.Count*8)+2;
            string result="";
            for (int i=0; ipdbRecord.Count; i++)
            {
                PDBRecordList rec=(PDBRecordList)pdbRecord[i];
                rec.RecordOffset=index;
                bw.Write(HexEncoding.GetBytes(rec.ToString(), 
                                               out discard));
                index+=(UInt32)rec.DataRecord.Length;
                result+=rec.DataRecord;
            }
            char[] padding={'\0','\0'};  // Two bytes for backup bits
            bw.Write(HexEncoding.GetBytes(
              HexEncoding.GetStringToChar(padding,2), 
              out discard));
            result=HexEncoding.GetStringToChar(
              result.ToCharArray(),result.Length);
            bw.Write(HexEncoding.GetBytes(result,out discard));
            bw.Close();
            fs.Close();
        }
        catch (Exception exc)
        {
            throw new PDBException("Error" + 
              " in writing pdb file "+exc.Message);
        }

    }
}

The PDBGenerator reads two file formats (CSV and XML) and displays data in table format in a DataGrid. This data can be changed. It reads all table data from the XML file and displays table names in a combo box.

PDBCreators pdb=new PDBCreators();
pdb.PDBHeaders.DataBaseName=this.txtDBName.Text;
pdb.PDBHeaders.CreatorID=this.txtCreatorID.Text;

DataTable recordsTable;
if (recordsDataSet.Tables.Count>0 && 
        this.cmbTableNames.Items.Count>0 && 
        recordsDataSet.Tables.Contains(this.cmbTableNames.Text))
    recordsTable=recordsDataSet.Tables[this.cmbTableNames.Text];
else
{
    MessageBox.Show("There is no table to convert", 
          "PDB Generator",MessageBoxButtons.OK,
          MessageBoxIcon.Information);
    return;
}
for (int i=0; i<recordsTable.Rows.Count; i++)
    pdb.AddRecord=recordsTable.Rows[i].ItemArray;
try
{
    pdb.GeneratePDB(this.txtDestination.Text+"\\"+
                      this.txtDBName.Text+".pdb");
    MessageBox.Show("PDB Generated Successfully",
      "PDB Generator",MessageBoxButtons.OK,
      MessageBoxIcon.Information);
}
catch(Exception exc)
{
    MessageBox.Show("Error in PDB Generation"+exc.ToString(),
      "PDB Generator",MessageBoxButtons.OK,
      MessageBoxIcon.Information);
}

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

MRSumra
Web Developer
Pakistan Pakistan
Member
I'm working as Software Engineer at ISF (Islamabad Software Factory) in Pakistan and involves in multiple products having different languages in different phases. My favourite areas are PDA's, Palm's, .Net and webservices......

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalrle compression of contentmemberUnruled Boy27 Nov '09 - 22:58 
GeneralNice, but the PDB generated can't be read by my application.memberMember 45957942 Jul '08 - 5:56 
GeneralRe: Nice, but the PDB generated can't be read by my application.memberMRSumra2 Jul '08 - 19:14 
GeneralRe: Nice, but the PDB generated can't be read by my application.memberMember 45957944 Jul '08 - 4:06 
GeneralRe: Nice, but the PDB generated can't be read by my application.memberMember 45957948 Jul '08 - 4:22 
Generalpdb usememberMember 23874258 Apr '08 - 2:57 
GeneralRe: pdb usememberMRSumra9 Apr '08 - 0:17 
GeneralRe: pdb usememberMember 23874259 Apr '08 - 3:02 
GeneralRe: pdb usememberMRSumra9 Apr '08 - 6:49 
GeneralRe: pdb usememberMember 45957948 Jul '08 - 4:30 
GeneralDoes not seem to work.memberMurdocMA25 Jun '07 - 5:32 
GeneralRe: Does not seem to work.memberrobertoy28 Sep '07 - 5:21 
QuestionRe: Does not seem to work.memberneal0071 Oct '07 - 11:11 
QuestionSync PDB and SQL Server 2005memberHandyGuy15 Jun '07 - 9:45 
GeneralPDB record headermembermihasic3 May '07 - 2:39 
GeneralAnd PDB to XMLmemberjohatenxxx7 Mar '07 - 11:27 
GeneralRead writememberpablojag2 Aug '06 - 6:33 
GeneralRe: Read writememberjulgui12 Sep '06 - 23:29 
Questionwhat does padding mean?memberDarekKawczynski31 Jul '06 - 4:34 
AnswerRe: what does padding mean?memberMRSumra2 Aug '06 - 4:18 
GeneralPDB generator in C#memberTime Lord18 Jul '06 - 12:05 
GeneralGreat codememberrobertoy17 Jul '06 - 13:03 
GeneralRe: Great codememberMRSumra20 Jul '06 - 4:16 
use following site to convert this code into VB.Net
http://www.developerfusion.co.uk/utilities/convertcsharptovb.aspx
 
Muhammad Rizwan Sumra
QuestionHow to install sqlce for PPC device?memberluongthang17 Jun '06 - 22:24 
GeneralNot working for mememberhaucks12 Apr '06 - 6:52 
GeneralRe: Not working for mememberMRSumra15 Apr '06 - 1:06 
GeneralRe: Not working for mememberhaucks17 Apr '06 - 10:33 
GeneralRe: Not working for mememberpalmuser12318 Aug '08 - 1:47 
GeneralRead PDBsmemberenshosinho16 Mar '06 - 3:24 
GeneralRe: Read PDBsmemberMRSumra15 Apr '06 - 1:09 
GeneralRead PDBs in both Pocket and Palmmemberpablojag19 Jan '06 - 2:38 
GeneralRe: Read PDBs in both Pocket and PalmmemberMRSumra20 Jan '06 - 18:05 
GeneralRe: Read PDBs in both Pocket and PalmmemberDaveCline27 Jan '06 - 8:15 
GeneralRe: Read PDBs in both Pocket and PalmmemberMRSumra1 Feb '06 - 17:45 
GeneralRe: Read PDBs in both Pocket and PalmmemberDaveCline2 Feb '06 - 5:57 
GeneralRe: Read PDBs in both Pocket and PalmmemberMRSumra2 Feb '06 - 18:20 
GeneralRe: Read PDBs in both Pocket and PalmmemberDaveCline3 Feb '06 - 9:31 
GeneralRe: Read PDBs in both Pocket and PalmmemberAlexander Blood6 Sep '06 - 8:10 
QuestionHow about reading pdb's?memberjavacas19 Jan '06 - 1:57 
AnswerRe: How about reading pdb's?memberMRSumra20 Jan '06 - 17:51 
QuestionGenerate PRCs?memberPinx18 Jan '06 - 1:54 
AnswerRe: Generate PRCs?memberMRSumra18 Jan '06 - 17:58 
GeneralThis is the WORK I m lookin for.....memberASPNEt Lover17 Jan '06 - 23:45 
JokeGreat JobmemberAwaisAhmedKhan17 Jan '06 - 22:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 10 Jan 2006
Article Copyright 2006 by MRSumra
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid