| // Common/Lang.cpp |
| |
| #include "StdAfx.h" |
| |
| #include "Lang.h" |
| #include "StringToInt.h" |
| #include "UTFConvert.h" |
| |
| #include "../Windows/FileIO.h" |
| |
| void CLang::Clear() throw() |
| { |
| _ids.Clear(); |
| _offsets.Clear(); |
| Comments.Clear(); |
| delete []_text; |
| _text = NULL; |
| } |
| |
| static const char * const kLangSignature = ";!@Lang2@!UTF-8!\n"; |
| |
| bool CLang::OpenFromString(const AString &s2) |
| { |
| UString su; |
| if (!ConvertUTF8ToUnicode(s2, su)) |
| return false; |
| if (su.IsEmpty()) |
| return false; |
| const wchar_t *s = su; |
| const wchar_t *sLim = s + su.Len(); |
| if (*s == 0xFEFF) |
| s++; |
| for (const char *p = kLangSignature;; s++) |
| { |
| const Byte c = (Byte)(*p++); |
| if (c == 0) |
| break; |
| if (*s != c) |
| return false; |
| } |
| |
| wchar_t *text = new wchar_t[(size_t)(sLim - s) + 1]; |
| _text = text; |
| |
| UString comment; |
| Int32 id = -1024; |
| unsigned pos = 0; |
| |
| while (s != sLim) |
| { |
| const unsigned start = pos; |
| do |
| { |
| wchar_t c = *s++; |
| if (c == '\n') |
| break; |
| if (c == '\\') |
| { |
| if (s == sLim) |
| return false; |
| c = *s++; |
| switch (c) |
| { |
| case '\n': return false; |
| case 'n': c = '\n'; break; |
| case 't': c = '\t'; break; |
| case '\\': /* c = '\\'; */ break; |
| default: text[pos++] = L'\\'; break; |
| } |
| } |
| text[pos++] = c; |
| } |
| while (s != sLim); |
| |
| { |
| unsigned j = start; |
| for (; j < pos; j++) |
| if (text[j] != ' ' && text[j] != '\t') |
| break; |
| if (j == pos) |
| { |
| id++; |
| pos = start; |
| continue; |
| } |
| } |
| |
| // start != pos |
| text[pos++] = 0; |
| |
| if (text[start] == ';') |
| { |
| comment = text + start; |
| comment.TrimRight(); |
| if (comment.Len() != 1) |
| Comments.Add(comment); |
| id++; |
| pos = start; |
| continue; |
| } |
| |
| const wchar_t *end; |
| const UInt32 id32 = ConvertStringToUInt32(text + start, &end); |
| if (*end == 0) |
| { |
| if (id32 > ((UInt32)1 << 30) || (Int32)id32 < id) |
| return false; |
| id = (Int32)id32; |
| pos = start; |
| continue; |
| } |
| |
| if (id < 0) |
| return false; |
| _ids.Add((UInt32)id++); |
| _offsets.Add(start); |
| } |
| |
| return true; |
| } |
| |
| bool CLang::Open(CFSTR fileName, const char *id) |
| { |
| Clear(); |
| NWindows::NFile::NIO::CInFile file; |
| if (!file.Open(fileName)) |
| return false; |
| UInt64 length; |
| if (!file.GetLength(length)) |
| return false; |
| if (length > (1 << 20)) |
| return false; |
| |
| AString s; |
| const unsigned len = (unsigned)length; |
| char *p = s.GetBuf(len); |
| size_t processed; |
| if (!file.ReadFull(p, len, processed)) |
| return false; |
| file.Close(); |
| if (len != processed) |
| return false; |
| |
| char *p2 = p; |
| for (unsigned i = 0; i < len; i++) |
| { |
| const char c = p[i]; |
| if (c == 0) |
| break; |
| if (c != 0x0D) |
| *p2++ = c; |
| } |
| *p2 = 0; |
| s.ReleaseBuf_SetLen((unsigned)(p2 - p)); |
| |
| if (OpenFromString(s)) |
| { |
| const wchar_t *name = Get(0); |
| if (name && StringsAreEqual_Ascii(name, id)) |
| return true; |
| } |
| |
| Clear(); |
| return false; |
| } |
| |
| const wchar_t *CLang::Get(UInt32 id) const throw() |
| { |
| const int index = _ids.FindInSorted(id); |
| if (index < 0) |
| return NULL; |
| return _text + (size_t)_offsets[(unsigned)index]; |
| } |