blob: 772fb14946aae74cfd896841152777c1334b9515 [file] [log] [blame]
#ifndef TALK_APP_WIN32_TARSTREAM_H__
#define TALK_APP_WIN32_TARSTREAM_H__
#include <string>
#include <vector>
#include "talk/base/fileutils.h"
#include "talk/base/sigslot.h"
#include "talk/base/stream.h"
namespace talk_base {
///////////////////////////////////////////////////////////////////////////////
// TarStream - acts as a source or sink for a tar-encoded collection of files
// and directories. Operates synchronously.
///////////////////////////////////////////////////////////////////////////////
class TarStream : public StreamInterface {
public:
TarStream();
virtual ~TarStream();
// AddFilter is used to limit the elements which will be read or written.
// In general, all members of the parent folder are read, and all members
// of a tarfile are written. However, if any filters are added, only those
// items (and their contents, in the case of folders) are processed. Filters
// must be added before opening the stream.
bool AddFilter(const std::string& pathname);
// 'folder' is parent of the tar contents. All paths will be evaluated
// relative to it. When 'read' is true, the specified folder will be
// traversed, and a tar stream will be generated (via Read). Otherwise, a
// tar stream is consumed (via Write), and files and folders will be created.
bool Open(const std::string& folder, bool read);
virtual talk_base::StreamState GetState() const;
virtual talk_base::StreamResult Read(void* buffer, size_t buffer_len,
size_t* read, int* error);
virtual talk_base::StreamResult Write(const void* data, size_t data_len,
size_t* written, int* error);
virtual void Close();
virtual bool GetSize(size_t* size) const { return false; }
virtual bool ReserveSize(size_t size) { return true; }
virtual bool Rewind() { return false; }
// Every time a new entry header is read/written, this signal is fired with
// the entry's name and size.
sigslot::signal2<const std::string&, size_t> SignalNextEntry;
private:
typedef std::list<DirectoryIterator*> DirectoryList;
enum ModeType { M_NONE, M_READ, M_WRITE };
enum NextBlockType { NB_NONE, NB_FILE_HEADER, NB_DATA, NB_TRAILER };
enum { BLOCK_SIZE = 512 };
talk_base::StreamResult ProcessBuffer(void* buffer, size_t buffer_len,
size_t* consumed, int* error);
talk_base::StreamResult ProcessNextBlock(int* error);
talk_base::StreamResult ProcessEmptyBlock(size_t start, int* error);
talk_base::StreamResult ReadNextFile(int* error);
talk_base::StreamResult WriteNextFile(int* error);
talk_base::StreamResult ProcessNextEntry(const DirectoryIterator *data,
int *error);
// Determine whether the given entry is allowed by our filters
bool CheckFilter(const std::string& pathname);
void WriteFieldN(size_t& pos, size_t max_len, size_t numeric_field);
void WriteFieldS(size_t& pos, size_t max_len, const char* string_field);
void WriteFieldF(size_t& pos, size_t max_len, const char* format, ...);
void ReadFieldN(size_t& pos, size_t max_len, size_t* numeric_field);
void ReadFieldS(size_t& pos, size_t max_len, std::string* string_field);
void WriteChecksum(void);
// Files and/or folders that should be processed
std::vector<std::string> filters_;
// Folder passed to Open
std::string root_folder_;
// Open for read or write?
ModeType mode_;
// The expected type of the next block
NextBlockType next_block_;
// The partial contents of the current block
char block_[BLOCK_SIZE];
size_t block_pos_;
// The file which is currently being read or written
talk_base::FileStream* current_;
// Bytes remaining to be processed for current_
size_t current_bytes_;
// Note: the following variables are used in M_READ mode only.
// Stack of open directory handles, representing depth-first search
DirectoryList find_;
// Subfolder path corresponding to current position in the directory tree
std::string subfolder_;
};
///////////////////////////////////////////////////////////////////////////////
} // namespace talk_base
#endif // TALK_APP_WIN32_TARSTREAM_H__