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.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 24 18:22:26 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003