koStore.cc
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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;
00047 if ( buf[0] == 0037 && buf[1] == 0213 )
00048 return Tar;
00049 if ( buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4 )
00050 return Zip;
00051 return DefaultFormat;
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;
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 , 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
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
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
00141 m_sName = toExternalNaming( _name );
00142
00143 if ( m_bIsOpen )
00144 {
00145 kdWarning(s_area) << "KoStore: File is already opened" << endl;
00146
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
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 )
00161 {
00162 kdWarning(s_area) << "KoStore: Duplicate filename " << m_sName << endl;
00163
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
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
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;
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() );
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
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
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:/" ) )
00494 intern = _internalNaming.mid( 5 );
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
00512
00513 if ( QChar(intern.at(0)).isDigit() )
00514 {
00515
00516
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 );
00540 intern = intern.mid( pos + 1 );
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 }
This file is part of the documentation for lib Library Version 1.3.5.