pennmush/dbtools/db_labelsv1.cpp
2018-03-02 21:56:24 -08:00

417 lines
12 KiB
C++

// db_labelsv1.cpp
//
// Read a current Penn database.
#include <iostream>
#include <string>
#include <utility>
#include "database.h"
#include "io_primitives.h"
#include "utils.h"
#include "bits.h"
#include "db_common.h"
using namespace std::literals::string_literals;
flagmap
read_flags(istream &in)
{
flagmap flags;
int count = db_read_this_labeled_int(in, "flagcount");
#ifdef HAVE_BOOST_CONTAINERS
flags.reserve(count + 10);
#endif
for (int n = 0; n < count; n += 1) {
flag f;
auto name = db_read_this_labeled_string(in, "name");
auto letter = db_read_this_labeled_string(in, "letter");
f.name = name;
f.letter = letter.size() ? letter.front() : '\0';
f.types = split_words(db_read_this_labeled_string(in, "type"));
f.perms = split_words(db_read_this_labeled_string(in, "perms"));
f.negate_perms =
split_words(db_read_this_labeled_string(in, "negate_perms"));
flags.emplace_hint(flags.end(), std::move(name), std::move(f));
}
count = db_read_this_labeled_int(in, "flagaliascount");
for (int n = 0; n < count; n += 1) {
auto name = db_read_this_labeled_string(in, "name");
auto alias = db_read_this_labeled_string(in, "alias");
auto orig = flags.find(name);
if (orig != flags.end()) {
flags.emplace(alias, orig->second);
}
}
return flags;
}
attrmap
read_db_attribs(istream &in)
{
attrmap attribs;
int count = db_read_this_labeled_int(in, "attrcount");
#ifdef HAVE_BOOST_CONTAINERS
attribs.reserve(count + 20);
#endif
for (int n = 0; n < count; n += 1) {
attrib a;
auto name = db_read_this_labeled_string(in, "name");
a.name = name;
a.flags = split_words_vec(db_read_this_labeled_string(in, "flags"));
a.creator = db_read_this_labeled_dbref(in, "creator");
a.data = db_read_this_labeled_string(in, "data");
attribs.emplace_hint(attribs.end(), std::move(name), std::move(a));
}
count = db_read_this_labeled_int(in, "attraliascount");
for (int n = 0; n < count; n += 1) {
auto name = db_read_this_labeled_string(in, "name");
auto alias = db_read_this_labeled_string(in, "alias");
auto orig = attribs.find(name);
if (orig != attribs.end()) {
attribs.emplace(alias, orig->second);
}
}
return attribs;
}
attrmap
read_obj_attribs(istream &in, std::uint32_t flags)
{
attrmap attribs;
int count = db_read_this_labeled_int(in, "attrcount");
#ifdef HAVE_BOOST_CONTAINERS
attribs.reserve(count);
#endif
for (int n = 0; n < count; n += 1) {
attrib a;
auto name = db_read_this_labeled_string(in, "name");
a.name = name;
a.creator = db_read_this_labeled_dbref(in, "owner");
a.flags = split_words_vec(db_read_this_labeled_string(in, "flags"));
a.derefs = db_read_this_labeled_int(in, "derefs");
a.data = db_read_this_labeled_string(in, "value");
if (!(flags & DBF_SPIFFY_AF_ANSI)) {
/* Reparses ANSI using ansi_string stuff. Ignore. */
}
attribs.emplace_hint(attribs.end(), std::move(name), std::move(a));
}
return attribs;
}
// Only works with DBF_SPIFFY_LOCKS
lockmap
read_locks(istream &in, std::uint32_t flags)
{
lockmap locks;
constexpr std::uint32_t fullspiff_flags = DBF_LABELS | DBF_SPIFFY_LOCKS;
bool fullspiff = ((flags & fullspiff_flags) == fullspiff_flags);
int count = db_read_this_labeled_int(in, "lockcount");
#ifdef HAVE_BOOST_CONTAINERS
locks.reserve(count);
#endif
for (int n = 0; n < count; n += 1) {
lock l{};
std::string type;
if (fullspiff) {
type = db_read_this_labeled_string(in, "type");
l.type = type;
l.creator = db_read_this_labeled_dbref(in, "creator");
l.flags = split_words_vec(db_read_this_labeled_string(in, "flags"));
l.derefs = db_read_this_labeled_int(in, "derefs");
l.key = db_read_this_labeled_string(in, "key");
} else if (flags & DBF_SPIFFY_LOCKS) {
type = db_read_this_labeled_string(in, "type");
l.type = type;
l.creator = db_read_this_labeled_int(in, "creator");
l.flags = lockbits_to_vec(db_read_this_labeled_int(in, "flags"));
l.key = db_read_this_labeled_string(in, "key");
} else {
throw db_format_exception{"Unsupported lock format."};
}
locks.emplace_hint(locks.end(), std::move(type), std::move(l));
}
return locks;
}
dbthing
read_object(istream &in, dbref num, int, std::uint32_t flags)
{
dbthing obj;
obj.num = num;
obj.name = db_read_this_labeled_string(in, "name");
obj.location = db_read_this_labeled_dbref(in, "location");
obj.contents = db_read_this_labeled_dbref(in, "contents");
obj.exits = db_read_this_labeled_dbref(in, "exits");
obj.next = db_read_this_labeled_dbref(in, "next");
obj.parent = db_read_this_labeled_dbref(in, "parent");
obj.locks = read_locks(in, flags);
obj.owner = db_read_this_labeled_dbref(in, "owner");
obj.zone = db_read_this_labeled_dbref(in, "zone");
obj.pennies = db_read_this_labeled_int(in, "pennies");
obj.type = dbtype_from_num(db_read_this_labeled_int(in, "type"));
obj.flags = split_words(db_read_this_labeled_string(in, "flags"));
obj.powers = split_words(db_read_this_labeled_string(in, "powers"));
if (flags & DBF_WARNINGS) {
obj.warnings = split_words_vec(db_read_this_labeled_string(in, "warnings"));
}
if (flags & DBF_CREATION_TIMES) {
obj.created = db_read_this_labeled_u32(in, "created");
obj.modified = db_read_this_labeled_u32(in, "modified");
}
obj.attribs = read_obj_attribs(in, flags);
return obj;
}
database
read_db_labelsv1(istream &in, std::uint32_t flags)
{
std::uint32_t minimum_flags = DBF_LABELS | DBF_SPIFFY_LOCKS;
if ((flags & minimum_flags) != minimum_flags) {
// Pretty sure this should never happen.
throw db_format_exception{"Invalid database format."};
}
database db;
if (flags & DBF_NEW_VERSIONS) {
db.version = db_read_this_labeled_int(in, "dbversion");
}
db.saved_time = db_read_this_labeled_string(in, "savedtime");
char c;
std::string line;
while (in.get(c)) {
switch (c) {
case '+':
std::getline(in, line);
if (line == "FLAGS LIST") {
db.flags = read_flags(in);
} else if (line == "POWER LIST") {
db.powers = read_flags(in);
} else if (line == "ATTRIBUTES LIST") {
db.attribs = read_db_attribs(in);
} else {
throw db_format_exception{"unknown +LIST: "s + line};
}
break;
case '~': {
long len = db_getref(in);
db.objects.reserve(len);
} break;
case '!': {
dbref d = db_getref(in);
while (static_cast<std::size_t>(d) != db.objects.size()) {
if (!(flags & DBF_LESS_GARBAGE)) {
std::cerr << "Missing object #" << db.objects.size()
<< istream_line(in) << '\n';
}
dbthing garbage;
garbage.num = static_cast<dbref>(db.objects.size());
db.objects.emplace_back(std::move(garbage));
}
db.objects.emplace_back(read_object(in, d, db.version, flags));
} break;
case '*': {
std::string eod;
std::getline(in, eod);
if (eod != "**END OF DUMP***") {
throw db_format_exception{"Invalid end string: *"s + eod};
}
} break;
default:
throw db_format_exception{"Unexpected character: "s + c};
}
}
if (flags & DBF_SPIFFY_AF_ANSI) {
db.spiffy_af_ansi = true;
}
return db;
}
void
write_flags(std::ostream &out, const flagmap &flags)
{
std::vector<std::string> canon;
std::vector<std::string> aliases;
for (const auto &flag : flags) {
if (flag.first == flag.second.name) {
canon.push_back(flag.first);
} else {
aliases.push_back(flag.first);
}
}
out << "flagcount " << canon.size() << '\n';
for (const auto &name : canon) {
const auto &flag = flags.find(name)->second;
out << " name \"" << flag.name << "\"\n";
if (flag.letter) {
if (flag.letter == '"') {
out << R"( letter "\"")" << '\n';
} else {
out << " letter \"" << flag.letter << "\"\n";
}
} else {
out << " letter \"\"\n";
}
out << " type \"" << join_words(flag.types) << "\"\n";
out << " perms \"" << join_words(flag.perms) << "\"\n";
out << " negate_perms \"" << join_words(flag.negate_perms) << "\"\n";
}
out << "flagaliascount " << aliases.size() << '\n';
for (const auto &name : aliases) {
const auto &flag = flags.find(name)->second;
out << " name \"" << flag.name << "\"\n";
out << " alias \"" << name << "\"\n";
}
}
void
write_db_attribs(std::ostream &out, const attrmap &attribs)
{
std::vector<std::string> canon;
std::vector<std::string> aliases;
for (const auto &attr : attribs) {
if (attr.first == attr.second.name) {
canon.push_back(attr.first);
} else {
aliases.push_back(attr.first);
}
}
out << "attrcount " << canon.size() << '\n';
for (const auto &name : canon) {
const auto &attr = attribs.find(name)->second;
out << " name \"" << attr.name << "\"\n";
out << " flags \"" << join_words(attr.flags) << "\"\n";
out << " creator #" << attr.creator << '\n';
out << " data \"\"\n";
}
out << "attraliascount " << aliases.size() << '\n';
for (const auto &name : aliases) {
const auto &attr = attribs.find(name)->second;
out << " name \"" << attr.name << "\"\n";
out << " alias \"" << name << "\"\n";
}
}
void
write_locks(std::ostream &out, const lockmap &locks)
{
out << "lockcount " << locks.size() << '\n';
for (const auto &l : locks) {
const auto &lk = l.second;
out << " type \"" << lk.type << "\"\n";
out << " creator #" << lk.creator << '\n';
out << " flags \"" << join_words(lk.flags) << "\"\n";
out << " derefs " << lk.derefs << '\n';
db_write_labeled_string(out, " key", lk.key);
}
}
void
write_obj_attribs(std::ostream &out, const attrmap &attribs)
{
out << "attrcount " << attribs.size() << '\n';
for (const auto &a : attribs) {
const auto &attr = a.second;
out << " name \"" << attr.name << "\"\n";
out << " owner #" << attr.creator << '\n';
out << " flags \"" << join_words(attr.flags) << "\"\n";
out << " derefs " << attr.derefs << '\n';
db_write_labeled_string(out, " value", attr.data);
}
}
void
write_db_labelsv1(std::ostream &out, const database &db)
{
int dbflag = 5;
dbflag += DBF_NO_CHAT_SYSTEM;
dbflag += DBF_WARNINGS;
dbflag += DBF_CREATION_TIMES;
dbflag += DBF_SPIFFY_LOCKS;
dbflag += DBF_NEW_STRINGS;
dbflag += DBF_TYPE_GARBAGE;
dbflag += DBF_SPLIT_IMMORTAL;
dbflag += DBF_NO_TEMPLE;
dbflag += DBF_LESS_GARBAGE;
dbflag += DBF_AF_VISUAL;
dbflag += DBF_VALUE_IS_COST;
dbflag += DBF_LINK_ANYWHERE;
dbflag += DBF_NO_STARTUP_FLAG;
dbflag += DBF_AF_NODUMP;
dbflag += DBF_NEW_FLAGS;
dbflag += DBF_NEW_POWERS;
dbflag += DBF_POWERS_LOGGED;
dbflag += DBF_LABELS;
dbflag += DBF_HEAR_CONNECT;
dbflag += DBF_NEW_VERSIONS;
if (db.spiffy_af_ansi) {
dbflag += DBF_SPIFFY_AF_ANSI;
}
dbflag = dbflag * 256 + 2;
out << "+V" << dbflag << '\n';
out << "dbversion 6\n";
out << "savedtime \"" << get_time() << "\"\n";
out << "+FLAGS LIST\n";
write_flags(out, db.flags);
out << "+POWER LIST\n";
write_flags(out, db.powers);
out << "+ATTRIBUTES LIST\n";
write_db_attribs(out, db.attribs);
out << '~' << db.objects.size() << '\n';
for (const auto &obj : db.objects) {
if (obj.type == dbtype::GARBAGE) {
continue;
}
out << '!' << obj.num << '\n';
db_write_labeled_string(out, "name", obj.name);
out << "location #" << obj.location << '\n';
out << "contents #" << obj.contents << '\n';
out << "exits #" << obj.exits << '\n';
out << "next #" << obj.next << '\n';
out << "parent #" << obj.parent << '\n';
write_locks(out, obj.locks);
out << "owner #" << obj.owner << '\n';
out << "zone #" << obj.zone << '\n';
out << "pennies " << obj.pennies << '\n';
out << "type " << dbtype_to_num(obj.type) << '\n';
out << "flags \"" << join_words(obj.flags) << "\"\n";
out << "powers \"" << join_words(obj.powers) << "\"\n";
out << "warnings \"" << join_words(obj.warnings) << "\"\n";
out << "created " << obj.created << '\n';
out << "modified " << obj.modified << '\n';
write_obj_attribs(out, obj.attribs);
}
out << "***END OF DUMP***\n";
}