filters

palmdb.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002 Ariya Hidayat <ariyahidayat@yahoo.de>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 /*
00021    The database layout for PalmDB files is described in 
00022    http://www.palmos.com/dev/support/docs/protein_books/FileFormats/Intro.html
00023 */
00024 
00025 #include "palmdb.h"
00026 
00027 #include <qcstring.h>
00028 #include <qdatastream.h>
00029 #include <qdatetime.h>
00030 #include <qfile.h>
00031 #include <qmemarray.h>
00032 #include <qptrlist.h>
00033 #include <qstring.h>
00034 
00035 PalmDB::PalmDB()
00036 {
00037   // some default values
00038   setName( "Unnamed" );
00039   setAttributes( 0 );
00040   setVersion( 0 );
00041   setCreationDate( QDateTime::currentDateTime() );
00042   setModificationDate( QDateTime::currentDateTime() );
00043   setLastBackupDate( QDateTime::currentDateTime() );
00044   setType( QString::null );
00045   setCreator( QString::null );
00046 
00047   // crash if autodelete ?
00048   records.setAutoDelete( TRUE );
00049 }
00050 
00051 PalmDB::~PalmDB()
00052 {
00053   records.clear();
00054 }
00055 
00056 bool PalmDB::load( const char* filename )
00057 {
00058   // open input file
00059   QFile in (filename);
00060   if (!in.open (IO_ReadOnly))
00061     return FALSE;
00062 
00063   QDataStream stream;
00064   stream.setDevice (&in);
00065 
00066   unsigned filesize = stream.device()->size();
00067   if( filesize < 72 ) return FALSE;
00068 
00069   // always big-endian
00070   stream.setByteOrder (QDataStream::BigEndian);
00071 
00072   // now start to read PDB header (72 bytes)
00073 
00074   // read and encode database name
00075   // The name field is 32 bytes long, and is NUL terminated.
00076   // Use the length parameter of fromLatin1() anyway.
00077   Q_UINT8 name[32];
00078   for(int k = 0; k < 32; k++)
00079     stream >> name[k];
00080   m_name = QString::fromLatin1( (char*) name, 31 );
00081 
00082   // read database attribute
00083   Q_UINT16 attr;
00084   stream >> attr;
00085   m_attributes = attr;
00086 
00087   // read database version (app-specific)
00088   Q_UINT16 ver;
00089   stream >> ver;
00090   m_version = ver;
00091 
00092   // NOTE: PDB specifies date as number of seconds since 1 Jan 1904
00093   // QDateTime::setTime_t expects number of seconds since 1 Jan 1970
00094   // so, we make adjustment with a constant offset of 2082844800
00095   const int adjust = 2082844800;
00096 
00097   // read creation date
00098   Q_UINT32 creation;
00099   stream >> creation;
00100   m_creationDate.setTime_t( creation - adjust );
00101 
00102   // read modification date
00103   Q_UINT32 modification;
00104   stream >> modification;
00105   m_modificationDate.setTime_t( modification - adjust );
00106 
00107   // read last backup date
00108   Q_UINT32 lastbackup;
00109   stream >> lastbackup;
00110   m_lastBackupDate.setTime_t( lastbackup - adjust );
00111 
00112   // read modification number
00113   Q_UINT32 modnum;
00114   stream >> modnum;
00115 
00116   // read app info id and sort info id
00117   Q_UINT32 appid, sortid;
00118   stream >> appid;
00119   stream >> sortid;
00120 
00121   // read and encode database type
00122   Q_UINT8 dbt[4];
00123   stream >> dbt[0] >> dbt[1] >> dbt[2] >> dbt[3];
00124   m_type = QString::fromLatin1( (char*) dbt, 4 );
00125 
00126   // read and encode database creator
00127   Q_UINT8 dbc[4];
00128   stream >> dbc[0] >> dbc[1] >> dbc[2] >> dbc[3];
00129   m_creator = QString::fromLatin1( (char*) dbc, 4 );
00130 
00131   // read unique id seed
00132   Q_UINT32 idseed;
00133   stream >> idseed;
00134   m_uniqueIDSeed = idseed;
00135 
00136   // now start to read PDB record list (variable-length)
00137 
00138   // next record list
00139   // FIXME what to do with this ?
00140   Q_UINT32 nextlist;
00141   stream >> nextlist;
00142 
00143   // number of records
00144   Q_UINT16 numrec;
00145   stream >> numrec;
00146 
00147   // read entries in record list
00148   // find out location and size of each record
00149   QMemArray<unsigned> recpos( numrec );
00150   QMemArray<int> recsize( numrec );
00151 
00152   // FIXME any other better way to find record size ?
00153   for( int r = 0; r < numrec; r++ )
00154   {
00155     Q_UINT32 pos;
00156     Q_UINT8 flag, dummy;
00157     stream >> pos >> flag >> dummy >> dummy >> dummy;
00158     recpos[r] = pos; recsize[r] = filesize - pos;
00159     if( r> 0 ) recsize[r-1] = pos - recpos[r-1]; // fixup
00160   }
00161 
00162   // debugging
00163 #ifdef PDB_DEBUG
00164   qDebug( "name: \"%s\"", m_name.latin1() );
00165   qDebug( "type: \"%s\"", m_type.latin1() );
00166   qDebug( "creator: \"%s\"", m_creator.latin1() );
00167   qDebug( "attributes: 0x%04X", m_attributes );
00168   qDebug( "version: 0x%04X", m_version );
00169   qDebug( "creation date: %s", m_creationDate.toString().latin1() );
00170   qDebug( "modification date: %s", m_modificationDate.toString().latin1() );
00171   qDebug( "last backup date: %s", m_lastBackupDate.toString().latin1() );
00172   qDebug( "number of records: %d", numrec );
00173   for( int r = 0; r < numrec; r++ )
00174     qDebug( "  rec %d at 0x%X size %d", r, recpos[r], recsize[r] );
00175 #endif
00176 
00177   // load all records
00178   records.clear();
00179   for( int r = 0; r < numrec; r++ )
00180   {
00181     QByteArray* data = new QByteArray;
00182 
00183     if( recpos[r] < filesize )
00184       if( recsize[r] >= 0 )
00185         {
00186           data->resize( recsize[r] );
00187           stream.device()->at( recpos[r] );
00188           for( int q = 0; q < recsize[r]; q++ )
00189             { Q_UINT8 c; stream >> c; data->at(q) = c; }
00190         }
00191     records.append( data );
00192   }
00193 
00194   // close input file
00195   in.close();
00196 
00197   return TRUE;
00198 }
00199 
00200 bool PalmDB::save( const char* filename )
00201 {
00202   // open output file
00203   QFile out( filename );
00204   if( !out.open( IO_WriteOnly ) )
00205     return FALSE;
00206 
00207   QDataStream stream;
00208   stream.setDevice( &out );
00209 
00210   // always big-endian
00211   stream.setByteOrder (QDataStream::BigEndian);
00212 
00213   // now write PDB header (72 bytes)
00214 
00215   // write database name
00216   setName( name() );
00217   const char *dbname = m_name.latin1();
00218   for( unsigned k=0; k<31; k++ )
00219   {
00220     Q_UINT8 c = (k<m_name.length()) ? dbname[k] : 0;
00221     stream << c;
00222   }
00223   {
00224     // NUL-terminate the database name
00225     Q_UINT8 c = 0;
00226     stream << c;
00227   }
00228 
00229 
00230 
00231   // write database attribute
00232   Q_UINT16 attr = m_attributes;
00233   stream << attr;
00234 
00235   // write database version (app-specific)
00236   Q_UINT16 ver = m_version;
00237   stream << ver;
00238 
00239   // reference date is 1 Jan 1904
00240   // see also note in function load() above
00241   QDateTime ref = QDate( 1904, 1, 1 );
00242 
00243   // write creation date
00244   Q_UINT32 creation = -m_creationDate.secsTo( ref );
00245   stream << creation;
00246 
00247   // write modification date
00248   Q_UINT32 modification = -m_modificationDate.secsTo( ref );
00249   stream << modification;
00250 
00251   // write last backup date
00252   Q_UINT32 lastbackup = -m_lastBackupDate.secsTo( ref );
00253   stream << lastbackup;
00254 
00255   // write modification number
00256   Q_UINT32 modnum = 0;
00257   stream << modnum;
00258 
00259   // write app info id and sort info id
00260   Q_UINT32 appid = 0, sortid = 0;
00261   stream << appid;
00262   stream << sortid;
00263 
00264   // write and encode database type
00265   Q_UINT8 dbt[4];
00266   const char *dbtype = m_type.latin1();
00267   for( int p=0; p<4; p++ ) dbt[p]=dbtype[p];
00268   stream << dbt[0] << dbt[1] << dbt[2] << dbt[3];
00269 
00270   // write and encode database creator
00271   Q_UINT8 dbc[4];
00272   const char *dbcreator = m_creator.latin1();
00273   for( int p=0; p<4; p++ ) dbc[p]=dbcreator[p];
00274   stream << dbc[0] << dbc[1] << dbc[2] << dbc[3];
00275 
00276   // write unique id seed
00277   Q_UINT32 idseed = 0;
00278   stream << idseed;
00279 
00280   // now start to read PDB record list (variable-length)
00281 
00282   // next record list
00283   Q_UINT32 nextlist = 0;
00284   stream << nextlist;
00285 
00286   // number of records
00287   Q_UINT16 numrec = records.count();
00288   stream << numrec;
00289 
00290   // where is the first record ?
00291   // 78 is size of PDB header, 2 is filler before data
00292   Q_UINT32 pos = 78 + 2;
00293   pos += records.count()*8;
00294 
00295   // write record list
00296   for( unsigned r = 0; r < records.count(); r++ )
00297   {
00298     Q_UINT8 flag = 0, dummy = 0;
00299     stream << pos;
00300     stream << flag;
00301     stream  << dummy << dummy << dummy;
00302     pos += records.at(r)->count();
00303   }
00304 
00305   // write 2-byte dummy
00306   Q_UINT16 filler = 0;
00307   stream << filler;
00308 
00309   // write all records
00310   for( unsigned r = 0; r < records.count(); r++ )
00311   {
00312     QByteArray *data = records.at( r );
00313     if( !data ) continue;
00314     for( unsigned j=0; j<data->count(); j++ )
00315       {
00316         Q_UINT8 c = data->at( j ); 
00317         stream << c;  
00318       }
00319   }
00320 
00321   // close output file
00322   out.close();
00323 
00324   return TRUE;
00325 }
00326 
00327 void PalmDB::setType( const QString& t )
00328 {
00329   m_type = t;
00330   if( m_type.length() > 4 )
00331     m_type = m_type.left( 4 );
00332   while( m_type.length() < 4 )
00333     m_type.append( 32 );
00334 }
00335 
00336 
00337 void PalmDB::setCreator( const QString& c )
00338 {
00339   m_creator = c;
00340   if( m_creator.length() > 4 )
00341     m_type = m_creator.left( 4 );
00342   while( m_creator.length() < 4 )
00343     m_creator.append( 32 );
00344 }
KDE Home | KDE Accessibility Home | Description of Access Keys