lib Library API Documentation

koStore.cc

00001 // -*- c-basic-offset: 2 -*-
00002 /* This file is part of the KDE project
00003    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00004    Copyright (C) 2000-2002 David Faure <david@mandrakesoft.com>, Werner Trobin <trobin@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <stdio.h>
00023 #include <assert.h>
00024 #include <stdlib.h>
00025 
00026 #include "koStore.h"
00027 #include "koTarStore.h"
00028 #include "koZipStore.h"
00029 #include "koDirectoryStore.h"
00030 
00031 #include <kdebug.h>
00032 
00033 #include <qfileinfo.h>
00034 #include <qfile.h>
00035 #include <qdir.h>
00036 
00037 //#define DefaultFormat KoStore::Tar
00038 #define DefaultFormat KoStore::Zip
00039 
00040 const int KoStore::s_area = 30002;
00041 
00042 KoStore::Backend KoStore::determineBackend( QIODevice* dev )
00043 {
00044     unsigned char buf[5];
00045     if ( dev->readBlock( (char *)buf, 4 ) < 4 )
00046       return DefaultFormat; // will create a "bad" store (bad()==true)
00047     if ( buf[0] == 0037 && buf[1] == 0213 ) // gzip -> tar.gz
00048       return Tar;
00049     if ( buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4 )
00050       return Zip;
00051     return DefaultFormat; // fallback
00052 }
00053 
00054 KoStore* KoStore::createStore( const QString& fileName, Mode mode, const QCString & appIdentification, Backend backend )
00055 {
00056   if ( backend == Auto ) {
00057     if ( mode == KoStore::Write )
00058       backend = DefaultFormat;
00059     else
00060     {
00061       QFileInfo inf( fileName );
00062       if ( inf.isDir() )
00063         backend = Directory;
00064       else
00065       {
00066         QFile file( fileName );
00067         if ( file.open( IO_ReadOnly ) )
00068           backend = determineBackend( &file );
00069         else
00070           backend = DefaultFormat; // will create a "bad" store (bad()==true)
00071       }
00072     }
00073   }
00074   switch ( backend )
00075   {
00076   case Tar:
00077     return new KoTarStore( fileName, mode, appIdentification );
00078   case Zip:
00079     return new KoZipStore( fileName, mode, appIdentification );
00080   case Directory:
00081     return new KoDirectoryStore( fileName /* should be a dir name.... */, mode );
00082   default:
00083     kdWarning(s_area) << "Unsupported backend requested for KoStore : " << backend << endl;
00084     return 0L;
00085   }
00086 }
00087 
00088 KoStore* KoStore::createStore( QIODevice *device, Mode mode, const QCString & appIdentification, Backend backend )
00089 {
00090   if ( backend == Auto )
00091   {
00092     if ( mode == KoStore::Write )
00093       backend = DefaultFormat;
00094     else {
00095       if ( device->open( IO_ReadOnly ) ) {
00096         backend = determineBackend( device );
00097         device->close();
00098       }
00099     }
00100   }
00101   switch ( backend )
00102   {
00103   case Tar:
00104     return new KoTarStore( device, mode, appIdentification );
00105   case Directory:
00106     kdError(s_area) << "Can't create a Directory store for a memory buffer!" << endl;
00107     // fallback
00108   case Zip:
00109     return new KoZipStore( device, mode, appIdentification );
00110   default:
00111     kdWarning(s_area) << "Unsupported backend requested for KoStore : " << backend << endl;
00112     return 0L;
00113   }
00114 }
00115 
00116 namespace {
00117   const char* const ROOTPART = "root";
00118   const char* const MAINNAME = "maindoc.xml";
00119 }
00120 
00121 bool KoStore::init( Mode _mode )
00122 {
00123   d = 0;
00124   m_bIsOpen = false;
00125   m_mode = _mode;
00126   m_stream = 0;
00127 
00128   // Assume new style names.
00129   m_namingVersion = NAMING_VERSION_2_2;
00130   return true;
00131 }
00132 
00133 KoStore::~KoStore()
00134 {
00135   delete m_stream;
00136 }
00137 
00138 bool KoStore::open( const QString & _name )
00139 {
00140   // This also converts from relative to absolute, i.e. merges the currentPath()
00141   m_sName = toExternalNaming( _name );
00142 
00143   if ( m_bIsOpen )
00144   {
00145     kdWarning(s_area) << "KoStore: File is already opened" << endl;
00146     //return KIO::ERR_INTERNAL;
00147     return false;
00148   }
00149 
00150   if ( m_sName.length() > 512 )
00151   {
00152       kdError(s_area) << "KoStore: Filename " << m_sName << " is too long" << endl;
00153       //return KIO::ERR_MALFORMED_URL;
00154       return false;
00155   }
00156 
00157   if ( m_mode == Write )
00158   {
00159     kdDebug(s_area) << "KoStore: opening for writing '" << m_sName << "'" << endl;
00160     if ( m_strFiles.findIndex( m_sName ) != -1 ) // just check if it's there
00161     {
00162       kdWarning(s_area) << "KoStore: Duplicate filename " << m_sName << endl;
00163       //return KIO::ERR_FILE_ALREADY_EXIST;
00164       return false;
00165     }
00166 
00167     m_strFiles.append( m_sName );
00168 
00169     m_iSize = 0;
00170     if ( !openWrite( m_sName ) )
00171       return false;
00172   }
00173   else if ( m_mode == Read )
00174   {
00175     kdDebug(s_area) << "Opening for reading '" << m_sName << "'" << endl;
00176     if ( !openRead( m_sName ) )
00177       return false;
00178   }
00179   else
00180     //return KIO::ERR_UNSUPPORTED_ACTION;
00181     return false;
00182 
00183   m_bIsOpen = true;
00184   return true;
00185 }
00186 
00187 bool KoStore::isOpen() const
00188 {
00189   return m_bIsOpen;
00190 }
00191 
00192 bool KoStore::close()
00193 {
00194   kdDebug(s_area) << "KoStore: Closing" << endl;
00195 
00196   if ( !m_bIsOpen )
00197   {
00198     kdWarning(s_area) << "KoStore: You must open before closing" << endl;
00199     //return KIO::ERR_INTERNAL;
00200     return false;
00201   }
00202 
00203   bool ret = m_mode == Write ? closeWrite() : closeRead();
00204 
00205   delete m_stream;
00206   m_stream = 0L;
00207   m_bIsOpen = false;
00208   return ret;
00209 }
00210 
00211 QIODevice* KoStore::device() const
00212 {
00213   if ( !m_bIsOpen )
00214     kdWarning(s_area) << "KoStore: You must open before asking for a device" << endl;
00215   if ( m_mode != Read )
00216     kdWarning(s_area) << "KoStore: Can not get device from store that is opened for writing" << endl;
00217   return m_stream;
00218 }
00219 
00220 QByteArray KoStore::read( unsigned long int max )
00221 {
00222   QByteArray data; // Data is a QArray<char>
00223 
00224   if ( !m_bIsOpen )
00225   {
00226     kdWarning(s_area) << "KoStore: You must open before reading" << endl;
00227     data.resize( 0 );
00228     return data;
00229   }
00230   if ( m_mode != Read )
00231   {
00232     kdError(s_area) << "KoStore: Can not read from store that is opened for writing" << endl;
00233     data.resize( 0 );
00234     return data;
00235   }
00236 
00237   if ( m_stream->atEnd() )
00238   {
00239     data.resize( 0 );
00240     return data;
00241   }
00242 
00243   if ( max > m_iSize - m_stream->at() )
00244     max = m_iSize - m_stream->at();
00245   if ( max == 0 )
00246   {
00247     data.resize( 0 );
00248     return data;
00249   }
00250 
00251   char *p = new char[ max ];
00252   m_stream->readBlock( p, max );
00253 
00254   data.setRawData( p, max );
00255   return data;
00256 }
00257 
00258 Q_LONG KoStore::write( const QByteArray& data )
00259 {
00260   return write( data.data(), data.size() ); // see below
00261 }
00262 
00263 Q_LONG KoStore::read( char *_buffer, Q_ULONG _len )
00264 {
00265   if ( !m_bIsOpen )
00266   {
00267     kdError(s_area) << "KoStore: You must open before reading" << endl;
00268     return -1;
00269   }
00270   if ( m_mode != Read )
00271   {
00272     kdError(s_area) << "KoStore: Can not read from store that is opened for writing" << endl;
00273     return -1;
00274   }
00275 
00276   if ( m_stream->atEnd() )
00277     return 0;
00278 
00279   if ( _len > m_iSize - m_stream->at() )
00280     _len = m_iSize - m_stream->at();
00281   if ( _len == 0 )
00282     return 0;
00283 
00284   return m_stream->readBlock( _buffer, _len );
00285 }
00286 
00287 Q_LONG KoStore::write( const char* _data, Q_ULONG _len )
00288 {
00289   if ( _len == 0L ) return 0;
00290 
00291   if ( !m_bIsOpen )
00292   {
00293     kdError(s_area) << "KoStore: You must open before writing" << endl;
00294     return 0L;
00295   }
00296   if ( m_mode != Write  )
00297   {
00298     kdError(s_area) << "KoStore: Can not write to store that is opened for reading" << endl;
00299     return 0L;
00300   }
00301 
00302   int nwritten = m_stream->writeBlock( _data, _len );
00303   Q_ASSERT( nwritten == (int)_len );
00304   m_iSize += nwritten;
00305 
00306   return nwritten;
00307 }
00308 
00309 QIODevice::Offset KoStore::size() const
00310 {
00311   if ( !m_bIsOpen )
00312   {
00313     kdWarning(s_area) << "KoStore: You must open before asking for a size" << endl;
00314     return static_cast<QIODevice::Offset>(-1);
00315   }
00316   if ( m_mode != Read )
00317   {
00318     kdWarning(s_area) << "KoStore: Can not get size from store that is opened for writing" << endl;
00319     return static_cast<QIODevice::Offset>(-1);
00320   }
00321   return m_iSize;
00322 }
00323 
00324 bool KoStore::enterDirectory( const QString& directory )
00325 {
00326   //kdDebug(s_area) << "KoStore::enterDirectory " << directory << endl;
00327   int pos;
00328   bool success = true;
00329   QString tmp( directory );
00330 
00331   while ( ( pos = tmp.find( '/' ) ) != -1 &&
00332           ( success = enterDirectoryInternal( tmp.left( pos ) ) ) )
00333           tmp = tmp.mid( pos + 1 );
00334 
00335   if ( success && !tmp.isEmpty() )
00336     return enterDirectoryInternal( tmp );
00337   return success;
00338 }
00339 
00340 bool KoStore::leaveDirectory()
00341 {
00342   if ( m_currentPath.isEmpty() )
00343     return false;
00344 
00345   m_currentPath.pop_back();
00346 
00347   return enterAbsoluteDirectory( expandEncodedDirectory( currentPath() ) );
00348 }
00349 
00350 QString KoStore::currentPath() const
00351 {
00352   QString path;
00353   QStringList::ConstIterator it = m_currentPath.begin();
00354   QStringList::ConstIterator end = m_currentPath.end();
00355   for ( ; it != end; ++it ) {
00356     path += *it;
00357     path += '/';
00358   }
00359   return path;
00360 }
00361 
00362 void KoStore::pushDirectory()
00363 {
00364   m_directoryStack.push( currentPath() );
00365 }
00366 
00367 void KoStore::popDirectory()
00368 {
00369   m_currentPath.clear();
00370   enterAbsoluteDirectory( QString::null );
00371   enterDirectory( m_directoryStack.pop() );
00372 }
00373 
00374 bool KoStore::addLocalFile( const QString &fileName, const QString &destName )
00375 {
00376   QFileInfo fi( fileName );
00377   uint size = fi.size();
00378   QFile file( fileName );
00379   if ( !file.open( IO_ReadOnly ))
00380   {
00381     return false;
00382   }
00383 
00384   if ( !open ( destName ) )
00385   {
00386     return false;
00387   }
00388 
00389   QByteArray data ( 8 * 1024 );
00390 
00391   uint total = 0;
00392   for ( int block = 0; ( block = file.readBlock ( data.data(), data.size() ) ) > 0; total += block )
00393   {
00394     data.resize(block);
00395     if ( write( data ) != block )
00396       return false;
00397     data.resize(8*1024);
00398   }
00399   Q_ASSERT( total == size );
00400 
00401   close();
00402   file.close();
00403 
00404   return true;
00405 }
00406 
00407 bool KoStore::extractFile ( const QString &srcName, const QString &fileName )
00408 {
00409   if ( !open ( srcName ) )
00410     return false;
00411 
00412   QFile file( fileName );
00413 
00414   if( !file.open ( IO_WriteOnly ) )
00415   {
00416     close();
00417     return false;
00418   }
00419 
00420   QByteArray data ( 8 * 1024 );
00421   uint total = 0;
00422   for( int block = 0; ( block = read ( data.data(), data.size() ) ) > 0; total += block )
00423   {
00424     file.writeBlock ( data.data(), block );
00425   }
00426 
00427   if( size() != static_cast<QIODevice::Offset>(-1) )
00428     Q_ASSERT( total == size() );
00429 
00430   file.close();
00431   close();
00432 
00433   return true;
00434 }
00435 
00436 QStringList KoStore::addLocalDirectory( const QString &dirPath, const QString &destName )
00437 {
00438   QString dot = ".";
00439   QString dotdot = "..";
00440   QStringList content;
00441 
00442   QDir dir(dirPath);
00443   if ( !dir.exists() )
00444     return 0;
00445 
00446   QStringList files = dir.entryList();
00447   for ( QStringList::Iterator it = files.begin(); it != files.end(); ++it )
00448   {
00449      if ( *it != dot && *it != dotdot )
00450      {
00451         QString currentFile = dirPath + "/" + *it;
00452         QString dest = destName.isEmpty() ? *it : (destName + "/" + *it);
00453 
00454         QFileInfo fi ( currentFile );
00455         if ( fi.isFile() )
00456         {
00457           addLocalFile ( currentFile, dest );
00458           content.append(dest);
00459         }
00460         else if ( fi.isDir() )
00461         {
00462           content += addLocalDirectory ( currentFile, dest );
00463         }
00464      }
00465   }
00466 
00467   return content;
00468 }
00469 
00470 
00471 bool KoStore::at( QIODevice::Offset pos )
00472 {
00473   return m_stream->at( pos );
00474 }
00475 
00476 QIODevice::Offset KoStore::at() const
00477 {
00478   return m_stream->at();
00479 }
00480 
00481 bool KoStore::atEnd() const
00482 {
00483   return m_stream->atEnd();
00484 }
00485 
00486 // See the specification for details of what this function does.
00487 QString KoStore::toExternalNaming( const QString & _internalNaming )
00488 {
00489   if ( _internalNaming == ROOTPART )
00490     return expandEncodedDirectory( currentPath() ) + MAINNAME;
00491 
00492   QString intern;
00493   if ( _internalNaming.startsWith( "tar:/" ) ) // absolute reference
00494     intern = _internalNaming.mid( 5 ); // remove protocol
00495   else
00496     intern = currentPath() + _internalNaming;
00497 
00498   return expandEncodedPath( intern );
00499 }
00500 
00501 QString KoStore::expandEncodedPath( QString intern )
00502 {
00503   QString result;
00504   int pos;
00505 
00506   if ( ( pos = intern.findRev( '/', -1 ) ) != -1 ) {
00507     result = expandEncodedDirectory( intern.left( pos ) ) + '/';
00508     intern = intern.mid( pos + 1 );
00509   }
00510 
00511   // Now process the filename. If the first character is numeric, we have
00512   // a main document.
00513   if ( QChar(intern.at(0)).isDigit() )
00514   {
00515     // If this is the first part name, check if we have a store with
00516     // old-style names.
00517     if ( ( m_namingVersion == NAMING_VERSION_2_2 ) &&
00518          ( m_mode == Read ) &&
00519          ( fileExists( result + "part" + intern + ".xml" ) ) )
00520       m_namingVersion = NAMING_VERSION_2_1;
00521 
00522     if ( m_namingVersion == NAMING_VERSION_2_1 )
00523       result = result + "part" + intern + ".xml";
00524     else
00525       result = result + "part" + intern + "/" + MAINNAME;
00526   }
00527   else
00528     result += intern;
00529   return result;
00530 }
00531 
00532 QString KoStore::expandEncodedDirectory( QString intern )
00533 {
00534   QString result;
00535   int pos;
00536   while ( ( pos = intern.find( '/' ) ) != -1 ) {
00537     if ( QChar(intern.at(0)).isDigit() )
00538       result += "part";
00539     result += intern.left( pos + 1 ); // copy numbers (or "pictures") + "/"
00540     intern = intern.mid( pos + 1 ); // remove the dir we just processed
00541   }
00542 
00543   if ( QChar(intern.at(0)).isDigit() )
00544     result += "part";
00545   result += intern;
00546   return result;
00547 }
00548 
00549 bool KoStore::enterDirectoryInternal( const QString& directory )
00550 {
00551     if ( enterRelativeDirectory( expandEncodedDirectory( directory ) ) )
00552     {
00553       m_currentPath.append( directory );
00554       return true;
00555     }
00556     return false;
00557 }
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Nov 17 13:19:25 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2003