1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
#pragma once
#define USE_ZLIB
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdint>
#ifdef USE_ZLIB
#include <zlib.h>
#endif
using std::map;
using std::pair;
using std::set;
using std::string;
using std::vector;
#if !defined(DGAMELAUNCH) && !defined(DEBUG_DIAGNOSTICS)
#define DO_FSYNC
#endif
#define MAX_CHUNK_NAME_LENGTH 255
typedef uint32_t plen_t;
class package;
class chunk_writer
{
private:
package *pkg;
string name;
plen_t first_block;
plen_t cur_block;
plen_t block_len;
#ifdef USE_ZLIB
z_stream zs;
Bytef *z_buffer;
#endif
void raw_write(const void *data, plen_t len);
void finish_block(plen_t next);
public:
chunk_writer(package *parent, const string &_name);
~chunk_writer();
void write(const void *data, plen_t len);
friend class package;
};
class chunk_reader
{
private:
chunk_reader(package *parent, plen_t start);
void init(plen_t start);
package *pkg;
plen_t first_block, next_block;
plen_t off, block_left;
#ifdef USE_ZLIB
bool eof;
z_stream zs;
Bytef z_buffer[32768];
#endif
plen_t raw_read(void *data, plen_t len);
public:
chunk_reader(package *parent, const string &_name);
~chunk_reader();
plen_t read(void *data, plen_t len);
void read_all(vector<char> &data);
friend class package;
};
class package
{
public:
package(const char* file, bool writeable, bool empty = false);
package();
~package();
chunk_writer* writer(const string &name);
chunk_reader* reader(const string &name);
void commit();
void delete_chunk(const string &name);
bool has_chunk(const string &name);
vector<string> list_chunks();
void abort();
void unlink();
string get_filename() { return filename; }
// statistics
plen_t get_slack();
plen_t get_size() const { return file_len; }
plen_t get_chunk_fragmentation(const string &name);
plen_t get_chunk_compressed_length(const string &name);
private:
string filename;
bool rw;
int fd;
plen_t file_len;
int n_users;
bool dirty;
bool aborted;
#ifdef DO_FSYNC
bool tmp;
#endif
map<string, plen_t> directory;
map<plen_t, plen_t> free_blocks;
vector<plen_t> unlinked_blocks;
map<plen_t, pair<plen_t, plen_t> > block_map;
set<plen_t> new_chunks;
map<plen_t, uint32_t> reader_count;
plen_t extend_block(plen_t at, plen_t size, plen_t by);
plen_t alloc_block(plen_t &size);
void finish_chunk(const string &name, plen_t at);
void free_chunk(const string &name);
plen_t write_directory();
void collect_blocks();
void free_block_chain(plen_t at);
void free_block(plen_t at, plen_t size);
void seek(plen_t to);
void fsck();
void read_directory(plen_t start, uint8_t version);
void trace_chunk(plen_t start);
void load();
void load_traces();
friend class chunk_writer;
friend class chunk_reader;
};
|