1 // Common/Lang.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "Lang.h"
6 #include "StringToInt.h"
7 #include "UTFConvert.h"
8 
9 #include "../Windows/FileIO.h"
10 
Clear()11 void CLang::Clear() throw()
12 {
13   _ids.Clear();
14   _offsets.Clear();
15   delete []_text;
16   _text = 0;
17 }
18 
19 static const char * const kLangSignature = ";!@Lang2@!UTF-8!";
20 
OpenFromString(const AString & s2)21 bool CLang::OpenFromString(const AString &s2)
22 {
23   UString s;
24   if (!ConvertUTF8ToUnicode(s2, s))
25     return false;
26   unsigned i = 0;
27   if (s.IsEmpty())
28     return false;
29   if (s[0] == 0xFEFF)
30     i++;
31 
32   for (const char *p = kLangSignature;; i++)
33   {
34     Byte c = (Byte)(*p++);
35     if (c == 0)
36       break;
37     if (s[i] != c)
38       return false;
39   }
40 
41   _text = new wchar_t[s.Len() - i + 1];
42   wchar_t *text = _text;
43 
44   Int32 id = -100;
45   UInt32 pos = 0;
46 
47   while (i < s.Len())
48   {
49     unsigned start = pos;
50     do
51     {
52       wchar_t c = s[i++];
53       if (c == '\n')
54         break;
55       if (c == '\\')
56       {
57         if (i == s.Len())
58           return false;
59         c = s[i++];
60         switch (c)
61         {
62           case '\n': return false;
63           case 'n': c = '\n'; break;
64           case 't': c = '\t'; break;
65           case '\\': c = '\\'; break;
66           default: text[pos++] = L'\\'; break;
67         }
68       }
69       text[pos++] = c;
70     }
71     while (i < s.Len());
72 
73     {
74       unsigned j = start;
75       for (; j < pos; j++)
76         if (text[j] != ' ')
77           break;
78       if (j == pos)
79       {
80         id++;
81         continue;
82       }
83     }
84     if (text[start] == ';')
85     {
86       pos = start;
87       id++;
88       continue;
89     }
90 
91     text[pos++] = 0;
92     const wchar_t *end;
93     UInt32 id32 = ConvertStringToUInt32(text + start, &end);
94     if (*end == 0)
95     {
96       if (id32 > ((UInt32)1 << 30) || (Int32)id32 < id)
97         return false;
98       id = (Int32)id32;
99       pos = start;
100       continue;
101     }
102 
103     if (id < 0)
104       return false;
105     _ids.Add((UInt32)id++);
106     _offsets.Add(start);
107   }
108 
109   return true;
110 }
111 
Open(CFSTR fileName,const char * id)112 bool CLang::Open(CFSTR fileName, const char *id)
113 {
114   Clear();
115   NWindows::NFile::NIO::CInFile file;
116   if (!file.Open(fileName))
117     return false;
118   UInt64 length;
119   if (!file.GetLength(length))
120     return false;
121   if (length > (1 << 20))
122     return false;
123 
124   AString s;
125   const unsigned len = (unsigned)length;
126   char *p = s.GetBuf(len);
127   size_t processed;
128   if (!file.ReadFull(p, len, processed))
129     return false;
130   file.Close();
131   if (len != processed)
132     return false;
133 
134   char *p2 = p;
135   for (unsigned i = 0; i < len; i++)
136   {
137     char c = p[i];
138     if (c == 0)
139       break;
140     if (c != 0x0D)
141       *p2++ = c;
142   }
143   *p2 = 0;
144   s.ReleaseBuf_SetLen((unsigned)(p2 - p));
145 
146   if (OpenFromString(s))
147   {
148     const wchar_t *name = Get(0);
149     if (name && StringsAreEqual_Ascii(name, id))
150       return true;
151   }
152 
153   Clear();
154   return false;
155 }
156 
Get(UInt32 id) const157 const wchar_t *CLang::Get(UInt32 id) const throw()
158 {
159   int index = _ids.FindInSorted(id);
160   if (index < 0)
161     return NULL;
162   return _text + (size_t)_offsets[(unsigned)index];
163 }
164