/* This file is part of the KDE project Copyright (C) 2002 Ariya Hidayat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* The database layout for PalmDB files is described in http://www.palmos.com/dev/support/docs/protein_books/FileFormats/Intro.html */ #include "palmdb.h" #include #include #include #include #include #include #include PalmDB::PalmDB() { // some default values setName( "Unnamed" ); setAttributes( 0 ); setVersion( 0 ); setCreationDate( TQDateTime::currentDateTime() ); setModificationDate( TQDateTime::currentDateTime() ); setLastBackupDate( TQDateTime::currentDateTime() ); setType( TQString() ); setCreator( TQString() ); // crash if autodelete ? records.setAutoDelete( TRUE ); } PalmDB::~PalmDB() { records.clear(); } bool PalmDB::load( const char* filename ) { // open input file TQFile in (filename); if (!in.open (IO_ReadOnly)) return FALSE; TQDataStream stream; stream.setDevice (&in); unsigned filesize = stream.device()->size(); if( filesize < 72 ) return FALSE; // always big-endian stream.setByteOrder (TQDataStream::BigEndian); // now start to read PDB header (72 bytes) // read and encode database name // The name field is 32 bytes long, and is NUL terminated. // Use the length parameter of fromLatin1() anyway. TQ_UINT8 name[32]; for(int k = 0; k < 32; k++) stream >> name[k]; m_name = TQString::fromLatin1( (char*) name, 31 ); // read database attribute TQ_UINT16 attr; stream >> attr; m_attributes = attr; // read database version (app-specific) TQ_UINT16 ver; stream >> ver; m_version = ver; // NOTE: PDB specifies date as number of seconds since 1 Jan 1904 // TQDateTime::setTime_t expects number of seconds since 1 Jan 1970 // so, we make adjustment with a constant offset of 2082844800 const int adjust = 2082844800; // read creation date TQ_UINT32 creation; stream >> creation; m_creationDate.setTime_t( creation - adjust ); // read modification date TQ_UINT32 modification; stream >> modification; m_modificationDate.setTime_t( modification - adjust ); // read last backup date TQ_UINT32 lastbackup; stream >> lastbackup; m_lastBackupDate.setTime_t( lastbackup - adjust ); // read modification number TQ_UINT32 modnum; stream >> modnum; // read app info id and sort info id TQ_UINT32 appid, sortid; stream >> appid; stream >> sortid; // read and encode database type TQ_UINT8 dbt[4]; stream >> dbt[0] >> dbt[1] >> dbt[2] >> dbt[3]; m_type = TQString::fromLatin1( (char*) dbt, 4 ); // read and encode database creator TQ_UINT8 dbc[4]; stream >> dbc[0] >> dbc[1] >> dbc[2] >> dbc[3]; m_creator = TQString::fromLatin1( (char*) dbc, 4 ); // read unique id seed TQ_UINT32 idseed; stream >> idseed; m_uniqueIDSeed = idseed; // now start to read PDB record list (variable-length) // next record list // FIXME what to do with this ? TQ_UINT32 nextlist; stream >> nextlist; // number of records TQ_UINT16 numrec; stream >> numrec; // read entries in record list // find out location and size of each record TQMemArray recpos( numrec ); TQMemArray recsize( numrec ); // FIXME any other better way to find record size ? for( int r = 0; r < numrec; r++ ) { TQ_UINT32 pos; TQ_UINT8 flag, dummy; stream >> pos >> flag >> dummy >> dummy >> dummy; recpos[r] = pos; recsize[r] = filesize - pos; if( r> 0 ) recsize[r-1] = pos - recpos[r-1]; // fixup } // debugging #ifdef PDB_DEBUG tqDebug( "name: \"%s\"", m_name.latin1() ); tqDebug( "type: \"%s\"", m_type.latin1() ); tqDebug( "creator: \"%s\"", m_creator.latin1() ); tqDebug( "attributes: 0x%04X", m_attributes ); tqDebug( "version: 0x%04X", m_version ); tqDebug( "creation date: %s", m_creationDate.toString().latin1() ); tqDebug( "modification date: %s", m_modificationDate.toString().latin1() ); tqDebug( "last backup date: %s", m_lastBackupDate.toString().latin1() ); tqDebug( "number of records: %d", numrec ); for( int r = 0; r < numrec; r++ ) tqDebug( " rec %d at 0x%X size %d", r, recpos[r], recsize[r] ); #endif // load all records records.clear(); for( int r = 0; r < numrec; r++ ) { TQByteArray* data = new TQByteArray; if( recpos[r] < filesize ) if( recsize[r] >= 0 ) { data->resize( recsize[r] ); stream.device()->at( recpos[r] ); for( int q = 0; q < recsize[r]; q++ ) { TQ_UINT8 c; stream >> c; data->at(q) = c; } } records.append( data ); } // close input file in.close(); return TRUE; } bool PalmDB::save( const char* filename ) { // open output file TQFile out( filename ); if( !out.open( IO_WriteOnly ) ) return FALSE; TQDataStream stream; stream.setDevice( &out ); // always big-endian stream.setByteOrder (TQDataStream::BigEndian); // now write PDB header (72 bytes) // write database name setName( name() ); const char *dbname = m_name.latin1(); for( unsigned k=0; k<31; k++ ) { TQ_UINT8 c = (kcount(); } // write 2-byte dummy TQ_UINT16 filler = 0; stream << filler; // write all records for( unsigned r = 0; r < records.count(); r++ ) { TQByteArray *data = records.at( r ); if( !data ) continue; for( unsigned j=0; jcount(); j++ ) { TQ_UINT8 c = data->at( j ); stream << c; } } // close output file out.close(); return TRUE; } void PalmDB::setType( const TQString& t ) { m_type = t; if( m_type.length() > 4 ) m_type = m_type.left( 4 ); while( m_type.length() < 4 ) m_type.append( 32 ); } void PalmDB::setCreator( const TQString& c ) { m_creator = c; if( m_creator.length() > 4 ) m_type = m_creator.left( 4 ); while( m_creator.length() < 4 ) m_creator.append( 32 ); }