File indexing completed on 2024-05-19 04:52:44

0001 // -*- c-basic-offset: 2 -*-
0002 /* This file is part of the KDE project
0003    SPDX-FileCopyrightText: 1998, 1999 David Faure <faure@kde.org>
0004 
0005    SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef __koStore_h_
0009 #define __koStore_h_
0010 
0011 #include <QString>
0012 #include <QStringList>
0013 #include <QStack>
0014 
0015 class QByteArray;
0016 class QIODevice;
0017 class QWidget;
0018 class QUrl;
0019 
0020 /**
0021  * Saves and loads KOffice documents using various backends. Currently supported
0022  * backends are ZIP, tar and directory.
0023  * We call a "store" the file on the hard disk (the one the users sees)
0024  * and call a "file" a file inside the store.
0025  */
0026 class /*KOSTORE_EXPORT*/ KoStore
0027 {
0028 public:
0029 
0030   enum Mode { Read, Write };
0031   enum Backend { Auto, Tar, Zip, Directory, Encrypted };
0032 
0033   /**
0034    * Open a store (i.e. the representation on disk of a KOffice document).
0035    *
0036    * @param fileName the name of the file to open
0037    * @param mode if KoStore::Read, open an existing store to read it.
0038    *             if KoStore::Write, create or replace a store.
0039    * @param backend the backend to use for the data storage.
0040    * Auto means automatically-determined for reading,
0041    * and the current format (now Zip) for writing.
0042    *
0043    * @param appIdentification the application's mimetype,
0044    * to be written in the file for "mime-magic" identification.
0045    * Only meaningful if mode is Write, and if backend!=Directory.
0046    */
0047   static KoStore* createStore( const QString& fileName, Mode mode, const QByteArray & appIdentification = "", Backend backend = Auto );
0048 
0049   /**
0050    * Create a store for any kind of QIODevice: file, memory buffer...
0051    * KoStore will take care of opening the QIODevice.
0052    * This method doesn't support the Directory store!
0053    */
0054   static KoStore* createStore( QIODevice *device, Mode mode, const QByteArray & appIdentification = "", Backend backend = Auto );
0055 
0056   /**
0057    * Open a store (i.e. the representation on disk of a KOffice document).
0058    *
0059    * @param window associated window (for the progress bar dialog and authentication)
0060    * @param url URL of the file to open
0061    * @param mode if KoStore::Read, open an existing store to read it.
0062    *             if KoStore::Write, create or replace a store.
0063    * @param backend the backend to use for the data storage.
0064    * Auto means automatically-determined for reading,
0065    * and the current format (now Zip) for writing.
0066    *
0067    * @param appIdentification the application's mimetype,
0068    * to be written in the file for "mime-magic" identification.
0069    * Only meaningful if mode is Write, and if backend!=Directory.
0070    *
0071    * If the file is remote, the backend Directory cannot be used!
0072    *
0073    * @bug saving not completely implemented (fixed temporary file)
0074    */
0075   static KoStore* createStore( QWidget* window, const QUrl& url, Mode mode, const QByteArray & appIdentification = "", Backend backend = Auto );
0076 
0077   /**
0078    * Destroys the store (i.e. closes the file on the hard disk)
0079    */
0080   virtual ~KoStore();
0081 
0082   /**
0083    * Open a new file inside the store
0084    * @param name The filename, internal representation ("root", "tar:/0"... ).
0085    *        If the tar:/ prefix is missing it's assumed to be a relative URI.
0086    * @return true on success.
0087    */
0088   bool open( const QString & name );
0089 
0090   /**
0091    * Check whether a file inside the store is currently opened with open(),
0092    * ready to be read or written.
0093    * @return true if a file is currently opened.
0094    */
0095   bool isOpen() const;
0096 
0097   /**
0098    * Close the file inside the store
0099    * @return true on success.
0100    */
0101   bool close();
0102 
0103   /**
0104    * Get a device for reading a file from the store directly
0105    * (slightly faster than read() calls)
0106    * You need to call @ref open first, and @ref close afterwards.
0107    */
0108   QIODevice* device() const;
0109 
0110   /**
0111    * Read data from the currently opened file. You can also use the streams
0112    * for this.
0113    */
0114   QByteArray read( qint64 max );
0115 
0116   /**
0117    * Write data into the currently opened file. You can also use the streams
0118    * for this.
0119    */
0120   qint64 write( const QByteArray& _data );
0121 
0122   /**
0123    * Read data from the currently opened file. You can also use the streams
0124    * for this.
0125    * @return size of data read, -1 on error
0126    */
0127   qint64 read( char *_buffer, qint64 _len );
0128 
0129   /**
0130    * Write data into the currently opened file. You can also use the streams
0131    * for this.
0132    */
0133   virtual qint64 write( const char* _data, qint64 _len );
0134 
0135   /**
0136    * @return the size of the currently opened file, -1 on error.
0137    * Can be used as an argument for the read methods, for instance
0138    */
0139   qint64 size() const;
0140 
0141   /**
0142    * @return true if an error occurred
0143    */
0144   bool bad() const { return !m_bGood; } // :)
0145 
0146   /**
0147    * @return the mode used when opening, read or write
0148    */
0149   Mode mode() const { return m_mode; }
0150 
0151   /**
0152    * Enters one or multiple directories. In Read mode this actually
0153    * checks whether the specified directories exist and returns false
0154    * if they don't. In Write mode we don't create the directory, we
0155    * just use the "current directory" to generate the absolute path
0156    * if you pass a relative path (one not starting with tar:/) when
0157    * opening a stream.
0158    * Note: Operates on internal names
0159    */
0160   bool enterDirectory( const QString& directory );
0161 
0162   /**
0163    * Leaves a directory. Equivalent to "cd .."
0164    * @return true on success, false if we were at the root already to
0165    * make it possible to "loop to the root"
0166    */
0167   bool leaveDirectory();
0168 
0169   /**
0170    * Returns the current path including a trailing slash.
0171    * Note: Returns a path in "internal name" style
0172    */
0173   QString currentPath() const;
0174 
0175   /**
0176    * Returns the current directory.
0177    * Note: Returns a path in "internal name" style
0178    */
0179   QString currentDirectory() const;
0180 
0181 
0182   /**
0183    * Stacks the current directory. Restore the current path using
0184    * @ref popDirectory .
0185    */
0186   void pushDirectory();
0187 
0188   /**
0189    * Restores the previously pushed directory. No-op if the stack is
0190    * empty.
0191    */
0192   void popDirectory();
0193 
0194   /**
0195    * @return true if the given file exists in the current directory,
0196    * i.e. if open(fileName) will work.
0197    */
0198   bool hasFile( const QString& fileName ) const;
0199 
0200   /**
0201    * Imports a local file into a store
0202    * @param fileName file on hard disk
0203    * @param destName file in the store
0204    */
0205   bool addLocalFile( const QString &fileName, const QString &destName );
0206 
0207   /**
0208    * Imports data into a store
0209    * @param buffer data
0210    * @param destName file in the store
0211    */
0212   bool addDataToFile( QByteArray &buffer, const QString &destName );
0213 
0214   /**
0215    * Imports a local directory
0216    * @param dirPath path to the directory on a disk
0217    * @param dest path in the store where the directory should get saved
0218    * @return the directory index
0219    */
0220   QStringList addLocalDirectory( const QString &dirPath, const QString &dest );
0221 
0222 
0223   /**
0224    * Extracts a file out of the store
0225    * @param srcName file in the store
0226    * @param fileName file on a disk
0227    */
0228   bool extractFile( const QString &srcName, const QString &fileName );
0229 
0230   /**
0231    * Extracts a file out of the store to a buffer
0232    * @param srcName file in the store
0233    * @param data memory buffer
0234    */
0235   bool extractFile( const QString &srcName, QByteArray &data );
0236 
0237   //@{
0238   /// See QIODevice
0239   bool seek( qint64 pos );
0240   qint64 pos() const;
0241   bool atEnd() const;
0242   //@}
0243 
0244   /**
0245    * Do not expand file and directory names
0246    * Useful when using KoStore on non-KOffice files.
0247    * (This method should be called just after the constructor)
0248    */
0249   void disallowNameExpansion( void );
0250 
0251   /**
0252    * Call this before destroying the store, to be able to catch errors
0253    * (e.g. from ksavefile)
0254    */
0255   bool finalize();
0256 
0257   /**
0258    * Sets the password to be used for decryption or encryption of the store.
0259    * Use of this function is optional: an encryptable store should make
0260    * a best effort in obtaining a password if it wasn't supplied.
0261    *
0262    * This method only works before opening a file. It might fail when a file
0263    * has already been opened before calling this method.
0264    * 
0265    * This method will not function for any store that is not encrypted or
0266    * can't be encrypted when saving.
0267    *
0268    * @param   password    A non-empty password.
0269    *
0270    * @return  True if the password was set.
0271    */
0272   virtual bool setPassword( const QString& password );
0273 
0274   /**
0275    * Retrieves the password used to encrypt or decrypt the store. Note that
0276    * QString() will returned if no password has been given or the store is
0277    * not encrypted.
0278    *
0279    * @return  The password this store is encrypted with.
0280    */
0281   virtual QString password( );
0282 
0283   /**
0284    * Returns whether a store opened for reading is encrypted or a store opened
0285    * for saving will be encrypted.
0286    *
0287    * @return  True if the store is encrypted.
0288    */
0289   virtual bool isEncrypted( );
0290 
0291 protected:
0292 
0293   KoStore();
0294 
0295   /**
0296    * Init store - called by constructor.
0297    * @return true on success
0298    */
0299   virtual bool init( Mode mode );
0300 
0301   /**
0302    * Finalize store - called by finalize.
0303    * @return true on success
0304    */
0305   virtual bool doFinalize() { return true; }
0306 
0307   /**
0308    * Open the file @p name in the store, for writing
0309    * On success, this method must set m_stream to a stream in which we can write.
0310    * @param name "absolute path" (in the archive) to the file to open
0311    * @return true on success
0312    */
0313   virtual bool openWrite( const QString& name ) = 0;
0314   /**
0315    * Open the file @p name in the store, for reading.
0316    * On success, this method must set m_stream to a stream from which we can read,
0317    * as well as setting m_iSize to the size of the file.
0318    * @param name "absolute path" (in the archive) to the file to open
0319    * @return true on success
0320    */
0321   virtual bool openRead( const QString& name ) = 0;
0322 
0323   /**
0324    * @return true on success
0325    */
0326   virtual bool closeRead() = 0;
0327   /**
0328    * @return true on success
0329    */
0330   virtual bool closeWrite() = 0;
0331 
0332   /**
0333    * Enter a subdirectory of the current directory.
0334    * The directory might not exist yet in Write mode.
0335    */
0336   virtual bool enterRelativeDirectory( const QString& dirName ) = 0;
0337   /**
0338    * Enter a directory where we've been before.
0339    * It is guaranteed to always exist.
0340    */
0341   virtual bool enterAbsoluteDirectory( const QString& path ) = 0;
0342 
0343   /**
0344    * Check if a file exists inside the store.
0345    * @param absPath the absolute path inside the store, i.e. not relative to the current directory
0346    */
0347   virtual bool fileExists( const QString& absPath ) const = 0;
0348 
0349 private:
0350   static Backend determineBackend( QIODevice* dev );
0351 
0352   /**
0353    * Conversion routine
0354    * @param _internalNaming name used internally : "root", "tar:/0", ...
0355    * @return the name used in the file, more user-friendly ("maindoc.xml",
0356    *         "part0/maindoc.xml", ...)
0357    * Examples:
0358    *
0359    * tar:/0 is saved as part0/maindoc.xml
0360    * tar:/0/1 is saved as part0/part1/maindoc.xml
0361    * tar:/0/1/pictures/picture0.png is saved as part0/part1/pictures/picture0.png
0362    *
0363    * see specification (koffice/lib/store/SPEC) for details.
0364    */
0365   QString toExternalNaming( const QString & _internalNaming ) const;
0366 
0367   /**
0368    *  Expands a full path name for a stream (directories+filename)
0369    */
0370   QString expandEncodedPath( const QString& intern ) const;
0371 
0372   /**
0373    * Expands only directory names(!)
0374    * Needed for the path handling code, as we only operate on internal names
0375    */
0376   QString expandEncodedDirectory( const QString& intern ) const;
0377 
0378   mutable enum
0379   {
0380       NAMING_VERSION_2_1,
0381       NAMING_VERSION_2_2,
0382       NAMING_VERSION_RAW  ///< Never expand file and directory names
0383   } m_namingVersion;
0384 
0385   /**
0386    * Enter *one* single directory. Nothing like foo/bar/bleh allowed.
0387    * Performs some checking when in Read mode
0388    */
0389   bool enterDirectoryInternal( const QString& directory );
0390 
0391   bool extractFile( const QString &srcName, QIODevice &buffer );
0392 
0393 protected:
0394 
0395   Mode m_mode;
0396 
0397   /// Store the filenames (with full path inside the archive) when writing, to avoid duplicates
0398   QStringList m_strFiles;
0399 
0400   /// The "current directory" (path)
0401   QStringList m_currentPath;
0402 
0403   /// Current filename (between an open() and a close())
0404   QString m_sName;
0405   /// Current size of the file named m_sName
0406   qint64 m_iSize;
0407 
0408   /// The stream for the current read or write operation
0409   QIODevice * m_stream;
0410 
0411   bool m_bIsOpen;
0412   /// Must be set by the constructor.
0413   bool m_bGood;
0414   bool m_bFinalized;
0415 
0416 private:
0417   /// Used to push/pop directories to make it easy to save/restore the state
0418   QStack<QString> m_directoryStack;
0419 
0420 private:
0421   KoStore( const KoStore& store );  ///< don't copy
0422   KoStore& operator=( const KoStore& store );  ///< don't assign
0423 };
0424 
0425 #endif