| |
| |
| #include "tw/stringtable.h" |
| |
| |
| #include "tfilepath_io.h" |
| #include "tenv.h" |
| |
| #include "tsystem.h" |
| #include "tstream.h" |
| #include "tconvert.h" |
| |
| namespace { |
| |
| |
| |
| class TStringTableImp final : public TStringTable { |
| public: |
| bool m_initialized; |
| |
| std::map<std::string, Item> m_table; |
| std::pair<std::string, int> m_defaultFontNameAndSize; |
| std::string m_defaultMacFontName; |
| |
| TStringTableImp(); |
| ~TStringTableImp(); |
| |
| void init(); |
| |
| void load(const TFilePath &); |
| |
| void loadCoded(const TFilePath &); |
| void saveCoded(const TFilePath &); |
| |
| const Item *getItem(std::string name) const override; |
| std::pair<std::string, int> getDefaultFontNameAndSize() const override { |
| return m_defaultFontNameAndSize; |
| } |
| std::string getDefaultMacFontName() const override; |
| }; |
| |
| |
| |
| 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 (...) { |
| } |
| } |
| |
| |
| |
| std::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, std::string s) { |
| int len = s.length(); |
| writeShort(os, len); |
| os.write(s.c_str(), len); |
| if (len & 0x3) { |
| os.write("____", 4 - (len & 0x3)); |
| } |
| } |
| |
| |
| |
| std::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 std::string(buffer, len); |
| } |
| |
| |
| |
| void writeStringW(Tofstream &os, std::wstring s) { |
| int len = s.length(); |
| writeShort(os, len); |
| os.write(reinterpret_cast<const char *>(s.c_str()), sizeof(wchar_t) * len); |
| } |
| |
| |
| |
| std::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 std::wstring(buffer, len); |
| } |
| |
| |
| #ifdef MACOSX |
| class TMagic // singleton |
| { |
| public: |
| std::string m_magic; |
| |
| private: |
| TMagic() : m_magic("stab.001") {} |
| |
| public: |
| static TMagic *instance() { |
| static TMagic inst; |
| ; |
| return &inst; |
| } |
| }; |
| |
| #else |
| const std::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); |
| std::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); |
| |
| |
| } catch (...) { |
| |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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 "); |
| |
| std::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") { |
| std::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 = ::to_wstring(name); |
| item.m_help = ::to_wstring(help); |
| item.m_tip = ::to_wstring(tip); |
| } else if (tagName == "defaultFont") { |
| std::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") { |
| std::string macFontName; |
| is >> macFontName; |
| if (!is.matchEndTag()) throw TException("Expected end tag"); |
| m_defaultMacFontName = macFontName; |
| } else |
| throw TException("unexpected tag /" + tagName + "/"); |
| } |
| |
| } |
| |
| |
| |
| const TStringTable::Item *TStringTableImp::getItem(std::string name) const { |
| std::map<std::string, Item>::const_iterator it; |
| it = m_table.find(name); |
| if (it == m_table.end()) |
| return 0; |
| else |
| return &(it->second); |
| } |
| |
| |
| |
| } |
| |
| |
| |
| TStringTable::TStringTable() {} |
| |
| |
| |
| TStringTable::~TStringTable() {} |
| |
| |
| |
| std::wstring TStringTable::translate(std::string name) { |
| const TStringTable::Item *item = instance()->getItem(name); |
| if (item) |
| return item->m_name; |
| else |
| return ::to_wstring(name); |
| } |
| |
| |
| |
| const TStringTable *TStringTable::instance() { |
| |
| static TStringTableImp *instance = 0; |
| if (!instance) instance = new TStringTableImp; |
| |
| instance->init(); |
| |
| return instance; |
| } |
| |