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