-
Notifications
You must be signed in to change notification settings - Fork 43
/
filestr.cpp
163 lines (139 loc) · 3.99 KB
/
filestr.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "rar.hpp"
bool ReadTextFile(
const std::wstring &Name,
StringList *List,
bool Config,
bool AbortOnError,
RAR_CHARSET SrcCharset,
bool Unquote,
bool SkipComments,
bool ExpandEnvStr)
{
std::wstring FileName;
if (Config)
GetConfigName(Name,FileName,true,false);
else
FileName=Name;
File SrcFile;
if (!FileName.empty())
{
bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,0);
if (!OpenCode)
{
if (AbortOnError)
ErrHandler.Exit(RARX_OPEN);
return false;
}
}
else
SrcFile.SetHandleType(FILE_HANDLESTD);
size_t DataSize=0,ReadSize;
const int ReadBlock=4096;
std::vector<byte> Data(ReadBlock);
while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0)
{
DataSize+=ReadSize;
Data.resize(DataSize+ReadBlock); // Always have ReadBlock available for next data.
}
// Set to really read size, so we can zero terminate it correctly.
Data.resize(DataSize);
int LittleEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0;
int BigEndian=DataSize>=2 && Data[0]==254 && Data[1]==255 ? 1:0;
bool Utf8=DataSize>=3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf;
if (SrcCharset==RCH_DEFAULT)
SrcCharset=DetectTextEncoding(Data.data(),DataSize);
std::vector<wchar> DataW(ReadBlock);
if (SrcCharset==RCH_DEFAULT || SrcCharset==RCH_OEM || SrcCharset==RCH_ANSI)
{
Data.push_back(0); // Zero terminate.
#if defined(_WIN_ALL)
if (SrcCharset==RCH_OEM)
OemToCharA((char *)Data.data(),(char *)Data.data());
#endif
DataW.resize(Data.size());
CharToWide((char *)Data.data(),DataW.data(),DataW.size());
}
if (SrcCharset==RCH_UNICODE)
{
size_t Start=2; // Skip byte order mark.
if (!LittleEndian && !BigEndian) // No byte order mask.
{
Start=0;
LittleEndian=1;
}
DataW.resize(Data.size()/2+1);
size_t End=Data.size() & ~1; // We need even bytes number for UTF-16.
for (size_t I=Start;I<End;I+=2)
DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LittleEndian]*256;
DataW[(End-Start)/2]=0;
}
if (SrcCharset==RCH_UTF8)
{
Data.push_back(0); // Zero terminate data.
DataW.resize(Data.size());
UtfToWide((const char *)(Data.data()+(Utf8 ? 3:0)),DataW.data(),DataW.size());
}
wchar *CurStr=DataW.data();
while (*CurStr!=0)
{
wchar *NextStr=CurStr,*CmtPtr=NULL;
while (*NextStr!='\r' && *NextStr!='\n' && *NextStr!=0)
{
if (SkipComments && NextStr[0]=='/' && NextStr[1]=='/')
{
*NextStr=0;
CmtPtr=NextStr;
}
NextStr++;
}
bool Done=*NextStr==0;
*NextStr=0;
for (wchar *SpacePtr=(CmtPtr!=NULL ? CmtPtr:NextStr)-1;SpacePtr>=CurStr;SpacePtr--)
{
if (*SpacePtr!=' ' && *SpacePtr!='\t')
break;
*SpacePtr=0;
}
if (Unquote && *CurStr=='\"')
{
size_t Length=wcslen(CurStr);
if (CurStr[Length-1]=='\"')
{
CurStr[Length-1]=0;
CurStr++;
}
}
bool Expanded=false;
#if defined(_WIN_ALL)
if (ExpandEnvStr && *CurStr=='%') // Expand environment variables in Windows.
{
std::wstring ExpName=CurStr;
ExpandEnvironmentStr(ExpName);
if (!ExpName.empty())
List->AddString(ExpName);
Expanded=true;
}
#endif
if (!Expanded && *CurStr!=0)
List->AddString(CurStr);
if (Done)
break;
CurStr=NextStr+1;
while (*CurStr=='\r' || *CurStr=='\n')
CurStr++;
}
return true;
}
RAR_CHARSET DetectTextEncoding(const byte *Data,size_t DataSize)
{
if (DataSize>3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf &&
IsTextUtf8(Data+3,DataSize-3))
return RCH_UTF8;
bool LittleEndian=DataSize>2 && Data[0]==255 && Data[1]==254;
bool BigEndian=DataSize>2 && Data[0]==254 && Data[1]==255;
if (LittleEndian || BigEndian)
for (size_t I=LittleEndian ? 3 : 2;I<DataSize;I+=2)
if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n')
return RCH_UNICODE; // High byte in UTF-16 char is found.
return RCH_DEFAULT;
}