summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/package.cc
diff options
context:
space:
mode:
authorAdam Borowski <kilobyte@angband.pl>2011-01-11 13:03:13 +0100
committerAdam Borowski <kilobyte@angband.pl>2011-01-11 13:03:13 +0100
commite7c3fa432cecc5eeb49d79109033fd85ee3cad2a (patch)
treefe057b8382c66ffccbd6c6a01ce3286b691c2135 /crawl-ref/source/package.cc
parente5001fba77867a842c1b0b192ec6969aab1cf102 (diff)
parentcc071d90f3d21a23526d1f92d055835e3d370d73 (diff)
downloadcrawl-ref-e7c3fa432cecc5eeb49d79109033fd85ee3cad2a.tar.gz
crawl-ref-e7c3fa432cecc5eeb49d79109033fd85ee3cad2a.zip
Merge branch 'master' into unicode
Conflicts galore...
Diffstat (limited to 'crawl-ref/source/package.cc')
-rw-r--r--crawl-ref/source/package.cc104
1 files changed, 60 insertions, 44 deletions
diff --git a/crawl-ref/source/package.cc b/crawl-ref/source/package.cc
index e2512ce42d..7a100344cd 100644
--- a/crawl-ref/source/package.cc
+++ b/crawl-ref/source/package.cc
@@ -31,6 +31,7 @@ Caveats/issues:
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
+#include <sstream>
#include "AppHdr.h"
#include "package.h"
@@ -53,7 +54,7 @@ static len_t htole(len_t x)
return htole32(x);
if (sizeof(len_t) == 8)
return htole64(x);
- ASSERT(!"unsupported len_t size");
+ die("unsupported len_t size");
}
#ifdef DEBUG_PACKAGE
@@ -62,13 +63,13 @@ static len_t htole(len_t x)
#define dprintf(...) do {} while(0)
#endif
-#define PACKAGE_VERSION 0
+#define PACKAGE_VERSION 1
#define PACKAGE_MAGIC 0x53534344 /* "DCSS" */
struct file_header
{
- int32_t magic;
- int8_t version;
+ uint32_t magic;
+ uint8_t version;
char padding[3];
len_t start;
};
@@ -79,12 +80,6 @@ struct block_header
len_t next;
};
-struct dir_entry
-{
- char name[sizeof(len_t)];
- len_t start;
-};
-
typedef std::map<std::string, len_t> directory_t;
typedef std::pair<len_t, len_t> bm_p;
typedef std::map<len_t, bm_p> bm_t;
@@ -151,14 +146,11 @@ void package::load()
if (htole(head.magic) != PACKAGE_MAGIC)
fail("save file (%s) corrupted -- not a DCSS save file",
filename.c_str());
- if (head.version != PACKAGE_VERSION)
- fail("save file (%s) uses an unknown format %u", filename.c_str(),
- head.version);
off_t len = lseek(fd, 0, SEEK_END);
if (len == -1)
sysfail("save file (%s) is not seekable", filename.c_str());
file_len = len;
- read_directory(htole(head.start));
+ read_directory(htole(head.start), head.version);
if (rw)
{
@@ -343,25 +335,22 @@ len_t package::write_directory()
{
delete_chunk("");
- std::vector<dir_entry> dir;
- dir.reserve(directory.size());
+ std::stringstream dir;
for (directory_t::iterator i = directory.begin();
i != directory.end(); i++)
{
- dir_entry ch;
- // probably the only case ever when strncpy() does exactly the
- // right thing
- strncpy(ch.name, i->first.c_str(), sizeof(ch.name));
- ch.start = htole(i->second);
- dir.push_back(ch);
+ uint8_t name_len = i->first.length();
+ dir.write((const char*)&name_len, sizeof(name_len));
+ dir.write(&i->first[0], i->first.length());
+ len_t start = htole(i->second);
+ dir.write((const char*)&start, sizeof(len_t));
}
- ASSERT(dir.size());
- dprintf("writing directory of size %u*%u\n", (unsigned int)dir.size(),
- (unsigned int)sizeof(dir_entry));
+ ASSERT(dir.str().size());
+ dprintf("writing directory (%u bytes)\n", (unsigned int)dir.str().size());
{
chunk_writer dch(this, "");
- dch.write(&dir.front(), dir.size() * sizeof(dir_entry));
+ dch.write(&dir.str()[0], dir.str().size());
}
return directory[""];
@@ -457,26 +446,55 @@ void package::fsck()
file_len = save_file_len;
}
-void package::read_directory(len_t start)
+struct dir_entry0
+{
+ char name[sizeof(len_t)];
+ len_t start;
+};
+
+void package::read_directory(len_t start, uint8_t version)
{
ASSERT(directory.empty());
directory[""] = start;
dprintf("package: reading directory\n");
- chunk_reader *rd = new chunk_reader(this, start);
+ chunk_reader rd(this, start);
- dir_entry ch;
- while(len_t res = rd->read(&ch, sizeof(dir_entry)))
+ switch(version)
{
- if (res != sizeof(dir_entry))
- fail("save file corrupted -- truncated directory");
- std::string chname(ch.name, 4);
- chname.resize(strlen(chname.c_str()));
- directory[chname] = htole(ch.start);
- dprintf("* %s\n", chname.c_str());
+ case 0:
+ dir_entry0 ch0;
+ while(len_t res = rd.read(&ch0, sizeof(dir_entry0)))
+ {
+ if (res != sizeof(dir_entry0))
+ fail("save file corrupted -- truncated directory");
+ std::string chname(ch0.name, 4);
+ chname.resize(strlen(chname.c_str()));
+ directory[chname] = htole(ch0.start);
+ dprintf("* %s\n", chname.c_str());
+ }
+ break;
+ case 1:
+ uint8_t name_len;
+ len_t bstart;
+ while(len_t res = rd.read(&name_len, sizeof(name_len)))
+ {
+ if (res != sizeof(name_len))
+ fail("save file corrupted -- truncated directory");
+ std::string chname;
+ chname.resize(name_len);
+ if (rd.read(&chname[0], name_len) != name_len)
+ fail("save file corrupted -- truncated directory");
+ if (rd.read(&bstart, sizeof(bstart)) != sizeof(bstart))
+ fail("save file corrupted -- truncated directory");
+ directory[chname] = htole(bstart);
+ dprintf("* %s\n", chname.c_str());
+ }
+ break;
+ default:
+ fail("save file (%s) uses an unknown format %u", filename.c_str(),
+ version);
}
-
- delete rd;
}
bool package::has_chunk(const std::string name)
@@ -556,12 +574,9 @@ chunk_writer::chunk_writer(package *parent, const std::string _name)
ASSERT(parent);
ASSERT(!parent->aborted);
- /*
- The save format is currently limited to 4 character names for simplicity
- (we use 3 max). If you want to extend this, please implement marshalling
- of arbitrary strings in {read,write}_directory().
- */
- ASSERT(_name.size() <= 4);
+ // If you need more, please change {read,write}_directory().
+ ASSERT(MAX_CHUNK_NAME_LENGTH < 256);
+ ASSERT(_name.length() < MAX_CHUNK_NAME_LENGTH);
dprintf("chunk_writer(%s): starting\n", _name.c_str());
pkg = parent;
@@ -592,6 +607,7 @@ chunk_writer::~chunk_writer()
#ifdef USE_ZLIB
// ignore errors, they're not relevant anymore
deflateEnd(&zs);
+ free(z_buffer);
#endif
return;
}