Make the two-parameter global load function take a reference as the second parameter
Use numeric IDs for short strings in binary mode
ParserMode(i, s),
first(true)
{
- dict[1]=DictEntry("__st", "iss");
- dict[2]=DictEntry("__enum", "is");
+ dict[1]=DictEntry("__kwd", "iss");
+ dict[2]=DictEntry("__str", "is");
}
Statement BinaryParser::parse()
while(1)
{
Statement st=parse_statement();
- if(st.keyword=="__st")
+ if(st.keyword=="__kwd")
{
if(st.args.size()!=3)
throw TypeError(src+": Keyword definition must have three arguments");
const string &args=st.args[2].get<const string &>();
dict[id]=DictEntry(kw, args);
}
- else if(st.keyword=="__enum")
+ else if(st.keyword=="__str")
{
if(st.args.size()!=2)
- throw TypeError(src+": Enum definition must have three arguments");
+ throw TypeError(src+": String definition must have two arguments");
const unsigned id=st.args[0].get<unsigned>();
- enums[id]=st.args[1].get<const std::string &>();
+ strings[id]=st.args[1].get<const string &>();
}
else
return st;
break;
}
- const long long mask=1<<(bits-1);
+ const long long mask=1LL<<(bits-1);
result=(result^mask)-mask;
return result;
string BinaryParser::parse_string()
{
- unsigned len=parse_int();
- string result;
- result.reserve(len);
- for(unsigned i=0; i<len; ++i)
- result+=in.get();
- return result;
+ int len=parse_int();
+ if(len>=0)
+ {
+ string result;
+ result.reserve(len);
+ for(int i=0; i<len; ++i)
+ result+=in.get();
+ return result;
+ }
+ else
+ return lookup_string(-len);
}
string BinaryParser::parse_enum()
{
- unsigned id=parse_int();
- EnumMap::iterator i=enums.find(id);
- if(i==enums.end())
- throw KeyError("Unknown enum", lexical_cast(id));
+ return lookup_string(parse_int());
+}
+
+const string &BinaryParser::lookup_string(unsigned id) const
+{
+ StringMap::const_iterator i=strings.find(id);
+ if(i==strings.end())
+ throw KeyError("Unknown string", lexical_cast(id));
return i->second;
}
{
private:
typedef std::map<unsigned, DictEntry> Dictionary;
- typedef std::map<unsigned, std::string> EnumMap;
+ typedef std::map<unsigned, std::string> StringMap;
Dictionary dict;
- EnumMap enums;
+ StringMap strings;
bool first;
public:
std::string parse_string();
bool parse_bool();
std::string parse_enum();
+ const std::string &lookup_string(unsigned) const;
};
} // namespace DataFile
BinaryWriter::BinaryWriter(IO::Base &o):
WriterMode(o),
- next_st_id(3),
- next_enum_id(1)
+ next_kwd_id(3),
+ next_str_id(1)
{
- dict[DictEntry("__st", "iss")]=1;
- dict[DictEntry("__enum", "is")]=2;
+ dict[DictEntry("__kwd", "iss")]=1;
+ dict[DictEntry("__str", "is")]=2;
}
void BinaryWriter::write(const Statement &st)
if(!dict.count(de))
{
Statement kst;
- kst.keyword="__st";
- kst.args.push_back(next_st_id);
+ kst.keyword="__kwd";
+ kst.args.push_back(next_kwd_id);
kst.args.push_back(de.keyword);
kst.args.push_back(de.args);
write_(kst);
- dict[de]=next_st_id++;
+ dict[de]=next_kwd_id++;
}
for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i)
- if(i->get_type()==ENUM && !enums.count(i->get_raw()))
+ {
+ const Type t=i->get_type();
+ const string &r=i->get_raw();
+ if((t==ENUM || (t==STRING && r.size()<32)) && !strings.count(r))
{
- Statement est;
- est.keyword="__enum";
- est.args.push_back(next_enum_id);
- est.args.push_back(i->get_raw());
- write_(est);
+ Statement sst;
+ sst.keyword="__str";
+ sst.args.push_back(next_str_id);
+ sst.args.push_back(r);
+ write_(sst);
- enums[i->get_raw()]=next_enum_id++;
+ strings[r]=next_str_id++;
}
+ }
for(list<Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
collect_keywords(*i);
void BinaryWriter::write_string(const string &s)
{
- write_int(s.size());
- out.write(s.data(), s.size());
+ StringMap::const_iterator i=strings.find(s);
+ if(i!=strings.end())
+ write_int(-static_cast<int>(i->second));
+ else
+ {
+ write_int(s.size());
+ out.write(s.data(), s.size());
+ }
}
void BinaryWriter::write_float(float f)
void BinaryWriter::write_enum(const string &e)
{
- EnumMap::const_iterator i=enums.find(e);
- if(i==enums.end())
+ StringMap::const_iterator i=strings.find(e);
+ if(i==strings.end())
throw InvalidParameterValue("Unknown enum");
write_int(i->second);
}
{
private:
typedef std::map<DictEntry, unsigned> Dictionary;
- typedef std::map<std::string, unsigned> EnumMap;
+ typedef std::map<std::string, unsigned> StringMap;
Dictionary dict;
- unsigned next_st_id;
- EnumMap enums;
- unsigned next_enum_id;
+ unsigned next_kwd_id;
+ StringMap strings;
+ unsigned next_str_id;
public:
BinaryWriter(IO::Base &o);
*/
bool contains(const std::string &n) const;
+ /**
+ Returns the name of an item in the collection.
+ */
+ template<typename T>
+ const std::string &get_name(T *d) const
+ {
+ typedef typename RemoveConst<T>::Type NCT;
+
+ for(ItemMap::const_iterator i=items.begin(); i!=items.end(); ++i)
+ if(Item<NCT> *item=dynamic_cast<Item<NCT> *>(i->second))
+ if(item->data==d)
+ return i->first;
+
+ throw KeyError("Item not found in collection");
+ }
+
protected:
/**
Adds a type that can be loaded from datafiles.
}
template<typename T, typename U>
-void load(T &obj, const std::string &fn, U arg)
+void load(T &obj, const std::string &fn, U &arg)
{
IO::File in(fn);
IO::Buffered buf(in);