1 
2 
3 #include "tw/stringtable.h"
4 // #include "tw/message.h"
5 //#include "tfilepath.h"
6 #include "tfilepath_io.h"
7 #include "tenv.h"
8 //#include "texception.h"
9 #include "tsystem.h"
10 #include "tstream.h"
11 #include "tconvert.h"
12 
13 namespace {
14 
15 //-------------------------------------------------------------------
16 
17 class TStringTableImp final : public TStringTable {
18 public:
19   bool m_initialized;
20 
21   std::map<std::string, Item> m_table;
22   std::pair<std::string, int> m_defaultFontNameAndSize;
23   std::string m_defaultMacFontName;
24 
25   TStringTableImp();
26   ~TStringTableImp();
27 
28   void init();
29 
30   void load(const TFilePath &);
31 
32   void loadCoded(const TFilePath &);
33   void saveCoded(const TFilePath &);
34 
35   const Item *getItem(std::string name) const override;
getDefaultFontNameAndSize() const36   std::pair<std::string, int> getDefaultFontNameAndSize() const override {
37     return m_defaultFontNameAndSize;
38   }
39   std::string getDefaultMacFontName() const override;
40 };
41 
42 //-------------------------------------------------------------------
43 
TStringTableImp()44 TStringTableImp::TStringTableImp()
45     : m_initialized(false)
46     , m_defaultFontNameAndSize("", 0)
47     , m_defaultMacFontName("") {}
48 
49 //-------------------------------------------------------------------
50 
~TStringTableImp()51 TStringTableImp::~TStringTableImp() {}
52 
53 //-------------------------------------------------------------------
54 
init()55 void TStringTableImp::init() {
56   if (m_initialized) return;
57 
58   m_initialized = true;
59 
60   TFilePath plainFp = TEnv::getConfigDir() + "current.txt";
61 
62   try {
63     load(plainFp);
64   } catch (...) {
65   }
66 }
67 
68 //-------------------------------------------------------------------
69 
getDefaultMacFontName() const70 std::string TStringTableImp::getDefaultMacFontName() const {
71   return m_defaultMacFontName;
72 }
73 
74 //-------------------------------------------------------------------
75 
writeShort(Tofstream & os,int x)76 void writeShort(Tofstream &os, int x) {
77   os.put(x & 0xff);
78   os.put((x >> 8) & 0xff);
79 }
80 
81 //-------------------------------------------------------------------
82 
readShort(Tifstream & is)83 int readShort(Tifstream &is) {
84   char hi = 0, lo = 0;
85   is.get(lo);
86   is.get(hi);
87   return (unsigned char)hi << 8 | (unsigned char)lo;
88 }
89 
90 //-------------------------------------------------------------------
91 
writeString(Tofstream & os,std::string s)92 void writeString(Tofstream &os, std::string s) {
93   int len = s.length();
94   writeShort(os, len);
95   os.write(s.c_str(), len);
96   if (len & 0x3) {
97     os.write("____", 4 - (len & 0x3));
98   }
99 }
100 
101 //-------------------------------------------------------------------
102 
readString(Tifstream & is)103 std::string readString(Tifstream &is) {
104   int len  = readShort(is);
105   int len2 = len;
106   if (len2 & 0x3) len2 += 4 - (len2 & 0x3);
107   char buffer[1204];
108   assert(len2 <= (int)(sizeof(buffer)));
109   is.read(buffer, len2);
110   return std::string(buffer, len);
111 }
112 
113 //-------------------------------------------------------------------
114 
writeStringW(Tofstream & os,std::wstring s)115 void writeStringW(Tofstream &os, std::wstring s) {
116   int len = s.length();
117   writeShort(os, len);
118   os.write(reinterpret_cast<const char *>(s.c_str()), sizeof(wchar_t) * len);
119 }
120 
121 //-------------------------------------------------------------------
122 
readStringW(Tifstream & is)123 std::wstring readStringW(Tifstream &is) {
124   int len = readShort(is);
125   wchar_t buffer[1204];
126   assert(len <= (int)(sizeof(buffer)));
127   is.read(reinterpret_cast<char *>(buffer), sizeof(wchar_t) * len);
128   return std::wstring(buffer, len);
129 }
130 
131 //-------------------------------------------------------------------
132 #ifdef MACOSX
133 class TMagic  // singleton
134 {
135 public:
136   std::string m_magic;
137 
138 private:
TMagic()139   TMagic() : m_magic("stab.001") {}
140 
141 public:
instance()142   static TMagic *instance() {
143     static TMagic inst;
144     ;
145     return &inst;
146   }
147 };
148 
149 #else
150 const std::string magic = "stab.001";
151 #endif
152 
loadCoded(const TFilePath & fp)153 void TStringTableImp::loadCoded(const TFilePath &fp) {
154   try {
155     Tifstream is(fp);
156     char buffer[1024];
157 
158 #ifdef MACOSX
159     is.read(buffer, TMagic::instance()->m_magic.length());
160 #else
161     is.read(buffer, magic.length());
162 #endif
163 
164     m_defaultFontNameAndSize.first  = readString(is);
165     m_defaultFontNameAndSize.second = readShort(is);
166     int count                       = readShort(is);
167     for (int i = 0; i < count; i++) {
168       int m = readShort(is);
169       assert(1 <= m && m <= 3);
170       std::string id = readString(is);
171       Item &item     = m_table[id];
172       item.m_name    = readStringW(is);
173       if (m >= 2) {
174         item.m_help            = readStringW(is);
175         if (m == 3) item.m_tip = readStringW(is);
176       }
177     }
178     int check = readShort(is);
179     assert(check == 12345);
180     // if(check != 12345)
181     //  throw;
182   } catch (...) {
183     // TMessage::error("Error reading StringTable file: ", fp);
184   }
185 }
186 
187 //-------------------------------------------------------------------
188 
189 /*
190 void TStringTableImp::saveCoded(const TFilePath &fp)
191 {
192   try {
193     Tofstream os(fp);
194 
195 #ifdef MACOSX
196     os.write(TMagic::instance()->m_magic.c_str(),
197 TMagic::instance()->m_magic.length());
198  #else
199     os.write(magic.c_str(), magic.length());
200  #endif
201     writeString(os, m_defaultFontNameAndSize.first);
202     writeShort(os, m_defaultFontNameAndSize.second);
203     writeShort(os, m_table.size());
204     for(std::map<std::string, Item>::iterator it = m_table.begin();
205         it != m_table.end(); ++it)
206       {
207        Item &item = it->second;
208        int m = 1;
209        if(item.m_tip != L"") m = 3;
210        else if(item.m_help != L"") m = 2;
211        writeShort(os, m);
212        writeString(os, it->first);
213        writeStringW(os, item.m_name);
214        if(m>=2)
215          {
216           writeStringW(os, item.m_help);
217           if(m==3)
218             writeStringW(os, item.m_tip);
219          }
220       }
221     writeShort(os, 12345);
222   } catch(...) {
223     TMessage::error("Unable to save StringTable file: ", fp);
224   }
225 }
226 */
227 //-------------------------------------------------------------------
228 
load(const TFilePath & fp)229 void TStringTableImp::load(const TFilePath &fp) {
230   if (!TFileStatus(fp).doesExist()) throw TException("file not found");
231 
232   TIStream is(fp);
233   if (!is) throw TException("can't read string table ");
234 
235   std::string tagName;
236   if (!is.matchTag(tagName) || tagName != "stringtable")
237     throw TException("not a string table file");
238 
239   while (!is.matchEndTag()) {
240     if (!is.matchTag(tagName)) throw TException("expected tag");
241     if (tagName == "item") {
242       std::string id, name, help, tip;
243       is >> id >> name;
244       if (!is.matchEndTag()) {
245         is >> help;
246         if (!is.matchEndTag()) {
247           is >> tip;
248           if (!is.matchEndTag()) throw TException("Expected end tag");
249         }
250       }
251       Item &item  = m_table[id];
252       item.m_name = ::to_wstring(name);
253       item.m_help = ::to_wstring(help);
254       item.m_tip  = ::to_wstring(tip);
255     } else if (tagName == "defaultFont") {
256       std::string fontName;
257       int fontSize = 0;
258       is >> fontName >> fontSize;
259       if (!is.matchEndTag()) throw TException("Expected end tag");
260       m_defaultFontNameAndSize = std::make_pair(fontName, fontSize);
261     } else if (tagName == "defaultMacFont") {
262       std::string macFontName;
263       is >> macFontName;
264       if (!is.matchEndTag()) throw TException("Expected end tag");
265       m_defaultMacFontName = macFontName;
266     } else
267       throw TException("unexpected tag /" + tagName + "/");
268   }
269   // m_valid =true;
270 }
271 
272 //-------------------------------------------------------------------
273 
getItem(std::string name) const274 const TStringTable::Item *TStringTableImp::getItem(std::string name) const {
275   std::map<std::string, Item>::const_iterator it;
276   it = m_table.find(name);
277   if (it == m_table.end())
278     return 0;
279   else
280     return &(it->second);
281 }
282 
283 //-------------------------------------------------------------------
284 
285 }  // namespace
286 
287 //-------------------------------------------------------------------
288 
TStringTable()289 TStringTable::TStringTable() {}
290 
291 //-------------------------------------------------------------------
292 
~TStringTable()293 TStringTable::~TStringTable() {}
294 
295 //-------------------------------------------------------------------
296 
translate(std::string name)297 std::wstring TStringTable::translate(std::string name) {
298   const TStringTable::Item *item = instance()->getItem(name);
299   if (item)
300     return item->m_name;
301   else
302     return ::to_wstring(name);
303 }
304 
305 //-------------------------------------------------------------------
306 
instance()307 const TStringTable *TStringTable::instance() {
308   // may hurt MacOsX
309   static TStringTableImp *instance = 0;
310   if (!instance) instance          = new TStringTableImp;
311 
312   instance->init();
313 
314   return instance;
315 }
316