#include "tw/stringtable.h"
// #include "tw/message.h"
//#include "tfilepath.h"
#include "tfilepath_io.h"
#include "tenv.h"
//#include "texception.h"
#include "tsystem.h"
#include "tstream.h"
#include "tconvert.h"
namespace
{
//-------------------------------------------------------------------
class TStringTableImp : public TStringTable
{
public:
bool m_initialized;
map<string, Item> m_table;
std::pair<string, int> m_defaultFontNameAndSize;
string m_defaultMacFontName;
TStringTableImp();
~TStringTableImp();
void init();
void load(const TFilePath &);
void loadCoded(const TFilePath &);
void saveCoded(const TFilePath &);
const Item *getItem(string name) const;
std::pair<string, int> getDefaultFontNameAndSize() const
{
return m_defaultFontNameAndSize;
}
string getDefaultMacFontName() const;
};
//-------------------------------------------------------------------
TStringTableImp::TStringTableImp()
: m_initialized(false), m_defaultFontNameAndSize("", 0), m_defaultMacFontName("")
{
}
//-------------------------------------------------------------------
TStringTableImp::~TStringTableImp()
{
}
//-------------------------------------------------------------------
void TStringTableImp::init()
{
if (m_initialized)
return;
m_initialized = true;
TFilePath plainFp = TEnv::getConfigDir() + "current.txt";
try {
load(plainFp);
} catch (...) {
}
}
//-------------------------------------------------------------------
string TStringTableImp::getDefaultMacFontName() const
{
return m_defaultMacFontName;
}
//-------------------------------------------------------------------
void writeShort(Tofstream &os, int x)
{
os.put(x & 0xff);
os.put((x >> 8) & 0xff);
}
//-------------------------------------------------------------------
int readShort(Tifstream &is)
{
char hi = 0, lo = 0;
is.get(lo);
is.get(hi);
return (unsigned char)hi << 8 | (unsigned char)lo;
}
//-------------------------------------------------------------------
void writeString(Tofstream &os, string s)
{
int len = s.length();
writeShort(os, len);
os.write(s.c_str(), len);
if (len & 0x3) {
os.write("____", 4 - (len & 0x3));
}
}
//-------------------------------------------------------------------
string readString(Tifstream &is)
{
int len = readShort(is);
int len2 = len;
if (len2 & 0x3)
len2 += 4 - (len2 & 0x3);
char buffer[1204];
assert(len2 <= (int)(sizeof(buffer)));
is.read(buffer, len2);
return string(buffer, len);
}
//-------------------------------------------------------------------
void writeStringW(Tofstream &os, wstring s)
{
int len = s.length();
writeShort(os, len);
os.write(reinterpret_cast<const char *>(s.c_str()), sizeof(wchar_t) * len);
}
//-------------------------------------------------------------------
wstring readStringW(Tifstream &is)
{
int len = readShort(is);
wchar_t buffer[1204];
assert(len <= (int)(sizeof(buffer)));
is.read(reinterpret_cast<char *>(buffer), sizeof(wchar_t) * len);
return wstring(buffer, len);
}
//-------------------------------------------------------------------
#ifdef MACOSX
class TMagic //singleton
{
public:
string m_magic;
private:
TMagic()
: m_magic("stab.001")
{
}
public:
static TMagic *instance()
{
static TMagic inst;
;
return &inst;
}
};
#else
const string magic = "stab.001";
#endif
void TStringTableImp::loadCoded(const TFilePath &fp)
{
try {
Tifstream is(fp);
char buffer[1024];
#ifdef MACOSX
is.read(buffer, TMagic::instance()->m_magic.length());
#else
is.read(buffer, magic.length());
#endif
m_defaultFontNameAndSize.first = readString(is);
m_defaultFontNameAndSize.second = readShort(is);
int count = readShort(is);
for (int i = 0; i < count; i++) {
int m = readShort(is);
assert(1 <= m && m <= 3);
string id = readString(is);
Item &item = m_table[id];
item.m_name = readStringW(is);
if (m >= 2) {
item.m_help = readStringW(is);
if (m == 3)
item.m_tip = readStringW(is);
}
}
int check = readShort(is);
assert(check == 12345);
//if(check != 12345)
// throw;
} catch (...) {
// TMessage::error("Error reading StringTable file: ", fp);
}
}
//-------------------------------------------------------------------
/*
void TStringTableImp::saveCoded(const TFilePath &fp)
{
try {
Tofstream os(fp);
#ifdef MACOSX
os.write(TMagic::instance()->m_magic.c_str(), TMagic::instance()->m_magic.length());
#else
os.write(magic.c_str(), magic.length());
#endif
writeString(os, m_defaultFontNameAndSize.first);
writeShort(os, m_defaultFontNameAndSize.second);
writeShort(os, m_table.size());
for(std::map<string, Item>::iterator it = m_table.begin();
it != m_table.end(); ++it)
{
Item &item = it->second;
int m = 1;
if(item.m_tip != L"") m = 3;
else if(item.m_help != L"") m = 2;
writeShort(os, m);
writeString(os, it->first);
writeStringW(os, item.m_name);
if(m>=2)
{
writeStringW(os, item.m_help);
if(m==3)
writeStringW(os, item.m_tip);
}
}
writeShort(os, 12345);
} catch(...) {
TMessage::error("Unable to save StringTable file: ", fp);
}
}
*/
//-------------------------------------------------------------------
void TStringTableImp::load(const TFilePath &fp)
{
if (!TFileStatus(fp).doesExist())
throw TException("file not found");
TIStream is(fp);
if (!is)
throw TException("can't read string table ");
string tagName;
if (!is.matchTag(tagName) || tagName != "stringtable")
throw TException("not a string table file");
while (!is.matchEndTag()) {
if (!is.matchTag(tagName))
throw TException("expected tag");
if (tagName == "item") {
string id, name, help, tip;
is >> id >> name;
if (!is.matchEndTag()) {
is >> help;
if (!is.matchEndTag()) {
is >> tip;
if (!is.matchEndTag())
throw TException("Expected end tag");
}
}
Item &item = m_table[id];
item.m_name = toWideString(name);
item.m_help = toWideString(help);
item.m_tip = toWideString(tip);
} else if (tagName == "defaultFont") {
string fontName;
int fontSize = 0;
is >> fontName >> fontSize;
if (!is.matchEndTag())
throw TException("Expected end tag");
m_defaultFontNameAndSize = std::make_pair(fontName, fontSize);
} else if (tagName == "defaultMacFont") {
string macFontName;
is >> macFontName;
if (!is.matchEndTag())
throw TException("Expected end tag");
m_defaultMacFontName = macFontName;
} else
throw TException("unexpected tag /" + tagName + "/");
}
//m_valid =true;
}
//-------------------------------------------------------------------
const TStringTable::Item *TStringTableImp::getItem(string name) const
{
std::map<string, Item>::const_iterator it;
it = m_table.find(name);
if (it == m_table.end())
return 0;
else
return &(it->second);
}
//-------------------------------------------------------------------
} // namespace
//-------------------------------------------------------------------
TStringTable::TStringTable()
{
}
//-------------------------------------------------------------------
TStringTable::~TStringTable()
{
}
//-------------------------------------------------------------------
wstring TStringTable::translate(string name)
{
const TStringTable::Item *item = instance()->getItem(name);
if (item)
return item->m_name;
else
return toWideString(name);
}
//-------------------------------------------------------------------
const TStringTable *TStringTable::instance()
{
// may hurt MacOsX
static TStringTableImp *instance = 0;
if (!instance)
instance = new TStringTableImp;
instance->init();
return instance;
}