/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __NARCHIVE__ #define __NARCHIVE__ #include "nstring/nstring.h" #include "container/nlist.h" #include "memory/nauto_ptr.h" #include "filesystem/io_handle.h" namespace GS { namespace Threading { class Mutex; } /// Archive index entry. struct ArchiveEntry { // Do not change this enumeration order! enum Method { MethodRaw = 0, MethodZLibCompress }; String path; ///< Entry path. char method; ///< Compression method. size_t offset; ///< Data offset in archive. size_t length; ///< Original length. size_t compressed_length; ///< Compressed length. }; /*! @short Archive index. @author Emmanuel Julien (ejulien@gsworks.fr) */ class ArchiveIndex { friend class Archive; protected: AutoList index; public: /// Find an entry in the index file. ArchiveEntry *FindEntry(const char *alias) const; /// Load archive index. bool Load(const char *uri); /// Save archive index. bool Save(const char *uri); }; /*! @short Archive storage. A pretty straightforward solid archive file format. Supports per-file compression algorithm selection. @author Emmanuel Julien */ class Archive { public: enum Revision { Legacy = 0, EnhancedLegacy }; protected: AutoPtr access_mutex; bool verbose; bool append_mode; ///< Archive open in append mode. ArchiveIndex index; ///< Archive index table. AutoPtr handle; Revision revision; size_t offset_padding, ///< File offset padding. size_padding; ///< File size padding. public: /*! @short Set file offset padding. Padding archive content is necessary on some platforms that do not support seeking or reading an arbitrary amount of bytes inside a file. This is often the case with the DVD unit of console systems. */ void SetOffsetPadding(size_t padding = 0) { offset_padding = padding; } /*! @short Set file size padding. @see SetOffsetPadding(). */ void SetSizePadding(size_t padding = 0) { size_padding = padding; } /// Return internal index object. const List &GetIndex() const { return index.index; } /// Set the verbose mode. void SetVerbose(bool v = true) { verbose = v; } /// Load current archive index file. bool LoadIndex(const char *path); /// Save current archive index file. bool SaveIndex(const char *path); /*! @short Open archive. @note If no index is provided one will automatically be created upon archive opening. Although this a fast process it requires that the archive be opened on a stream-able file system and that the whole archive be seeked through. */ bool OpenRead(const char *uri, const char *index_uri = 0); /// Create a new archive. bool CreateNew(const char *); /// Close archive. void Close(); /// Check if a file exists in archive. ArchiveEntry *Exists(const char *path) const { return index.FindEntry(path); } /*! @short Load a file from the archive. @note The output buffer is expected to old enough room to store the decompressed data. @see Exists(). */ bool FileRead(const char *, void *); /// Write a memory block to the archive. ArchiveEntry *MemoryBlockWrite(const char *, const void *, size_t, int compression_level = 6); /// Write a file to the archive. ArchiveEntry *FileWrite(const char *path, const char *alias = 0, int compression_level = 6); Archive(); ~Archive(); }; } // GS #endif // __NARCHIVE__