diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/Common | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.gz 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.bz2 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.zip |
'21.07'21.07
Diffstat (limited to 'CPP/Common')
65 files changed, 11050 insertions, 0 deletions
diff --git a/CPP/Common/AutoPtr.h b/CPP/Common/AutoPtr.h new file mode 100644 index 0000000..006d315 --- /dev/null +++ b/CPP/Common/AutoPtr.h | |||
@@ -0,0 +1,35 @@ | |||
1 | // Common/AutoPtr.h | ||
2 | |||
3 | #ifndef __COMMON_AUTOPTR_H | ||
4 | #define __COMMON_AUTOPTR_H | ||
5 | |||
6 | template<class T> class CMyAutoPtr | ||
7 | { | ||
8 | T *_p; | ||
9 | public: | ||
10 | CMyAutoPtr(T *p = 0) : _p(p) {} | ||
11 | CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {} | ||
12 | CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p) | ||
13 | { | ||
14 | reset(p.release()); | ||
15 | return (*this); | ||
16 | } | ||
17 | ~CMyAutoPtr() { delete _p; } | ||
18 | T& operator*() const { return *_p; } | ||
19 | // T* operator->() const { return (&**this); } | ||
20 | T* get() const { return _p; } | ||
21 | T* release() | ||
22 | { | ||
23 | T *tmp = _p; | ||
24 | _p = 0; | ||
25 | return tmp; | ||
26 | } | ||
27 | void reset(T* p = 0) | ||
28 | { | ||
29 | if (p != _p) | ||
30 | delete _p; | ||
31 | _p = p; | ||
32 | } | ||
33 | }; | ||
34 | |||
35 | #endif | ||
diff --git a/CPP/Common/CRC.cpp b/CPP/Common/CRC.cpp new file mode 100644 index 0000000..c6b7d5e --- /dev/null +++ b/CPP/Common/CRC.cpp | |||
@@ -0,0 +1,7 @@ | |||
1 | // Common/CRC.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/7zCrc.h" | ||
6 | |||
7 | static struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit; | ||
diff --git a/CPP/Common/C_FileIO.cpp b/CPP/Common/C_FileIO.cpp new file mode 100644 index 0000000..4bd3fad --- /dev/null +++ b/CPP/Common/C_FileIO.cpp | |||
@@ -0,0 +1,3 @@ | |||
1 | // Common/C_FileIO.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
diff --git a/CPP/Common/C_FileIO.h b/CPP/Common/C_FileIO.h new file mode 100644 index 0000000..6818558 --- /dev/null +++ b/CPP/Common/C_FileIO.h | |||
@@ -0,0 +1,6 @@ | |||
1 | // Common/C_FileIO.h | ||
2 | |||
3 | #ifndef __COMMON_C_FILEIO_H | ||
4 | #define __COMMON_C_FILEIO_H | ||
5 | |||
6 | #endif | ||
diff --git a/CPP/Common/CksumReg.cpp b/CPP/Common/CksumReg.cpp new file mode 100644 index 0000000..29d9f82 --- /dev/null +++ b/CPP/Common/CksumReg.cpp | |||
@@ -0,0 +1,60 @@ | |||
1 | // CksumReg.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/CpuArch.h" | ||
6 | |||
7 | #include "../Common/MyCom.h" | ||
8 | |||
9 | #include "../7zip/Common/RegisterCodec.h" | ||
10 | |||
11 | #include "../7zip/Compress/BZip2Crc.h" | ||
12 | |||
13 | class CCksumHasher: | ||
14 | public IHasher, | ||
15 | public CMyUnknownImp | ||
16 | { | ||
17 | CBZip2Crc _crc; | ||
18 | UInt64 _size; | ||
19 | Byte mtDummy[1 << 7]; | ||
20 | |||
21 | public: | ||
22 | CCksumHasher() | ||
23 | { | ||
24 | _crc.Init(0); | ||
25 | _size = 0; | ||
26 | } | ||
27 | |||
28 | MY_UNKNOWN_IMP1(IHasher) | ||
29 | INTERFACE_IHasher(;) | ||
30 | }; | ||
31 | |||
32 | STDMETHODIMP_(void) CCksumHasher::Init() throw() | ||
33 | { | ||
34 | _crc.Init(0); | ||
35 | _size = 0; | ||
36 | } | ||
37 | |||
38 | STDMETHODIMP_(void) CCksumHasher::Update(const void *data, UInt32 size) throw() | ||
39 | { | ||
40 | _size += size; | ||
41 | CBZip2Crc crc = _crc; | ||
42 | for (UInt32 i = 0; i < size; i++) | ||
43 | crc.UpdateByte(((const Byte *)data)[i]); | ||
44 | _crc = crc; | ||
45 | } | ||
46 | |||
47 | STDMETHODIMP_(void) CCksumHasher::Final(Byte *digest) throw() | ||
48 | { | ||
49 | UInt64 size = _size; | ||
50 | CBZip2Crc crc = _crc; | ||
51 | while (size) | ||
52 | { | ||
53 | crc.UpdateByte((Byte)size); | ||
54 | size >>= 8; | ||
55 | } | ||
56 | const UInt32 val = crc.GetDigest(); | ||
57 | SetUi32(digest, val); | ||
58 | } | ||
59 | |||
60 | REGISTER_HASHER(CCksumHasher, 0x203, "CKSUM", 4) | ||
diff --git a/CPP/Common/ComTry.h b/CPP/Common/ComTry.h new file mode 100644 index 0000000..297c407 --- /dev/null +++ b/CPP/Common/ComTry.h | |||
@@ -0,0 +1,21 @@ | |||
1 | // ComTry.h | ||
2 | |||
3 | #ifndef __COM_TRY_H | ||
4 | #define __COM_TRY_H | ||
5 | |||
6 | #include "MyWindows.h" | ||
7 | // #include "Exception.h" | ||
8 | // #include "NewHandler.h" | ||
9 | |||
10 | #define COM_TRY_BEGIN try { | ||
11 | #define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; } | ||
12 | |||
13 | /* | ||
14 | #define COM_TRY_END } \ | ||
15 | catch(const CNewException &) { return E_OUTOFMEMORY; } \ | ||
16 | catch(...) { return HRESULT_FROM_WIN32(ERROR_NOACCESS); } \ | ||
17 | */ | ||
18 | // catch(const CSystemException &e) { return e.ErrorCode; } | ||
19 | // catch(...) { return E_FAIL; } | ||
20 | |||
21 | #endif | ||
diff --git a/CPP/Common/CommandLineParser.cpp b/CPP/Common/CommandLineParser.cpp new file mode 100644 index 0000000..465e0fd --- /dev/null +++ b/CPP/Common/CommandLineParser.cpp | |||
@@ -0,0 +1,197 @@ | |||
1 | // CommandLineParser.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "CommandLineParser.h" | ||
6 | |||
7 | namespace NCommandLineParser { | ||
8 | |||
9 | bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2) | ||
10 | { | ||
11 | dest1.Empty(); | ||
12 | dest2.Empty(); | ||
13 | bool quoteMode = false; | ||
14 | unsigned i; | ||
15 | for (i = 0; i < src.Len(); i++) | ||
16 | { | ||
17 | wchar_t c = src[i]; | ||
18 | if ((c == L' ' || c == L'\t') && !quoteMode) | ||
19 | { | ||
20 | dest2 = src.Ptr(i + 1); | ||
21 | return i != 0; | ||
22 | } | ||
23 | if (c == L'\"') | ||
24 | quoteMode = !quoteMode; | ||
25 | else | ||
26 | dest1 += c; | ||
27 | } | ||
28 | return i != 0; | ||
29 | } | ||
30 | |||
31 | void SplitCommandLine(const UString &s, UStringVector &parts) | ||
32 | { | ||
33 | UString sTemp (s); | ||
34 | sTemp.Trim(); | ||
35 | parts.Clear(); | ||
36 | for (;;) | ||
37 | { | ||
38 | UString s1, s2; | ||
39 | if (SplitCommandLine(sTemp, s1, s2)) | ||
40 | parts.Add(s1); | ||
41 | if (s2.IsEmpty()) | ||
42 | break; | ||
43 | sTemp = s2; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | |||
48 | static const char * const kStopSwitchParsing = "--"; | ||
49 | |||
50 | static bool inline IsItSwitchChar(wchar_t c) | ||
51 | { | ||
52 | return (c == '-'); | ||
53 | } | ||
54 | |||
55 | CParser::CParser(): | ||
56 | _switches(NULL), | ||
57 | StopSwitchIndex(-1) | ||
58 | { | ||
59 | } | ||
60 | |||
61 | CParser::~CParser() | ||
62 | { | ||
63 | delete []_switches; | ||
64 | } | ||
65 | |||
66 | |||
67 | // if (s) contains switch then function updates switch structures | ||
68 | // out: true, if (s) is a switch | ||
69 | bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches) | ||
70 | { | ||
71 | if (s.IsEmpty() || !IsItSwitchChar(s[0])) | ||
72 | return false; | ||
73 | |||
74 | unsigned pos = 1; | ||
75 | unsigned switchIndex = 0; | ||
76 | int maxLen = -1; | ||
77 | |||
78 | for (unsigned i = 0; i < numSwitches; i++) | ||
79 | { | ||
80 | const char * const key = switchForms[i].Key; | ||
81 | unsigned switchLen = MyStringLen(key); | ||
82 | if ((int)switchLen <= maxLen || pos + switchLen > s.Len()) | ||
83 | continue; | ||
84 | if (IsString1PrefixedByString2_NoCase_Ascii((const wchar_t *)s + pos, key)) | ||
85 | { | ||
86 | switchIndex = i; | ||
87 | maxLen = (int)switchLen; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | if (maxLen < 0) | ||
92 | { | ||
93 | ErrorMessage = "Unknown switch:"; | ||
94 | return false; | ||
95 | } | ||
96 | |||
97 | pos += (unsigned)maxLen; | ||
98 | |||
99 | CSwitchResult &sw = _switches[switchIndex]; | ||
100 | const CSwitchForm &form = switchForms[switchIndex]; | ||
101 | |||
102 | if (!form.Multi && sw.ThereIs) | ||
103 | { | ||
104 | ErrorMessage = "Multiple instances for switch:"; | ||
105 | return false; | ||
106 | } | ||
107 | |||
108 | sw.ThereIs = true; | ||
109 | |||
110 | const unsigned rem = s.Len() - pos; | ||
111 | if (rem < form.MinLen) | ||
112 | { | ||
113 | ErrorMessage = "Too short switch:"; | ||
114 | return false; | ||
115 | } | ||
116 | |||
117 | sw.WithMinus = false; | ||
118 | sw.PostCharIndex = -1; | ||
119 | |||
120 | switch (form.Type) | ||
121 | { | ||
122 | case NSwitchType::kMinus: | ||
123 | if (rem == 1) | ||
124 | { | ||
125 | sw.WithMinus = (s[pos] == '-'); | ||
126 | if (sw.WithMinus) | ||
127 | return true; | ||
128 | ErrorMessage = "Incorrect switch postfix:"; | ||
129 | return false; | ||
130 | } | ||
131 | break; | ||
132 | |||
133 | case NSwitchType::kChar: | ||
134 | if (rem == 1) | ||
135 | { | ||
136 | wchar_t c = s[pos]; | ||
137 | if (c <= 0x7F) | ||
138 | { | ||
139 | sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c); | ||
140 | if (sw.PostCharIndex >= 0) | ||
141 | return true; | ||
142 | } | ||
143 | ErrorMessage = "Incorrect switch postfix:"; | ||
144 | return false; | ||
145 | } | ||
146 | break; | ||
147 | |||
148 | case NSwitchType::kString: | ||
149 | { | ||
150 | sw.PostStrings.Add(s.Ptr(pos)); | ||
151 | return true; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | if (pos != s.Len()) | ||
156 | { | ||
157 | ErrorMessage = "Too long switch:"; | ||
158 | return false; | ||
159 | } | ||
160 | return true; | ||
161 | } | ||
162 | |||
163 | |||
164 | bool CParser::ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings) | ||
165 | { | ||
166 | StopSwitchIndex = -1; | ||
167 | ErrorMessage.Empty(); | ||
168 | ErrorLine.Empty(); | ||
169 | NonSwitchStrings.Clear(); | ||
170 | delete []_switches; | ||
171 | _switches = NULL; | ||
172 | _switches = new CSwitchResult[numSwitches]; | ||
173 | |||
174 | FOR_VECTOR (i, commandStrings) | ||
175 | { | ||
176 | const UString &s = commandStrings[i]; | ||
177 | if (StopSwitchIndex < 0) | ||
178 | { | ||
179 | if (s.IsEqualTo(kStopSwitchParsing)) | ||
180 | { | ||
181 | StopSwitchIndex = (int)NonSwitchStrings.Size(); | ||
182 | continue; | ||
183 | } | ||
184 | if (!s.IsEmpty() && IsItSwitchChar(s[0])) | ||
185 | { | ||
186 | if (ParseString(s, switchForms, numSwitches)) | ||
187 | continue; | ||
188 | ErrorLine = s; | ||
189 | return false; | ||
190 | } | ||
191 | } | ||
192 | NonSwitchStrings.Add(s); | ||
193 | } | ||
194 | return true; | ||
195 | } | ||
196 | |||
197 | } | ||
diff --git a/CPP/Common/CommandLineParser.h b/CPP/Common/CommandLineParser.h new file mode 100644 index 0000000..fbd4fa5 --- /dev/null +++ b/CPP/Common/CommandLineParser.h | |||
@@ -0,0 +1,63 @@ | |||
1 | // Common/CommandLineParser.h | ||
2 | |||
3 | #ifndef __COMMON_COMMAND_LINE_PARSER_H | ||
4 | #define __COMMON_COMMAND_LINE_PARSER_H | ||
5 | |||
6 | #include "MyString.h" | ||
7 | |||
8 | namespace NCommandLineParser { | ||
9 | |||
10 | bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2); | ||
11 | void SplitCommandLine(const UString &s, UStringVector &parts); | ||
12 | |||
13 | namespace NSwitchType | ||
14 | { | ||
15 | enum EEnum | ||
16 | { | ||
17 | kSimple, | ||
18 | kMinus, | ||
19 | kString, | ||
20 | kChar | ||
21 | }; | ||
22 | } | ||
23 | |||
24 | struct CSwitchForm | ||
25 | { | ||
26 | const char *Key; | ||
27 | Byte Type; | ||
28 | bool Multi; | ||
29 | Byte MinLen; | ||
30 | // int MaxLen; | ||
31 | const char *PostCharSet; | ||
32 | }; | ||
33 | |||
34 | struct CSwitchResult | ||
35 | { | ||
36 | bool ThereIs; | ||
37 | bool WithMinus; | ||
38 | int PostCharIndex; | ||
39 | UStringVector PostStrings; | ||
40 | |||
41 | CSwitchResult(): ThereIs(false) {} | ||
42 | }; | ||
43 | |||
44 | class CParser | ||
45 | { | ||
46 | CSwitchResult *_switches; | ||
47 | |||
48 | bool ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches); | ||
49 | public: | ||
50 | UStringVector NonSwitchStrings; | ||
51 | int StopSwitchIndex; // NonSwitchStrings[StopSwitchIndex+] are after "--" | ||
52 | AString ErrorMessage; | ||
53 | UString ErrorLine; | ||
54 | |||
55 | CParser(); | ||
56 | ~CParser(); | ||
57 | bool ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings); | ||
58 | const CSwitchResult& operator[](unsigned index) const { return _switches[index]; } | ||
59 | }; | ||
60 | |||
61 | } | ||
62 | |||
63 | #endif | ||
diff --git a/CPP/Common/Common.h b/CPP/Common/Common.h new file mode 100644 index 0000000..8dac613 --- /dev/null +++ b/CPP/Common/Common.h | |||
@@ -0,0 +1,57 @@ | |||
1 | // Common.h | ||
2 | |||
3 | #ifndef __COMMON_COMMON_H | ||
4 | #define __COMMON_COMMON_H | ||
5 | |||
6 | /* | ||
7 | This file is included to all cpp files in 7-Zip. | ||
8 | Each folder contains StdAfx.h file that includes "Common.h". | ||
9 | So 7-Zip includes "Common.h" in both modes: | ||
10 | with precompiled StdAfx.h | ||
11 | and | ||
12 | without precompiled StdAfx.h | ||
13 | |||
14 | If you use 7-Zip code, you must include "Common.h" before other h files of 7-zip. | ||
15 | If you don't need some things that are used in 7-Zip, | ||
16 | you can change this h file or h files included in this file. | ||
17 | */ | ||
18 | |||
19 | // compiler pragmas to disable some warnings | ||
20 | #include "../../C/Compiler.h" | ||
21 | |||
22 | // it's <windows.h> or code that defines windows things, if it's not _WIN32 | ||
23 | #include "MyWindows.h" | ||
24 | |||
25 | // NewHandler.h and NewHandler.cpp redefine operator new() to throw exceptions, if compiled with old MSVC compilers | ||
26 | #include "NewHandler.h" | ||
27 | |||
28 | |||
29 | |||
30 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) | ||
31 | |||
32 | |||
33 | /* There is BUG in MSVC 6.0 compiler for operator new[]: | ||
34 | It doesn't check overflow, when it calculates size in bytes for allocated array. | ||
35 | So we can use MY_ARRAY_NEW macro instead of new[] operator. */ | ||
36 | |||
37 | #if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64) | ||
38 | #define MY_ARRAY_NEW(p, T, size) p = new T[(size > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : size]; | ||
39 | #else | ||
40 | #define MY_ARRAY_NEW(p, T, size) p = new T[size]; | ||
41 | #endif | ||
42 | |||
43 | #if (defined(__GNUC__) && (__GNUC__ >= 8)) | ||
44 | #define MY_ATTR_NORETURN __attribute__((noreturn)) | ||
45 | #elif (defined(__clang__) && (__clang_major__ >= 3)) | ||
46 | #if __has_feature(cxx_attributes) | ||
47 | #define MY_ATTR_NORETURN [[noreturn]] | ||
48 | #else | ||
49 | #define MY_ATTR_NORETURN __attribute__ ((noreturn)) | ||
50 | #endif | ||
51 | #elif (defined(_MSC_VER) && (_MSC_VER >= 1900)) | ||
52 | #define MY_ATTR_NORETURN [[noreturn]] | ||
53 | #else | ||
54 | #define MY_ATTR_NORETURN | ||
55 | #endif | ||
56 | |||
57 | #endif | ||
diff --git a/CPP/Common/CrcReg.cpp b/CPP/Common/CrcReg.cpp new file mode 100644 index 0000000..fdbba77 --- /dev/null +++ b/CPP/Common/CrcReg.cpp | |||
@@ -0,0 +1,95 @@ | |||
1 | // CrcReg.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/7zCrc.h" | ||
6 | #include "../../C/CpuArch.h" | ||
7 | |||
8 | #include "../Common/MyCom.h" | ||
9 | |||
10 | #include "../7zip/Common/RegisterCodec.h" | ||
11 | |||
12 | EXTERN_C_BEGIN | ||
13 | |||
14 | typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
15 | |||
16 | UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table); | ||
17 | |||
18 | extern CRC_FUNC g_CrcUpdate; | ||
19 | extern CRC_FUNC g_CrcUpdateT4; | ||
20 | extern CRC_FUNC g_CrcUpdateT8; | ||
21 | extern CRC_FUNC g_CrcUpdateT0_32; | ||
22 | extern CRC_FUNC g_CrcUpdateT0_64; | ||
23 | |||
24 | EXTERN_C_END | ||
25 | |||
26 | class CCrcHasher: | ||
27 | public IHasher, | ||
28 | public ICompressSetCoderProperties, | ||
29 | public CMyUnknownImp | ||
30 | { | ||
31 | UInt32 _crc; | ||
32 | CRC_FUNC _updateFunc; | ||
33 | Byte mtDummy[1 << 7]; | ||
34 | |||
35 | bool SetFunctions(UInt32 tSize); | ||
36 | public: | ||
37 | CCrcHasher(): _crc(CRC_INIT_VAL) { SetFunctions(0); } | ||
38 | |||
39 | MY_UNKNOWN_IMP2(IHasher, ICompressSetCoderProperties) | ||
40 | INTERFACE_IHasher(;) | ||
41 | STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); | ||
42 | }; | ||
43 | |||
44 | bool CCrcHasher::SetFunctions(UInt32 tSize) | ||
45 | { | ||
46 | CRC_FUNC f = NULL; | ||
47 | if (tSize == 0) f = g_CrcUpdate; | ||
48 | else if (tSize == 1) f = CrcUpdateT1; | ||
49 | else if (tSize == 4) f = g_CrcUpdateT4; | ||
50 | else if (tSize == 8) f = g_CrcUpdateT8; | ||
51 | else if (tSize == 32) f = g_CrcUpdateT0_32; | ||
52 | else if (tSize == 64) f = g_CrcUpdateT0_64; | ||
53 | |||
54 | if (!f) | ||
55 | { | ||
56 | _updateFunc = g_CrcUpdate; | ||
57 | return false; | ||
58 | } | ||
59 | _updateFunc = f; | ||
60 | return true; | ||
61 | } | ||
62 | |||
63 | STDMETHODIMP CCrcHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) | ||
64 | { | ||
65 | for (UInt32 i = 0; i < numProps; i++) | ||
66 | { | ||
67 | const PROPVARIANT &prop = coderProps[i]; | ||
68 | if (propIDs[i] == NCoderPropID::kDefaultProp) | ||
69 | { | ||
70 | if (prop.vt != VT_UI4) | ||
71 | return E_INVALIDARG; | ||
72 | if (!SetFunctions(prop.ulVal)) | ||
73 | return E_NOTIMPL; | ||
74 | } | ||
75 | } | ||
76 | return S_OK; | ||
77 | } | ||
78 | |||
79 | STDMETHODIMP_(void) CCrcHasher::Init() throw() | ||
80 | { | ||
81 | _crc = CRC_INIT_VAL; | ||
82 | } | ||
83 | |||
84 | STDMETHODIMP_(void) CCrcHasher::Update(const void *data, UInt32 size) throw() | ||
85 | { | ||
86 | _crc = _updateFunc(_crc, data, size, g_CrcTable); | ||
87 | } | ||
88 | |||
89 | STDMETHODIMP_(void) CCrcHasher::Final(Byte *digest) throw() | ||
90 | { | ||
91 | UInt32 val = CRC_GET_DIGEST(_crc); | ||
92 | SetUi32(digest, val); | ||
93 | } | ||
94 | |||
95 | REGISTER_HASHER(CCrcHasher, 0x1, "CRC32", 4) | ||
diff --git a/CPP/Common/Defs.h b/CPP/Common/Defs.h new file mode 100644 index 0000000..9adb88c --- /dev/null +++ b/CPP/Common/Defs.h | |||
@@ -0,0 +1,16 @@ | |||
1 | // Common/Defs.h | ||
2 | |||
3 | #ifndef __COMMON_DEFS_H | ||
4 | #define __COMMON_DEFS_H | ||
5 | |||
6 | template <class T> inline T MyMin(T a, T b) { return a < b ? a : b; } | ||
7 | template <class T> inline T MyMax(T a, T b) { return a > b ? a : b; } | ||
8 | |||
9 | template <class T> inline int MyCompare(T a, T b) | ||
10 | { return a == b ? 0 : (a < b ? -1 : 1); } | ||
11 | |||
12 | inline int BoolToInt(bool v) { return (v ? 1 : 0); } | ||
13 | inline unsigned BoolToUInt(bool v) { return (v ? (unsigned)1 : (unsigned)0); } | ||
14 | inline bool IntToBool(int v) { return (v != 0); } | ||
15 | |||
16 | #endif | ||
diff --git a/CPP/Common/DynLimBuf.cpp b/CPP/Common/DynLimBuf.cpp new file mode 100644 index 0000000..7914104 --- /dev/null +++ b/CPP/Common/DynLimBuf.cpp | |||
@@ -0,0 +1,93 @@ | |||
1 | // Common/DynLimBuf.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "DynLimBuf.h" | ||
6 | #include "MyString.h" | ||
7 | |||
8 | CDynLimBuf::CDynLimBuf(size_t limit) throw() | ||
9 | { | ||
10 | _chars = 0; | ||
11 | _pos = 0; | ||
12 | _size = 0; | ||
13 | _sizeLimit = limit; | ||
14 | _error = true; | ||
15 | unsigned size = 1 << 4; | ||
16 | if (size > limit) | ||
17 | size = (unsigned)limit; | ||
18 | _chars = (Byte *)MyAlloc(size); | ||
19 | if (_chars) | ||
20 | { | ||
21 | _size = size; | ||
22 | _error = false; | ||
23 | } | ||
24 | } | ||
25 | |||
26 | CDynLimBuf & CDynLimBuf::operator+=(char c) throw() | ||
27 | { | ||
28 | if (_error) | ||
29 | return *this; | ||
30 | if (_size == _pos) | ||
31 | { | ||
32 | size_t n = _sizeLimit - _size; | ||
33 | if (n == 0) | ||
34 | { | ||
35 | _error = true; | ||
36 | return *this; | ||
37 | } | ||
38 | if (n > _size) | ||
39 | n = _size; | ||
40 | |||
41 | n += _pos; | ||
42 | |||
43 | Byte *newBuf = (Byte *)MyAlloc(n); | ||
44 | if (!newBuf) | ||
45 | { | ||
46 | _error = true; | ||
47 | return *this; | ||
48 | } | ||
49 | memcpy(newBuf, _chars, _pos); | ||
50 | MyFree(_chars); | ||
51 | _chars = newBuf; | ||
52 | _size = n; | ||
53 | } | ||
54 | _chars[_pos++] = (Byte)c; | ||
55 | return *this; | ||
56 | } | ||
57 | |||
58 | CDynLimBuf &CDynLimBuf::operator+=(const char *s) throw() | ||
59 | { | ||
60 | if (_error) | ||
61 | return *this; | ||
62 | unsigned len = MyStringLen(s); | ||
63 | size_t rem = _sizeLimit - _pos; | ||
64 | if (rem < len) | ||
65 | { | ||
66 | len = (unsigned)rem; | ||
67 | _error = true; | ||
68 | } | ||
69 | if (_size - _pos < len) | ||
70 | { | ||
71 | size_t n = _pos + len; | ||
72 | if (n - _size < _size) | ||
73 | { | ||
74 | n = _sizeLimit; | ||
75 | if (n - _size > _size) | ||
76 | n = _size * 2; | ||
77 | } | ||
78 | |||
79 | Byte *newBuf = (Byte *)MyAlloc(n); | ||
80 | if (!newBuf) | ||
81 | { | ||
82 | _error = true; | ||
83 | return *this; | ||
84 | } | ||
85 | memcpy(newBuf, _chars, _pos); | ||
86 | MyFree(_chars); | ||
87 | _chars = newBuf; | ||
88 | _size = n; | ||
89 | } | ||
90 | memcpy(_chars + _pos, s, len); | ||
91 | _pos += len; | ||
92 | return *this; | ||
93 | } | ||
diff --git a/CPP/Common/DynLimBuf.h b/CPP/Common/DynLimBuf.h new file mode 100644 index 0000000..e80a7e7 --- /dev/null +++ b/CPP/Common/DynLimBuf.h | |||
@@ -0,0 +1,41 @@ | |||
1 | // Common/DynLimBuf.h | ||
2 | |||
3 | #ifndef __COMMON_DYN_LIM_BUF_H | ||
4 | #define __COMMON_DYN_LIM_BUF_H | ||
5 | |||
6 | #include <string.h> | ||
7 | |||
8 | #include "../../C/Alloc.h" | ||
9 | |||
10 | #include "MyString.h" | ||
11 | |||
12 | class CDynLimBuf | ||
13 | { | ||
14 | Byte *_chars; | ||
15 | size_t _pos; | ||
16 | size_t _size; | ||
17 | size_t _sizeLimit; | ||
18 | bool _error; | ||
19 | |||
20 | CDynLimBuf(const CDynLimBuf &s); | ||
21 | |||
22 | // ---------- forbidden functions ---------- | ||
23 | CDynLimBuf &operator+=(wchar_t c); | ||
24 | |||
25 | public: | ||
26 | CDynLimBuf(size_t limit) throw(); | ||
27 | ~CDynLimBuf() { MyFree(_chars); } | ||
28 | |||
29 | size_t Len() const { return _pos; } | ||
30 | bool IsError() const { return _error; } | ||
31 | void Empty() { _pos = 0; _error = false; } | ||
32 | |||
33 | operator const Byte *() const { return _chars; } | ||
34 | // const char *Ptr() const { return _chars; } | ||
35 | |||
36 | CDynLimBuf &operator+=(char c) throw(); | ||
37 | CDynLimBuf &operator+=(const char *s) throw(); | ||
38 | }; | ||
39 | |||
40 | |||
41 | #endif | ||
diff --git a/CPP/Common/DynamicBuffer.h b/CPP/Common/DynamicBuffer.h new file mode 100644 index 0000000..f6f6b15 --- /dev/null +++ b/CPP/Common/DynamicBuffer.h | |||
@@ -0,0 +1,64 @@ | |||
1 | // Common/DynamicBuffer.h | ||
2 | |||
3 | #ifndef __COMMON_DYNAMIC_BUFFER_H | ||
4 | #define __COMMON_DYNAMIC_BUFFER_H | ||
5 | |||
6 | template <class T> class CDynamicBuffer | ||
7 | { | ||
8 | T *_items; | ||
9 | size_t _size; | ||
10 | size_t _pos; | ||
11 | |||
12 | CDynamicBuffer(const CDynamicBuffer &buffer); | ||
13 | void operator=(const CDynamicBuffer &buffer); | ||
14 | |||
15 | void Grow(size_t size) | ||
16 | { | ||
17 | size_t delta = _size >= 64 ? _size : 64; | ||
18 | if (delta < size) | ||
19 | delta = size; | ||
20 | size_t newCap = _size + delta; | ||
21 | if (newCap < delta) | ||
22 | { | ||
23 | newCap = _size + size; | ||
24 | if (newCap < size) | ||
25 | throw 20120116; | ||
26 | } | ||
27 | |||
28 | T *newBuffer = new T[newCap]; | ||
29 | if (_pos != 0) | ||
30 | memcpy(newBuffer, _items, _pos * sizeof(T)); | ||
31 | delete []_items; | ||
32 | _items = newBuffer; | ||
33 | _size = newCap; | ||
34 | } | ||
35 | |||
36 | public: | ||
37 | CDynamicBuffer(): _items(0), _size(0), _pos(0) {} | ||
38 | // operator T *() { return _items; } | ||
39 | operator const T *() const { return _items; } | ||
40 | ~CDynamicBuffer() { delete []_items; } | ||
41 | |||
42 | T *GetCurPtrAndGrow(size_t addSize) | ||
43 | { | ||
44 | size_t rem = _size - _pos; | ||
45 | if (rem < addSize) | ||
46 | Grow(addSize - rem); | ||
47 | T *res = _items + _pos; | ||
48 | _pos += addSize; | ||
49 | return res; | ||
50 | } | ||
51 | |||
52 | void AddData(const T *data, size_t size) | ||
53 | { | ||
54 | memcpy(GetCurPtrAndGrow(size), data, size * sizeof(T)); | ||
55 | } | ||
56 | |||
57 | size_t GetPos() const { return _pos; } | ||
58 | |||
59 | // void Empty() { _pos = 0; } | ||
60 | }; | ||
61 | |||
62 | typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer; | ||
63 | |||
64 | #endif | ||
diff --git a/CPP/Common/IntToString.cpp b/CPP/Common/IntToString.cpp new file mode 100644 index 0000000..c87643c --- /dev/null +++ b/CPP/Common/IntToString.cpp | |||
@@ -0,0 +1,192 @@ | |||
1 | // Common/IntToString.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/CpuArch.h" | ||
6 | |||
7 | #include "IntToString.h" | ||
8 | |||
9 | #define CONVERT_INT_TO_STR(charType, tempSize) \ | ||
10 | unsigned char temp[tempSize]; unsigned i = 0; \ | ||
11 | while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \ | ||
12 | *s++ = (charType)('0' + (unsigned)val); \ | ||
13 | while (i != 0) { i--; *s++ = (charType)temp[i]; } \ | ||
14 | *s = 0; \ | ||
15 | return s; | ||
16 | |||
17 | char * ConvertUInt32ToString(UInt32 val, char *s) throw() | ||
18 | { | ||
19 | CONVERT_INT_TO_STR(char, 16); | ||
20 | } | ||
21 | |||
22 | char * ConvertUInt64ToString(UInt64 val, char *s) throw() | ||
23 | { | ||
24 | if (val <= (UInt32)0xFFFFFFFF) | ||
25 | { | ||
26 | return ConvertUInt32ToString((UInt32)val, s); | ||
27 | } | ||
28 | CONVERT_INT_TO_STR(char, 24); | ||
29 | } | ||
30 | |||
31 | void ConvertUInt64ToOct(UInt64 val, char *s) throw() | ||
32 | { | ||
33 | UInt64 v = val; | ||
34 | unsigned i; | ||
35 | for (i = 1;; i++) | ||
36 | { | ||
37 | v >>= 3; | ||
38 | if (v == 0) | ||
39 | break; | ||
40 | } | ||
41 | s[i] = 0; | ||
42 | do | ||
43 | { | ||
44 | unsigned t = (unsigned)(val & 0x7); | ||
45 | val >>= 3; | ||
46 | s[--i] = (char)('0' + t); | ||
47 | } | ||
48 | while (i); | ||
49 | } | ||
50 | |||
51 | |||
52 | #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))))) | ||
53 | |||
54 | static inline char GetHexChar(unsigned t) { return GET_HEX_CHAR(t); } | ||
55 | |||
56 | |||
57 | void ConvertUInt32ToHex(UInt32 val, char *s) throw() | ||
58 | { | ||
59 | UInt32 v = val; | ||
60 | unsigned i; | ||
61 | for (i = 1;; i++) | ||
62 | { | ||
63 | v >>= 4; | ||
64 | if (v == 0) | ||
65 | break; | ||
66 | } | ||
67 | s[i] = 0; | ||
68 | do | ||
69 | { | ||
70 | unsigned t = (unsigned)(val & 0xF); | ||
71 | val >>= 4; | ||
72 | s[--i] = GET_HEX_CHAR(t); | ||
73 | } | ||
74 | while (i); | ||
75 | } | ||
76 | |||
77 | |||
78 | void ConvertUInt64ToHex(UInt64 val, char *s) throw() | ||
79 | { | ||
80 | UInt64 v = val; | ||
81 | unsigned i; | ||
82 | for (i = 1;; i++) | ||
83 | { | ||
84 | v >>= 4; | ||
85 | if (v == 0) | ||
86 | break; | ||
87 | } | ||
88 | s[i] = 0; | ||
89 | do | ||
90 | { | ||
91 | unsigned t = (unsigned)(val & 0xF); | ||
92 | val >>= 4; | ||
93 | s[--i] = GET_HEX_CHAR(t); | ||
94 | } | ||
95 | while (i); | ||
96 | } | ||
97 | |||
98 | void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw() | ||
99 | { | ||
100 | s[8] = 0; | ||
101 | for (int i = 7; i >= 0; i--) | ||
102 | { | ||
103 | unsigned t = val & 0xF; | ||
104 | val >>= 4; | ||
105 | s[i] = GET_HEX_CHAR(t);; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s) | ||
111 | { | ||
112 | s[8] = 0; | ||
113 | for (int i = 7; i >= 0; i--) | ||
114 | { | ||
115 | unsigned t = val & 0xF; | ||
116 | val >>= 4; | ||
117 | s[i] = (wchar_t)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); | ||
118 | } | ||
119 | } | ||
120 | */ | ||
121 | |||
122 | wchar_t * ConvertUInt32ToString(UInt32 val, wchar_t *s) throw() | ||
123 | { | ||
124 | CONVERT_INT_TO_STR(wchar_t, 16); | ||
125 | } | ||
126 | |||
127 | wchar_t * ConvertUInt64ToString(UInt64 val, wchar_t *s) throw() | ||
128 | { | ||
129 | if (val <= (UInt32)0xFFFFFFFF) | ||
130 | { | ||
131 | return ConvertUInt32ToString((UInt32)val, s); | ||
132 | } | ||
133 | CONVERT_INT_TO_STR(wchar_t, 24); | ||
134 | } | ||
135 | |||
136 | void ConvertInt64ToString(Int64 val, char *s) throw() | ||
137 | { | ||
138 | if (val < 0) | ||
139 | { | ||
140 | *s++ = '-'; | ||
141 | val = -val; | ||
142 | } | ||
143 | ConvertUInt64ToString((UInt64)val, s); | ||
144 | } | ||
145 | |||
146 | void ConvertInt64ToString(Int64 val, wchar_t *s) throw() | ||
147 | { | ||
148 | if (val < 0) | ||
149 | { | ||
150 | *s++ = L'-'; | ||
151 | val = -val; | ||
152 | } | ||
153 | ConvertUInt64ToString((UInt64)val, s); | ||
154 | } | ||
155 | |||
156 | |||
157 | static void ConvertByteToHex2Digits(unsigned v, char *s) throw() | ||
158 | { | ||
159 | s[0] = GetHexChar(v >> 4); | ||
160 | s[1] = GetHexChar(v & 0xF); | ||
161 | } | ||
162 | |||
163 | static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw() | ||
164 | { | ||
165 | ConvertByteToHex2Digits(val >> 8, s); | ||
166 | ConvertByteToHex2Digits(val & 0xFF, s + 2); | ||
167 | } | ||
168 | |||
169 | char *RawLeGuidToString(const Byte *g, char *s) throw() | ||
170 | { | ||
171 | ConvertUInt32ToHex8Digits(GetUi32(g ), s); s += 8; *s++ = '-'; | ||
172 | ConvertUInt16ToHex4Digits(GetUi16(g + 4), s); s += 4; *s++ = '-'; | ||
173 | ConvertUInt16ToHex4Digits(GetUi16(g + 6), s); s += 4; *s++ = '-'; | ||
174 | for (unsigned i = 0; i < 8; i++) | ||
175 | { | ||
176 | if (i == 2) | ||
177 | *s++ = '-'; | ||
178 | ConvertByteToHex2Digits(g[8 + i], s); | ||
179 | s += 2; | ||
180 | } | ||
181 | *s = 0; | ||
182 | return s; | ||
183 | } | ||
184 | |||
185 | char *RawLeGuidToString_Braced(const Byte *g, char *s) throw() | ||
186 | { | ||
187 | *s++ = '{'; | ||
188 | s = RawLeGuidToString(g, s); | ||
189 | *s++ = '}'; | ||
190 | *s = 0; | ||
191 | return s; | ||
192 | } | ||
diff --git a/CPP/Common/IntToString.h b/CPP/Common/IntToString.h new file mode 100644 index 0000000..d0a96ef --- /dev/null +++ b/CPP/Common/IntToString.h | |||
@@ -0,0 +1,30 @@ | |||
1 | // Common/IntToString.h | ||
2 | |||
3 | #ifndef __COMMON_INT_TO_STRING_H | ||
4 | #define __COMMON_INT_TO_STRING_H | ||
5 | |||
6 | #include "MyTypes.h" | ||
7 | |||
8 | // return: the pointer to the "terminating" null character after written characters | ||
9 | |||
10 | char * ConvertUInt32ToString(UInt32 value, char *s) throw(); | ||
11 | char * ConvertUInt64ToString(UInt64 value, char *s) throw(); | ||
12 | |||
13 | wchar_t * ConvertUInt32ToString(UInt32 value, wchar_t *s) throw(); | ||
14 | wchar_t * ConvertUInt64ToString(UInt64 value, wchar_t *s) throw(); | ||
15 | |||
16 | void ConvertUInt64ToOct(UInt64 value, char *s) throw(); | ||
17 | |||
18 | void ConvertUInt32ToHex(UInt32 value, char *s) throw(); | ||
19 | void ConvertUInt64ToHex(UInt64 value, char *s) throw(); | ||
20 | void ConvertUInt32ToHex8Digits(UInt32 value, char *s) throw(); | ||
21 | // void ConvertUInt32ToHex8Digits(UInt32 value, wchar_t *s) throw(); | ||
22 | |||
23 | void ConvertInt64ToString(Int64 value, char *s) throw(); | ||
24 | void ConvertInt64ToString(Int64 value, wchar_t *s) throw(); | ||
25 | |||
26 | // use RawLeGuid only for RAW bytes that contain stored GUID as Little-endian. | ||
27 | char *RawLeGuidToString(const Byte *guid, char *s) throw(); | ||
28 | char *RawLeGuidToString_Braced(const Byte *guid, char *s) throw(); | ||
29 | |||
30 | #endif | ||
diff --git a/CPP/Common/Lang.cpp b/CPP/Common/Lang.cpp new file mode 100644 index 0000000..35d3752 --- /dev/null +++ b/CPP/Common/Lang.cpp | |||
@@ -0,0 +1,163 @@ | |||
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 | |||
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 | |||
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 | |||
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 | |||
157 | 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 | } | ||
diff --git a/CPP/Common/Lang.h b/CPP/Common/Lang.h new file mode 100644 index 0000000..cc66677 --- /dev/null +++ b/CPP/Common/Lang.h | |||
@@ -0,0 +1,23 @@ | |||
1 | // Common/Lang.h | ||
2 | |||
3 | #ifndef __COMMON_LANG_H | ||
4 | #define __COMMON_LANG_H | ||
5 | |||
6 | #include "MyString.h" | ||
7 | |||
8 | class CLang | ||
9 | { | ||
10 | wchar_t *_text; | ||
11 | CRecordVector<UInt32> _ids; | ||
12 | CRecordVector<UInt32> _offsets; | ||
13 | |||
14 | bool OpenFromString(const AString &s); | ||
15 | public: | ||
16 | CLang(): _text(0) {} | ||
17 | ~CLang() { Clear(); } | ||
18 | bool Open(CFSTR fileName, const char *id); | ||
19 | void Clear() throw(); | ||
20 | const wchar_t *Get(UInt32 id) const throw(); | ||
21 | }; | ||
22 | |||
23 | #endif | ||
diff --git a/CPP/Common/ListFileUtils.cpp b/CPP/Common/ListFileUtils.cpp new file mode 100644 index 0000000..b361b37 --- /dev/null +++ b/CPP/Common/ListFileUtils.cpp | |||
@@ -0,0 +1,150 @@ | |||
1 | // Common/ListFileUtils.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/CpuArch.h" | ||
6 | |||
7 | #include "ListFileUtils.h" | ||
8 | #include "MyBuffer.h" | ||
9 | #include "StringConvert.h" | ||
10 | #include "UTFConvert.h" | ||
11 | |||
12 | #include "../Windows/FileIO.h" | ||
13 | |||
14 | #define CSysInFile NWindows::NFile::NIO::CInFile | ||
15 | #define MY_GET_LAST_ERROR ::GetLastError() | ||
16 | |||
17 | |||
18 | #define kQuoteChar '\"' | ||
19 | |||
20 | |||
21 | static void AddName(UStringVector &strings, UString &s) | ||
22 | { | ||
23 | s.Trim(); | ||
24 | if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar) | ||
25 | { | ||
26 | s.DeleteBack(); | ||
27 | s.Delete(0); | ||
28 | } | ||
29 | if (!s.IsEmpty()) | ||
30 | strings.Add(s); | ||
31 | } | ||
32 | |||
33 | |||
34 | static bool My_File_Read(CSysInFile &file, void *data, size_t size, DWORD &lastError) | ||
35 | { | ||
36 | size_t processed; | ||
37 | if (!file.ReadFull(data, size, processed)) | ||
38 | { | ||
39 | lastError = MY_GET_LAST_ERROR; | ||
40 | return false; | ||
41 | } | ||
42 | if (processed != size) | ||
43 | { | ||
44 | lastError = 1; // error: size of listfile was changed | ||
45 | return false; | ||
46 | } | ||
47 | return true; | ||
48 | } | ||
49 | |||
50 | |||
51 | bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, DWORD &lastError) | ||
52 | { | ||
53 | lastError = 0; | ||
54 | CSysInFile file; | ||
55 | if (!file.Open(fileName)) | ||
56 | { | ||
57 | lastError = MY_GET_LAST_ERROR; | ||
58 | return false; | ||
59 | } | ||
60 | UInt64 fileSize; | ||
61 | if (!file.GetLength(fileSize)) | ||
62 | { | ||
63 | lastError = MY_GET_LAST_ERROR; | ||
64 | return false; | ||
65 | } | ||
66 | if (fileSize >= ((UInt32)1 << 31) - 32) | ||
67 | return false; | ||
68 | UString u; | ||
69 | if (codePage == MY__CP_UTF16 || codePage == MY__CP_UTF16BE) | ||
70 | { | ||
71 | if ((fileSize & 1) != 0) | ||
72 | return false; | ||
73 | CByteArr buf((size_t)fileSize); | ||
74 | |||
75 | if (!My_File_Read(file, buf, (size_t)fileSize, lastError)) | ||
76 | return false; | ||
77 | |||
78 | file.Close(); | ||
79 | const unsigned num = (unsigned)fileSize / 2; | ||
80 | wchar_t *p = u.GetBuf(num); | ||
81 | if (codePage == MY__CP_UTF16) | ||
82 | for (unsigned i = 0; i < num; i++) | ||
83 | { | ||
84 | wchar_t c = GetUi16(buf + (size_t)i * 2); | ||
85 | if (c == 0) | ||
86 | return false; | ||
87 | p[i] = c; | ||
88 | } | ||
89 | else | ||
90 | for (unsigned i = 0; i < num; i++) | ||
91 | { | ||
92 | wchar_t c = (wchar_t)GetBe16(buf + (size_t)i * 2); | ||
93 | if (c == 0) | ||
94 | return false; | ||
95 | p[i] = c; | ||
96 | } | ||
97 | p[num] = 0; | ||
98 | u.ReleaseBuf_SetLen(num); | ||
99 | } | ||
100 | else | ||
101 | { | ||
102 | AString s; | ||
103 | char *p = s.GetBuf((unsigned)fileSize); | ||
104 | |||
105 | if (!My_File_Read(file, p, (size_t)fileSize, lastError)) | ||
106 | return false; | ||
107 | |||
108 | file.Close(); | ||
109 | s.ReleaseBuf_CalcLen((unsigned)fileSize); | ||
110 | if (s.Len() != fileSize) | ||
111 | return false; | ||
112 | |||
113 | // #ifdef CP_UTF8 | ||
114 | if (codePage == CP_UTF8) | ||
115 | { | ||
116 | // we must check UTF8 here, if convert function doesn't check | ||
117 | if (!CheckUTF8_AString(s)) | ||
118 | return false; | ||
119 | if (!ConvertUTF8ToUnicode(s, u)) | ||
120 | return false; | ||
121 | } | ||
122 | else | ||
123 | // #endif | ||
124 | MultiByteToUnicodeString2(u, s, codePage); | ||
125 | } | ||
126 | |||
127 | const wchar_t kGoodBOM = 0xFEFF; | ||
128 | // const wchar_t kBadBOM = 0xFFFE; | ||
129 | |||
130 | UString s; | ||
131 | unsigned i = 0; | ||
132 | for (; i < u.Len() && u[i] == kGoodBOM; i++); | ||
133 | for (; i < u.Len(); i++) | ||
134 | { | ||
135 | wchar_t c = u[i]; | ||
136 | /* | ||
137 | if (c == kGoodBOM || c == kBadBOM) | ||
138 | return false; | ||
139 | */ | ||
140 | if (c == '\n' || c == 0xD) | ||
141 | { | ||
142 | AddName(strings, s); | ||
143 | s.Empty(); | ||
144 | } | ||
145 | else | ||
146 | s += c; | ||
147 | } | ||
148 | AddName(strings, s); | ||
149 | return true; | ||
150 | } | ||
diff --git a/CPP/Common/ListFileUtils.h b/CPP/Common/ListFileUtils.h new file mode 100644 index 0000000..a91e4b1 --- /dev/null +++ b/CPP/Common/ListFileUtils.h | |||
@@ -0,0 +1,18 @@ | |||
1 | // Common/ListFileUtils.h | ||
2 | |||
3 | #ifndef __COMMON_LIST_FILE_UTILS_H | ||
4 | #define __COMMON_LIST_FILE_UTILS_H | ||
5 | |||
6 | #include "MyString.h" | ||
7 | #include "MyTypes.h" | ||
8 | |||
9 | #define MY__CP_UTF16 1200 | ||
10 | #define MY__CP_UTF16BE 1201 | ||
11 | |||
12 | // bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP); | ||
13 | |||
14 | // = CP_OEMCP | ||
15 | bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, | ||
16 | DWORD &lastError); | ||
17 | |||
18 | #endif | ||
diff --git a/CPP/Common/LzFindPrepare.cpp b/CPP/Common/LzFindPrepare.cpp new file mode 100644 index 0000000..8845e4a --- /dev/null +++ b/CPP/Common/LzFindPrepare.cpp | |||
@@ -0,0 +1,7 @@ | |||
1 | // Sha256Prepare.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/LzFind.h" | ||
6 | |||
7 | static struct CLzFindPrepare { CLzFindPrepare() { LzFindPrepare(); } } g_CLzFindPrepare; | ||
diff --git a/CPP/Common/MyBuffer.h b/CPP/Common/MyBuffer.h new file mode 100644 index 0000000..18ab6fa --- /dev/null +++ b/CPP/Common/MyBuffer.h | |||
@@ -0,0 +1,277 @@ | |||
1 | // Common/MyBuffer.h | ||
2 | |||
3 | #ifndef __COMMON_MY_BUFFER_H | ||
4 | #define __COMMON_MY_BUFFER_H | ||
5 | |||
6 | #include "Defs.h" | ||
7 | #include "MyTypes.h" | ||
8 | |||
9 | /* 7-Zip now uses CBuffer only as CByteBuffer. | ||
10 | So there is no need to use MY_ARRAY_NEW macro in CBuffer code. */ | ||
11 | |||
12 | template <class T> class CBuffer | ||
13 | { | ||
14 | T *_items; | ||
15 | size_t _size; | ||
16 | |||
17 | public: | ||
18 | void Free() | ||
19 | { | ||
20 | if (_items) | ||
21 | { | ||
22 | delete []_items; | ||
23 | _items = 0; | ||
24 | } | ||
25 | _size = 0; | ||
26 | } | ||
27 | |||
28 | CBuffer(): _items(0), _size(0) {}; | ||
29 | CBuffer(size_t size): _items(0), _size(0) { _items = new T[size]; _size = size; } | ||
30 | CBuffer(const CBuffer &buffer): _items(0), _size(0) | ||
31 | { | ||
32 | size_t size = buffer._size; | ||
33 | if (size != 0) | ||
34 | { | ||
35 | _items = new T[size]; | ||
36 | memcpy(_items, buffer._items, size * sizeof(T)); | ||
37 | _size = size; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | ~CBuffer() { delete []_items; } | ||
42 | |||
43 | operator T *() { return _items; } | ||
44 | operator const T *() const { return _items; } | ||
45 | size_t Size() const { return _size; } | ||
46 | |||
47 | void Alloc(size_t size) | ||
48 | { | ||
49 | if (size != _size) | ||
50 | { | ||
51 | Free(); | ||
52 | if (size != 0) | ||
53 | { | ||
54 | _items = new T[size]; | ||
55 | _size = size; | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | void AllocAtLeast(size_t size) | ||
61 | { | ||
62 | if (size > _size) | ||
63 | { | ||
64 | Free(); | ||
65 | _items = new T[size]; | ||
66 | _size = size; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | void CopyFrom(const T *data, size_t size) | ||
71 | { | ||
72 | Alloc(size); | ||
73 | if (size != 0) | ||
74 | memcpy(_items, data, size * sizeof(T)); | ||
75 | } | ||
76 | |||
77 | void ChangeSize_KeepData(size_t newSize, size_t keepSize) | ||
78 | { | ||
79 | if (newSize == _size) | ||
80 | return; | ||
81 | T *newBuffer = NULL; | ||
82 | if (newSize != 0) | ||
83 | { | ||
84 | newBuffer = new T[newSize]; | ||
85 | if (keepSize > _size) | ||
86 | keepSize = _size; | ||
87 | if (keepSize != 0) | ||
88 | memcpy(newBuffer, _items, MyMin(keepSize, newSize) * sizeof(T)); | ||
89 | } | ||
90 | delete []_items; | ||
91 | _items = newBuffer; | ||
92 | _size = newSize; | ||
93 | } | ||
94 | |||
95 | void Wipe() | ||
96 | { | ||
97 | if (_size != 0) | ||
98 | memset(_items, 0, _size * sizeof(T)); | ||
99 | } | ||
100 | |||
101 | CBuffer& operator=(const CBuffer &buffer) | ||
102 | { | ||
103 | if (&buffer != this) | ||
104 | CopyFrom(buffer, buffer._size); | ||
105 | return *this; | ||
106 | } | ||
107 | }; | ||
108 | |||
109 | template <class T> | ||
110 | bool operator==(const CBuffer<T>& b1, const CBuffer<T>& b2) | ||
111 | { | ||
112 | size_t size1 = b1.Size(); | ||
113 | if (size1 != b2.Size()) | ||
114 | return false; | ||
115 | if (size1 == 0) | ||
116 | return true; | ||
117 | return memcmp(b1, b2, size1 * sizeof(T)) == 0; | ||
118 | } | ||
119 | |||
120 | template <class T> | ||
121 | bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& b2) | ||
122 | { | ||
123 | size_t size1 = b1.Size(); | ||
124 | if (size1 != b2.Size()) | ||
125 | return true; | ||
126 | if (size1 == 0) | ||
127 | return false; | ||
128 | return memcmp(b1, b2, size1 * sizeof(T)) != 0; | ||
129 | } | ||
130 | |||
131 | |||
132 | // typedef CBuffer<char> CCharBuffer; | ||
133 | // typedef CBuffer<wchar_t> CWCharBuffer; | ||
134 | typedef CBuffer<unsigned char> CByteBuffer; | ||
135 | |||
136 | |||
137 | class CByteBuffer_Wipe: public CByteBuffer | ||
138 | { | ||
139 | CLASS_NO_COPY(CByteBuffer_Wipe) | ||
140 | public: | ||
141 | // CByteBuffer_Wipe(): CBuffer<unsigned char>() {} | ||
142 | CByteBuffer_Wipe(size_t size): CBuffer<unsigned char>(size) {} | ||
143 | ~CByteBuffer_Wipe() { Wipe(); } | ||
144 | }; | ||
145 | |||
146 | |||
147 | |||
148 | template <class T> class CObjArray | ||
149 | { | ||
150 | protected: | ||
151 | T *_items; | ||
152 | private: | ||
153 | // we disable copy | ||
154 | CObjArray(const CObjArray &buffer); | ||
155 | void operator=(const CObjArray &buffer); | ||
156 | public: | ||
157 | void Free() | ||
158 | { | ||
159 | delete []_items; | ||
160 | _items = 0; | ||
161 | } | ||
162 | CObjArray(size_t size): _items(0) | ||
163 | { | ||
164 | if (size != 0) | ||
165 | { | ||
166 | MY_ARRAY_NEW(_items, T, size) | ||
167 | // _items = new T[size]; | ||
168 | } | ||
169 | } | ||
170 | CObjArray(): _items(0) {}; | ||
171 | ~CObjArray() { delete []_items; } | ||
172 | |||
173 | operator T *() { return _items; } | ||
174 | operator const T *() const { return _items; } | ||
175 | |||
176 | void Alloc(size_t newSize) | ||
177 | { | ||
178 | delete []_items; | ||
179 | _items = 0; | ||
180 | MY_ARRAY_NEW(_items, T, newSize) | ||
181 | // _items = new T[newSize]; | ||
182 | } | ||
183 | }; | ||
184 | |||
185 | typedef CObjArray<unsigned char> CByteArr; | ||
186 | typedef CObjArray<bool> CBoolArr; | ||
187 | typedef CObjArray<int> CIntArr; | ||
188 | typedef CObjArray<unsigned> CUIntArr; | ||
189 | |||
190 | |||
191 | template <class T> class CObjArray2 | ||
192 | { | ||
193 | T *_items; | ||
194 | unsigned _size; | ||
195 | |||
196 | // we disable copy | ||
197 | CObjArray2(const CObjArray2 &buffer); | ||
198 | void operator=(const CObjArray2 &buffer); | ||
199 | public: | ||
200 | |||
201 | void Free() | ||
202 | { | ||
203 | delete []_items; | ||
204 | _items = 0; | ||
205 | _size = 0; | ||
206 | } | ||
207 | CObjArray2(): _items(0), _size(0) {}; | ||
208 | /* | ||
209 | CObjArray2(const CObjArray2 &buffer): _items(0), _size(0) | ||
210 | { | ||
211 | size_t newSize = buffer._size; | ||
212 | if (newSize != 0) | ||
213 | { | ||
214 | T *newBuffer = new T[newSize];; | ||
215 | _items = newBuffer; | ||
216 | _size = newSize; | ||
217 | const T *src = buffer; | ||
218 | for (size_t i = 0; i < newSize; i++) | ||
219 | newBuffer[i] = src[i]; | ||
220 | } | ||
221 | } | ||
222 | */ | ||
223 | /* | ||
224 | CObjArray2(size_t size): _items(0), _size(0) | ||
225 | { | ||
226 | if (size != 0) | ||
227 | { | ||
228 | _items = new T[size]; | ||
229 | _size = size; | ||
230 | } | ||
231 | } | ||
232 | */ | ||
233 | |||
234 | ~CObjArray2() { delete []_items; } | ||
235 | |||
236 | operator T *() { return _items; } | ||
237 | operator const T *() const { return _items; } | ||
238 | |||
239 | unsigned Size() const { return (unsigned)_size; } | ||
240 | bool IsEmpty() const { return _size == 0; } | ||
241 | |||
242 | // SetSize doesn't keep old items. It allocates new array if size is not equal | ||
243 | void SetSize(unsigned size) | ||
244 | { | ||
245 | if (size == _size) | ||
246 | return; | ||
247 | T *newBuffer = NULL; | ||
248 | if (size != 0) | ||
249 | { | ||
250 | MY_ARRAY_NEW(newBuffer, T, size) | ||
251 | // newBuffer = new T[size]; | ||
252 | } | ||
253 | delete []_items; | ||
254 | _items = newBuffer; | ||
255 | _size = size; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | CObjArray2& operator=(const CObjArray2 &buffer) | ||
260 | { | ||
261 | Free(); | ||
262 | size_t newSize = buffer._size; | ||
263 | if (newSize != 0) | ||
264 | { | ||
265 | T *newBuffer = new T[newSize];; | ||
266 | _items = newBuffer; | ||
267 | _size = newSize; | ||
268 | const T *src = buffer; | ||
269 | for (size_t i = 0; i < newSize; i++) | ||
270 | newBuffer[i] = src[i]; | ||
271 | } | ||
272 | return *this; | ||
273 | } | ||
274 | */ | ||
275 | }; | ||
276 | |||
277 | #endif | ||
diff --git a/CPP/Common/MyBuffer2.h b/CPP/Common/MyBuffer2.h new file mode 100644 index 0000000..372d478 --- /dev/null +++ b/CPP/Common/MyBuffer2.h | |||
@@ -0,0 +1,139 @@ | |||
1 | // Common/MyBuffer2.h | ||
2 | |||
3 | #ifndef __COMMON_MY_BUFFER2_H | ||
4 | #define __COMMON_MY_BUFFER2_H | ||
5 | |||
6 | #include "../../C/Alloc.h" | ||
7 | |||
8 | #include "MyTypes.h" | ||
9 | |||
10 | class CMidBuffer | ||
11 | { | ||
12 | Byte *_data; | ||
13 | size_t _size; | ||
14 | |||
15 | CLASS_NO_COPY(CMidBuffer) | ||
16 | |||
17 | public: | ||
18 | CMidBuffer(): _data(NULL), _size(0) {} | ||
19 | ~CMidBuffer() { ::MidFree(_data); } | ||
20 | |||
21 | void Free() { ::MidFree(_data); _data = NULL; _size = 0; } | ||
22 | |||
23 | bool IsAllocated() const { return _data != NULL; } | ||
24 | operator Byte *() { return _data; } | ||
25 | operator const Byte *() const { return _data; } | ||
26 | size_t Size() const { return _size; } | ||
27 | |||
28 | void Alloc(size_t size) | ||
29 | { | ||
30 | if (!_data || size != _size) | ||
31 | { | ||
32 | ::MidFree(_data); | ||
33 | _size = 0; | ||
34 | _data = NULL; | ||
35 | _data = (Byte *)::MidAlloc(size); | ||
36 | if (_data) | ||
37 | _size = size; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | void AllocAtLeast(size_t size) | ||
42 | { | ||
43 | if (!_data || size > _size) | ||
44 | { | ||
45 | ::MidFree(_data); | ||
46 | const size_t kMinSize = (size_t)1 << 16; | ||
47 | if (size < kMinSize) | ||
48 | size = kMinSize; | ||
49 | _size = 0; | ||
50 | _data = NULL; | ||
51 | _data = (Byte *)::MidAlloc(size); | ||
52 | if (_data) | ||
53 | _size = size; | ||
54 | } | ||
55 | } | ||
56 | }; | ||
57 | |||
58 | |||
59 | class CAlignedBuffer | ||
60 | { | ||
61 | Byte *_data; | ||
62 | size_t _size; | ||
63 | |||
64 | CLASS_NO_COPY(CAlignedBuffer) | ||
65 | |||
66 | public: | ||
67 | CAlignedBuffer(): _data(NULL), _size(0) {} | ||
68 | ~CAlignedBuffer() | ||
69 | { | ||
70 | ISzAlloc_Free(&g_AlignedAlloc, _data); | ||
71 | } | ||
72 | |||
73 | CAlignedBuffer(size_t size): _size(0) | ||
74 | { | ||
75 | _data = NULL; | ||
76 | _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size); | ||
77 | if (!_data) | ||
78 | throw 1; | ||
79 | _size = size; | ||
80 | } | ||
81 | |||
82 | void Free() | ||
83 | { | ||
84 | ISzAlloc_Free(&g_AlignedAlloc, _data); | ||
85 | _data = NULL; | ||
86 | _size = 0; | ||
87 | } | ||
88 | |||
89 | bool IsAllocated() const { return _data != NULL; } | ||
90 | operator Byte *() { return _data; } | ||
91 | operator const Byte *() const { return _data; } | ||
92 | size_t Size() const { return _size; } | ||
93 | |||
94 | void Alloc(size_t size) | ||
95 | { | ||
96 | if (!_data || size != _size) | ||
97 | { | ||
98 | ISzAlloc_Free(&g_AlignedAlloc, _data); | ||
99 | _size = 0; | ||
100 | _data = NULL; | ||
101 | _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size); | ||
102 | if (_data) | ||
103 | _size = size; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | void AllocAtLeast(size_t size) | ||
108 | { | ||
109 | if (!_data || size > _size) | ||
110 | { | ||
111 | ISzAlloc_Free(&g_AlignedAlloc, _data); | ||
112 | _size = 0; | ||
113 | _data = NULL; | ||
114 | _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size); | ||
115 | if (_data) | ||
116 | _size = size; | ||
117 | } | ||
118 | } | ||
119 | }; | ||
120 | |||
121 | /* | ||
122 | CMidAlignedBuffer must return aligned pointer. | ||
123 | - in Windows it uses CMidBuffer(): MidAlloc() : VirtualAlloc() | ||
124 | VirtualAlloc(): Memory allocated is automatically initialized to zero. | ||
125 | MidAlloc(0) returns NULL | ||
126 | - in non-Windows systems it uses g_AlignedAlloc. | ||
127 | g_AlignedAlloc::Alloc(size = 0) can return non NULL. | ||
128 | */ | ||
129 | |||
130 | typedef | ||
131 | #ifdef _WIN32 | ||
132 | CMidBuffer | ||
133 | #else | ||
134 | CAlignedBuffer | ||
135 | #endif | ||
136 | CMidAlignedBuffer; | ||
137 | |||
138 | |||
139 | #endif | ||
diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h new file mode 100644 index 0000000..ce2f0dd --- /dev/null +++ b/CPP/Common/MyCom.h | |||
@@ -0,0 +1,306 @@ | |||
1 | // MyCom.h | ||
2 | |||
3 | #ifndef __MY_COM_H | ||
4 | #define __MY_COM_H | ||
5 | |||
6 | #include "MyWindows.h" | ||
7 | #include "MyTypes.h" | ||
8 | |||
9 | #ifndef RINOK | ||
10 | #define RINOK(x) { HRESULT __result_ = (x); if (__result_ != S_OK) return __result_; } | ||
11 | #endif | ||
12 | |||
13 | template <class T> | ||
14 | class CMyComPtr | ||
15 | { | ||
16 | T* _p; | ||
17 | public: | ||
18 | CMyComPtr(): _p(NULL) {} | ||
19 | CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); } | ||
20 | CMyComPtr(const CMyComPtr<T>& lp) throw() { if ((_p = lp._p) != NULL) _p->AddRef(); } | ||
21 | ~CMyComPtr() { if (_p) _p->Release(); } | ||
22 | void Release() { if (_p) { _p->Release(); _p = NULL; } } | ||
23 | operator T*() const { return (T*)_p; } | ||
24 | // T& operator*() const { return *_p; } | ||
25 | T** operator&() { return &_p; } | ||
26 | T* operator->() const { return _p; } | ||
27 | T* operator=(T* p) | ||
28 | { | ||
29 | if (p) | ||
30 | p->AddRef(); | ||
31 | if (_p) | ||
32 | _p->Release(); | ||
33 | _p = p; | ||
34 | return p; | ||
35 | } | ||
36 | T* operator=(const CMyComPtr<T>& lp) { return (*this = lp._p); } | ||
37 | bool operator!() const { return (_p == NULL); } | ||
38 | // bool operator==(T* pT) const { return _p == pT; } | ||
39 | void Attach(T* p2) | ||
40 | { | ||
41 | Release(); | ||
42 | _p = p2; | ||
43 | } | ||
44 | T* Detach() | ||
45 | { | ||
46 | T* pt = _p; | ||
47 | _p = NULL; | ||
48 | return pt; | ||
49 | } | ||
50 | #ifdef _WIN32 | ||
51 | HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) | ||
52 | { | ||
53 | return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p); | ||
54 | } | ||
55 | #endif | ||
56 | /* | ||
57 | HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) | ||
58 | { | ||
59 | CLSID clsid; | ||
60 | HRESULT hr = CLSIDFromProgID(szProgID, &clsid); | ||
61 | ATLASSERT(_p == NULL); | ||
62 | if (SUCCEEDED(hr)) | ||
63 | hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p); | ||
64 | return hr; | ||
65 | } | ||
66 | */ | ||
67 | template <class Q> | ||
68 | HRESULT QueryInterface(REFGUID iid, Q** pp) const throw() | ||
69 | { | ||
70 | return _p->QueryInterface(iid, (void**)pp); | ||
71 | } | ||
72 | }; | ||
73 | |||
74 | ////////////////////////////////////////////////////////// | ||
75 | |||
76 | inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr) | ||
77 | { | ||
78 | *bstr = ::SysAllocString(src); | ||
79 | return (*bstr) ? S_OK : E_OUTOFMEMORY; | ||
80 | } | ||
81 | |||
82 | class CMyComBSTR | ||
83 | { | ||
84 | BSTR m_str; | ||
85 | CLASS_NO_COPY(CMyComBSTR) | ||
86 | public: | ||
87 | CMyComBSTR(): m_str(NULL) {} | ||
88 | ~CMyComBSTR() { ::SysFreeString(m_str); } | ||
89 | BSTR* operator&() { return &m_str; } | ||
90 | operator LPCOLESTR() const { return m_str; } | ||
91 | // operator bool() const { return m_str != NULL; } | ||
92 | // bool operator!() const { return m_str == NULL; } | ||
93 | |||
94 | void Wipe_and_Free() | ||
95 | { | ||
96 | if (m_str) | ||
97 | { | ||
98 | memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str)); | ||
99 | Empty(); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | private: | ||
104 | // operator BSTR() const { return m_str; } | ||
105 | |||
106 | CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); } | ||
107 | // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); } | ||
108 | // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); } | ||
109 | // CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); } | ||
110 | |||
111 | /* | ||
112 | CMyComBSTR(REFGUID src) | ||
113 | { | ||
114 | LPOLESTR szGuid; | ||
115 | StringFromCLSID(src, &szGuid); | ||
116 | m_str = ::SysAllocString(szGuid); | ||
117 | CoTaskMemFree(szGuid); | ||
118 | } | ||
119 | */ | ||
120 | |||
121 | /* | ||
122 | CMyComBSTR& operator=(const CMyComBSTR& src) | ||
123 | { | ||
124 | if (m_str != src.m_str) | ||
125 | { | ||
126 | if (m_str) | ||
127 | ::SysFreeString(m_str); | ||
128 | m_str = src.MyCopy(); | ||
129 | } | ||
130 | return *this; | ||
131 | } | ||
132 | */ | ||
133 | |||
134 | CMyComBSTR& operator=(LPCOLESTR src) | ||
135 | { | ||
136 | ::SysFreeString(m_str); | ||
137 | m_str = ::SysAllocString(src); | ||
138 | return *this; | ||
139 | } | ||
140 | |||
141 | unsigned Len() const { return ::SysStringLen(m_str); } | ||
142 | |||
143 | BSTR MyCopy() const | ||
144 | { | ||
145 | // We don't support Byte BSTRs here | ||
146 | return ::SysAllocStringLen(m_str, ::SysStringLen(m_str)); | ||
147 | /* | ||
148 | UINT byteLen = ::SysStringByteLen(m_str); | ||
149 | BSTR res = ::SysAllocStringByteLen(NULL, byteLen); | ||
150 | if (res && byteLen != 0 && m_str) | ||
151 | memcpy(res, m_str, byteLen); | ||
152 | return res; | ||
153 | */ | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | void Attach(BSTR src) { m_str = src; } | ||
158 | BSTR Detach() | ||
159 | { | ||
160 | BSTR s = m_str; | ||
161 | m_str = NULL; | ||
162 | return s; | ||
163 | } | ||
164 | */ | ||
165 | |||
166 | void Empty() | ||
167 | { | ||
168 | ::SysFreeString(m_str); | ||
169 | m_str = NULL; | ||
170 | } | ||
171 | }; | ||
172 | |||
173 | |||
174 | class CMyComBSTR_Wipe: public CMyComBSTR | ||
175 | { | ||
176 | CLASS_NO_COPY(CMyComBSTR_Wipe) | ||
177 | public: | ||
178 | CMyComBSTR_Wipe(): CMyComBSTR() {} | ||
179 | ~CMyComBSTR_Wipe() { Wipe_and_Free(); } | ||
180 | }; | ||
181 | |||
182 | |||
183 | |||
184 | /* | ||
185 | If CMyUnknownImp doesn't use virtual destructor, the code size is smaller. | ||
186 | But if some class_1 derived from CMyUnknownImp | ||
187 | uses MY_ADDREF_RELEASE and IUnknown::Release() | ||
188 | and some another class_2 is derived from class_1, | ||
189 | then class_1 must use virtual destructor: | ||
190 | virtual ~class_1(); | ||
191 | In that case, class_1::Release() calls correct destructor of class_2. | ||
192 | |||
193 | We use virtual ~CMyUnknownImp() to disable warning | ||
194 | "class has virtual functions, but destructor is not virtual". | ||
195 | |||
196 | also we can use virtual ~IUnknown() {} in MyWindows.h | ||
197 | */ | ||
198 | |||
199 | class CMyUnknownImp | ||
200 | { | ||
201 | CLASS_NO_COPY(CMyUnknownImp) | ||
202 | public: | ||
203 | ULONG __m_RefCount; | ||
204 | CMyUnknownImp(): __m_RefCount(0) {} | ||
205 | |||
206 | #ifdef _WIN32 | ||
207 | #if defined(__GNUC__) || defined(__clang__) | ||
208 | virtual // to disable GCC/CLANG varnings | ||
209 | #endif | ||
210 | #endif | ||
211 | ~CMyUnknownImp() {} | ||
212 | }; | ||
213 | |||
214 | |||
215 | |||
216 | #define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \ | ||
217 | (REFGUID iid, void **outObject) throw() { *outObject = NULL; | ||
218 | |||
219 | #define MY_QUERYINTERFACE_ENTRY(i) else if (iid == IID_ ## i) \ | ||
220 | { *outObject = (void *)(i *)this; } | ||
221 | |||
222 | #define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \ | ||
223 | { *outObject = (void *)(IUnknown *)(i *)this; } | ||
224 | |||
225 | #define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \ | ||
226 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \ | ||
227 | MY_QUERYINTERFACE_ENTRY(i) | ||
228 | |||
229 | #define MY_QUERYINTERFACE_END else return E_NOINTERFACE; ++__m_RefCount; /* AddRef(); */ return S_OK; } | ||
230 | |||
231 | #define MY_ADDREF_RELEASE \ | ||
232 | STDMETHOD_(ULONG, AddRef)() throw() { return ++__m_RefCount; } \ | ||
233 | STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) return __m_RefCount; \ | ||
234 | delete this; return 0; } | ||
235 | |||
236 | #define MY_UNKNOWN_IMP_SPEC(i) \ | ||
237 | MY_QUERYINTERFACE_BEGIN \ | ||
238 | i \ | ||
239 | MY_QUERYINTERFACE_END \ | ||
240 | MY_ADDREF_RELEASE | ||
241 | |||
242 | |||
243 | #define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \ | ||
244 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \ | ||
245 | MY_QUERYINTERFACE_END \ | ||
246 | MY_ADDREF_RELEASE | ||
247 | |||
248 | #define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \ | ||
249 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \ | ||
250 | MY_QUERYINTERFACE_ENTRY(i) \ | ||
251 | ) | ||
252 | |||
253 | #define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \ | ||
254 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ | ||
255 | MY_QUERYINTERFACE_ENTRY(i1) \ | ||
256 | MY_QUERYINTERFACE_ENTRY(i2) \ | ||
257 | ) | ||
258 | |||
259 | #define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \ | ||
260 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ | ||
261 | MY_QUERYINTERFACE_ENTRY(i1) \ | ||
262 | MY_QUERYINTERFACE_ENTRY(i2) \ | ||
263 | MY_QUERYINTERFACE_ENTRY(i3) \ | ||
264 | ) | ||
265 | |||
266 | #define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \ | ||
267 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ | ||
268 | MY_QUERYINTERFACE_ENTRY(i1) \ | ||
269 | MY_QUERYINTERFACE_ENTRY(i2) \ | ||
270 | MY_QUERYINTERFACE_ENTRY(i3) \ | ||
271 | MY_QUERYINTERFACE_ENTRY(i4) \ | ||
272 | ) | ||
273 | |||
274 | #define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \ | ||
275 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ | ||
276 | MY_QUERYINTERFACE_ENTRY(i1) \ | ||
277 | MY_QUERYINTERFACE_ENTRY(i2) \ | ||
278 | MY_QUERYINTERFACE_ENTRY(i3) \ | ||
279 | MY_QUERYINTERFACE_ENTRY(i4) \ | ||
280 | MY_QUERYINTERFACE_ENTRY(i5) \ | ||
281 | ) | ||
282 | |||
283 | #define MY_UNKNOWN_IMP6(i1, i2, i3, i4, i5, i6) MY_UNKNOWN_IMP_SPEC( \ | ||
284 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ | ||
285 | MY_QUERYINTERFACE_ENTRY(i1) \ | ||
286 | MY_QUERYINTERFACE_ENTRY(i2) \ | ||
287 | MY_QUERYINTERFACE_ENTRY(i3) \ | ||
288 | MY_QUERYINTERFACE_ENTRY(i4) \ | ||
289 | MY_QUERYINTERFACE_ENTRY(i5) \ | ||
290 | MY_QUERYINTERFACE_ENTRY(i6) \ | ||
291 | ) | ||
292 | |||
293 | #define MY_UNKNOWN_IMP7(i1, i2, i3, i4, i5, i6, i7) MY_UNKNOWN_IMP_SPEC( \ | ||
294 | MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \ | ||
295 | MY_QUERYINTERFACE_ENTRY(i1) \ | ||
296 | MY_QUERYINTERFACE_ENTRY(i2) \ | ||
297 | MY_QUERYINTERFACE_ENTRY(i3) \ | ||
298 | MY_QUERYINTERFACE_ENTRY(i4) \ | ||
299 | MY_QUERYINTERFACE_ENTRY(i5) \ | ||
300 | MY_QUERYINTERFACE_ENTRY(i6) \ | ||
301 | MY_QUERYINTERFACE_ENTRY(i7) \ | ||
302 | ) | ||
303 | |||
304 | const HRESULT k_My_HRESULT_WritingWasCut = 0x20000010; | ||
305 | |||
306 | #endif | ||
diff --git a/CPP/Common/MyException.h b/CPP/Common/MyException.h new file mode 100644 index 0000000..f0ad111 --- /dev/null +++ b/CPP/Common/MyException.h | |||
@@ -0,0 +1,14 @@ | |||
1 | // Common/Exception.h | ||
2 | |||
3 | #ifndef __COMMON_EXCEPTION_H | ||
4 | #define __COMMON_EXCEPTION_H | ||
5 | |||
6 | #include "MyWindows.h" | ||
7 | |||
8 | struct CSystemException | ||
9 | { | ||
10 | HRESULT ErrorCode; | ||
11 | CSystemException(HRESULT errorCode): ErrorCode(errorCode) {} | ||
12 | }; | ||
13 | |||
14 | #endif | ||
diff --git a/CPP/Common/MyGuidDef.h b/CPP/Common/MyGuidDef.h new file mode 100644 index 0000000..38aad6e --- /dev/null +++ b/CPP/Common/MyGuidDef.h | |||
@@ -0,0 +1,57 @@ | |||
1 | // Common/MyGuidDef.h | ||
2 | |||
3 | #ifndef GUID_DEFINED | ||
4 | #define GUID_DEFINED | ||
5 | |||
6 | #include "MyTypes.h" | ||
7 | |||
8 | typedef struct { | ||
9 | UInt32 Data1; | ||
10 | UInt16 Data2; | ||
11 | UInt16 Data3; | ||
12 | unsigned char Data4[8]; | ||
13 | } GUID; | ||
14 | |||
15 | #ifdef __cplusplus | ||
16 | #define REFGUID const GUID & | ||
17 | #else | ||
18 | #define REFGUID const GUID * | ||
19 | #endif | ||
20 | |||
21 | // typedef GUID IID; | ||
22 | typedef GUID CLSID; | ||
23 | |||
24 | #define REFCLSID REFGUID | ||
25 | #define REFIID REFGUID | ||
26 | |||
27 | #ifdef __cplusplus | ||
28 | inline int operator==(REFGUID g1, REFGUID g2) | ||
29 | { | ||
30 | for (int i = 0; i < (int)sizeof(g1); i++) | ||
31 | if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i]) | ||
32 | return 0; | ||
33 | return 1; | ||
34 | } | ||
35 | inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); } | ||
36 | #endif | ||
37 | |||
38 | #ifdef __cplusplus | ||
39 | #define MY_EXTERN_C extern "C" | ||
40 | #else | ||
41 | #define MY_EXTERN_C extern | ||
42 | #endif | ||
43 | |||
44 | #endif | ||
45 | |||
46 | |||
47 | #ifdef DEFINE_GUID | ||
48 | #undef DEFINE_GUID | ||
49 | #endif | ||
50 | |||
51 | #ifdef INITGUID | ||
52 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ | ||
53 | MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } | ||
54 | #else | ||
55 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ | ||
56 | MY_EXTERN_C const GUID name | ||
57 | #endif | ||
diff --git a/CPP/Common/MyInitGuid.h b/CPP/Common/MyInitGuid.h new file mode 100644 index 0000000..04d77e2 --- /dev/null +++ b/CPP/Common/MyInitGuid.h | |||
@@ -0,0 +1,49 @@ | |||
1 | // Common/MyInitGuid.h | ||
2 | |||
3 | #ifndef __COMMON_MY_INITGUID_H | ||
4 | #define __COMMON_MY_INITGUID_H | ||
5 | |||
6 | /* | ||
7 | This file must be included only to one C++ file in project before | ||
8 | declarations of COM interfaces with DEFINE_GUID macro. | ||
9 | |||
10 | Each GUID must be initialized exactly once in project. | ||
11 | There are two different versions of the DEFINE_GUID macro in guiddef.h (MyGuidDef.h): | ||
12 | - if INITGUID is not defined: DEFINE_GUID declares an external reference to the symbol name. | ||
13 | - if INITGUID is defined: DEFINE_GUID initializes the symbol name to the value of the GUID. | ||
14 | |||
15 | Also we need IID_IUnknown that is initialized in some file for linking: | ||
16 | MSVC: by default the linker uses some lib file that contains IID_IUnknown | ||
17 | MinGW: add -luuid switch for linker | ||
18 | WinCE: we define IID_IUnknown in this file | ||
19 | Other: we define IID_IUnknown in this file | ||
20 | */ | ||
21 | |||
22 | #ifdef __clang__ | ||
23 | #pragma clang diagnostic ignored "-Wmissing-variable-declarations" | ||
24 | #endif | ||
25 | |||
26 | #ifdef _WIN32 | ||
27 | |||
28 | #ifdef UNDER_CE | ||
29 | #include <basetyps.h> | ||
30 | #endif | ||
31 | |||
32 | #include <InitGuid.h> | ||
33 | |||
34 | #ifdef UNDER_CE | ||
35 | DEFINE_GUID(IID_IUnknown, | ||
36 | 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); | ||
37 | #endif | ||
38 | |||
39 | #else | ||
40 | |||
41 | #define INITGUID | ||
42 | #include "MyGuidDef.h" | ||
43 | DEFINE_GUID(IID_IUnknown, | ||
44 | 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); | ||
45 | |||
46 | #endif | ||
47 | |||
48 | |||
49 | #endif | ||
diff --git a/CPP/Common/MyLinux.h b/CPP/Common/MyLinux.h new file mode 100644 index 0000000..1a91899 --- /dev/null +++ b/CPP/Common/MyLinux.h | |||
@@ -0,0 +1,42 @@ | |||
1 | // MyLinux.h | ||
2 | |||
3 | #ifndef __MY_LIN_LINUX_H | ||
4 | #define __MY_LIN_LINUX_H | ||
5 | |||
6 | #define MY_LIN_S_IFMT 00170000 | ||
7 | #define MY_LIN_S_IFSOCK 0140000 | ||
8 | #define MY_LIN_S_IFLNK 0120000 | ||
9 | #define MY_LIN_S_IFREG 0100000 | ||
10 | #define MY_LIN_S_IFBLK 0060000 | ||
11 | #define MY_LIN_S_IFDIR 0040000 | ||
12 | #define MY_LIN_S_IFCHR 0020000 | ||
13 | #define MY_LIN_S_IFIFO 0010000 | ||
14 | |||
15 | #define MY_LIN_S_ISLNK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFLNK) | ||
16 | #define MY_LIN_S_ISREG(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFREG) | ||
17 | #define MY_LIN_S_ISDIR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFDIR) | ||
18 | #define MY_LIN_S_ISCHR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFCHR) | ||
19 | #define MY_LIN_S_ISBLK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFBLK) | ||
20 | #define MY_LIN_S_ISFIFO(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFIFO) | ||
21 | #define MY_LIN_S_ISSOCK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFSOCK) | ||
22 | |||
23 | #define MY_LIN_S_ISUID 0004000 | ||
24 | #define MY_LIN_S_ISGID 0002000 | ||
25 | #define MY_LIN_S_ISVTX 0001000 | ||
26 | |||
27 | #define MY_LIN_S_IRWXU 00700 | ||
28 | #define MY_LIN_S_IRUSR 00400 | ||
29 | #define MY_LIN_S_IWUSR 00200 | ||
30 | #define MY_LIN_S_IXUSR 00100 | ||
31 | |||
32 | #define MY_LIN_S_IRWXG 00070 | ||
33 | #define MY_LIN_S_IRGRP 00040 | ||
34 | #define MY_LIN_S_IWGRP 00020 | ||
35 | #define MY_LIN_S_IXGRP 00010 | ||
36 | |||
37 | #define MY_LIN_S_IRWXO 00007 | ||
38 | #define MY_LIN_S_IROTH 00004 | ||
39 | #define MY_LIN_S_IWOTH 00002 | ||
40 | #define MY_LIN_S_IXOTH 00001 | ||
41 | |||
42 | #endif | ||
diff --git a/CPP/Common/MyMap.cpp b/CPP/Common/MyMap.cpp new file mode 100644 index 0000000..923846a --- /dev/null +++ b/CPP/Common/MyMap.cpp | |||
@@ -0,0 +1,140 @@ | |||
1 | // MyMap.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "MyMap.h" | ||
6 | |||
7 | static const unsigned kNumBitsMax = sizeof(UInt32) * 8; | ||
8 | |||
9 | static UInt32 GetSubBits(UInt32 value, unsigned startPos, unsigned numBits) throw() | ||
10 | { | ||
11 | if (startPos == sizeof(value) * 8) | ||
12 | return 0; | ||
13 | value >>= startPos; | ||
14 | if (numBits == sizeof(value) * 8) | ||
15 | return value; | ||
16 | return value & (((UInt32)1 << numBits) - 1); | ||
17 | } | ||
18 | |||
19 | static inline unsigned GetSubBit(UInt32 v, unsigned n) { return (unsigned)(v >> n) & 1; } | ||
20 | |||
21 | bool CMap32::Find(UInt32 key, UInt32 &valueRes) const throw() | ||
22 | { | ||
23 | valueRes = (UInt32)(Int32)-1; | ||
24 | if (Nodes.Size() == 0) | ||
25 | return false; | ||
26 | if (Nodes.Size() == 1) | ||
27 | { | ||
28 | const CNode &n = Nodes[0]; | ||
29 | if (n.Len == kNumBitsMax) | ||
30 | { | ||
31 | valueRes = n.Values[0]; | ||
32 | return (key == n.Key); | ||
33 | } | ||
34 | } | ||
35 | |||
36 | unsigned cur = 0; | ||
37 | unsigned bitPos = kNumBitsMax; | ||
38 | for (;;) | ||
39 | { | ||
40 | const CNode &n = Nodes[cur]; | ||
41 | bitPos -= n.Len; | ||
42 | if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len)) | ||
43 | return false; | ||
44 | unsigned bit = GetSubBit(key, --bitPos); | ||
45 | if (n.IsLeaf[bit]) | ||
46 | { | ||
47 | valueRes = n.Values[bit]; | ||
48 | return (key == n.Keys[bit]); | ||
49 | } | ||
50 | cur = (unsigned)n.Keys[bit]; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | bool CMap32::Set(UInt32 key, UInt32 value) | ||
55 | { | ||
56 | if (Nodes.Size() == 0) | ||
57 | { | ||
58 | CNode n; | ||
59 | n.Key = n.Keys[0] = n.Keys[1] = key; | ||
60 | n.Values[0] = n.Values[1] = value; | ||
61 | n.IsLeaf[0] = n.IsLeaf[1] = 1; | ||
62 | n.Len = kNumBitsMax; | ||
63 | Nodes.Add(n); | ||
64 | return false; | ||
65 | } | ||
66 | if (Nodes.Size() == 1) | ||
67 | { | ||
68 | CNode &n = Nodes[0]; | ||
69 | if (n.Len == kNumBitsMax) | ||
70 | { | ||
71 | if (key == n.Key) | ||
72 | { | ||
73 | n.Values[0] = n.Values[1] = value; | ||
74 | return true; | ||
75 | } | ||
76 | unsigned i = kNumBitsMax - 1; | ||
77 | for (; GetSubBit(key, i) == GetSubBit(n.Key, i); i--); | ||
78 | n.Len = (UInt16)(kNumBitsMax - (1 + i)); | ||
79 | unsigned newBit = GetSubBit(key, i); | ||
80 | n.Values[newBit] = value; | ||
81 | n.Keys[newBit] = key; | ||
82 | return false; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | unsigned cur = 0; | ||
87 | unsigned bitPos = kNumBitsMax; | ||
88 | for (;;) | ||
89 | { | ||
90 | CNode &n = Nodes[cur]; | ||
91 | bitPos -= n.Len; | ||
92 | if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len)) | ||
93 | { | ||
94 | unsigned i = n.Len - 1; | ||
95 | for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--); | ||
96 | |||
97 | CNode e2(n); | ||
98 | e2.Len = (UInt16)i; | ||
99 | |||
100 | n.Len = (UInt16)(n.Len - (1 + i)); | ||
101 | unsigned newBit = GetSubBit(key, bitPos + i); | ||
102 | n.Values[newBit] = value; | ||
103 | n.IsLeaf[newBit] = 1; | ||
104 | n.IsLeaf[1 - newBit] = 0; | ||
105 | n.Keys[newBit] = key; | ||
106 | n.Keys[1 - newBit] = Nodes.Size(); | ||
107 | Nodes.Add(e2); | ||
108 | return false; | ||
109 | } | ||
110 | unsigned bit = GetSubBit(key, --bitPos); | ||
111 | |||
112 | if (n.IsLeaf[bit]) | ||
113 | { | ||
114 | if (key == n.Keys[bit]) | ||
115 | { | ||
116 | n.Values[bit] = value; | ||
117 | return true; | ||
118 | } | ||
119 | unsigned i = bitPos - 1; | ||
120 | for (; GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--); | ||
121 | |||
122 | CNode e2; | ||
123 | |||
124 | unsigned newBit = GetSubBit(key, i); | ||
125 | e2.Values[newBit] = value; | ||
126 | e2.Values[1 - newBit] = n.Values[bit]; | ||
127 | e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1; | ||
128 | e2.Keys[newBit] = key; | ||
129 | e2.Keys[1 - newBit] = e2.Key = n.Keys[bit]; | ||
130 | e2.Len = (UInt16)(bitPos - (1 + i)); | ||
131 | |||
132 | n.IsLeaf[bit] = 0; | ||
133 | n.Keys[bit] = Nodes.Size(); | ||
134 | |||
135 | Nodes.Add(e2); | ||
136 | return false; | ||
137 | } | ||
138 | cur = (unsigned)n.Keys[bit]; | ||
139 | } | ||
140 | } | ||
diff --git a/CPP/Common/MyMap.h b/CPP/Common/MyMap.h new file mode 100644 index 0000000..cbcbadd --- /dev/null +++ b/CPP/Common/MyMap.h | |||
@@ -0,0 +1,28 @@ | |||
1 | // MyMap.h | ||
2 | |||
3 | #ifndef __COMMON_MYMAP_H | ||
4 | #define __COMMON_MYMAP_H | ||
5 | |||
6 | #include "MyTypes.h" | ||
7 | #include "MyVector.h" | ||
8 | |||
9 | class CMap32 | ||
10 | { | ||
11 | struct CNode | ||
12 | { | ||
13 | UInt32 Key; | ||
14 | UInt32 Keys[2]; | ||
15 | UInt32 Values[2]; | ||
16 | UInt16 Len; | ||
17 | Byte IsLeaf[2]; | ||
18 | }; | ||
19 | CRecordVector<CNode> Nodes; | ||
20 | |||
21 | public: | ||
22 | |||
23 | void Clear() { Nodes.Clear(); } | ||
24 | bool Find(UInt32 key, UInt32 &valueRes) const throw(); | ||
25 | bool Set(UInt32 key, UInt32 value); // returns true, if there is such key already | ||
26 | }; | ||
27 | |||
28 | #endif | ||
diff --git a/CPP/Common/MyString.cpp b/CPP/Common/MyString.cpp new file mode 100644 index 0000000..db202f4 --- /dev/null +++ b/CPP/Common/MyString.cpp | |||
@@ -0,0 +1,1756 @@ | |||
1 | // Common/MyString.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #ifdef _WIN32 | ||
6 | #include <wchar.h> | ||
7 | #else | ||
8 | #include <ctype.h> | ||
9 | #endif | ||
10 | |||
11 | #include "IntToString.h" | ||
12 | |||
13 | #if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING) | ||
14 | #include "StringConvert.h" | ||
15 | #endif | ||
16 | |||
17 | #include "MyString.h" | ||
18 | |||
19 | #define MY_STRING_NEW(_T_, _size_) new _T_[_size_] | ||
20 | // #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_))) | ||
21 | |||
22 | /* | ||
23 | inline const char* MyStringGetNextCharPointer(const char *p) throw() | ||
24 | { | ||
25 | #if defined(_WIN32) && !defined(UNDER_CE) | ||
26 | return CharNextA(p); | ||
27 | #else | ||
28 | return p + 1; | ||
29 | #endif | ||
30 | } | ||
31 | */ | ||
32 | |||
33 | #define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, _size_) | ||
34 | #define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, _size_) | ||
35 | |||
36 | |||
37 | int FindCharPosInString(const char *s, char c) throw() | ||
38 | { | ||
39 | for (const char *p = s;; p++) | ||
40 | { | ||
41 | if (*p == c) | ||
42 | return (int)(p - s); | ||
43 | if (*p == 0) | ||
44 | return -1; | ||
45 | // MyStringGetNextCharPointer(p); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | int FindCharPosInString(const wchar_t *s, wchar_t c) throw() | ||
50 | { | ||
51 | for (const wchar_t *p = s;; p++) | ||
52 | { | ||
53 | if (*p == c) | ||
54 | return (int)(p - s); | ||
55 | if (*p == 0) | ||
56 | return -1; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | void MyStringUpper_Ascii(char *s) throw() | ||
62 | { | ||
63 | for (;;) | ||
64 | { | ||
65 | char c = *s; | ||
66 | if (c == 0) | ||
67 | return; | ||
68 | *s++ = MyCharUpper_Ascii(c); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | void MyStringUpper_Ascii(wchar_t *s) throw() | ||
73 | { | ||
74 | for (;;) | ||
75 | { | ||
76 | wchar_t c = *s; | ||
77 | if (c == 0) | ||
78 | return; | ||
79 | *s++ = MyCharUpper_Ascii(c); | ||
80 | } | ||
81 | } | ||
82 | */ | ||
83 | |||
84 | void MyStringLower_Ascii(char *s) throw() | ||
85 | { | ||
86 | for (;;) | ||
87 | { | ||
88 | char c = *s; | ||
89 | if (c == 0) | ||
90 | return; | ||
91 | *s++ = MyCharLower_Ascii(c); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | void MyStringLower_Ascii(wchar_t *s) throw() | ||
96 | { | ||
97 | for (;;) | ||
98 | { | ||
99 | wchar_t c = *s; | ||
100 | if (c == 0) | ||
101 | return; | ||
102 | *s++ = MyCharLower_Ascii(c); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | #ifdef _WIN32 | ||
107 | |||
108 | #ifdef _UNICODE | ||
109 | |||
110 | // wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); } | ||
111 | // wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); } | ||
112 | // for WinCE - FString - char | ||
113 | // const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; } | ||
114 | |||
115 | #else | ||
116 | |||
117 | // const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); } | ||
118 | // char * MyStringUpper(char *s) { return CharUpperA(s); } | ||
119 | // char * MyStringLower(char *s) { return CharLowerA(s); } | ||
120 | |||
121 | wchar_t MyCharUpper_WIN(wchar_t c) throw() | ||
122 | { | ||
123 | wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); | ||
124 | if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | ||
125 | return (wchar_t)(unsigned)(UINT_PTR)res; | ||
126 | const int kBufSize = 4; | ||
127 | char s[kBufSize + 1]; | ||
128 | int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); | ||
129 | if (numChars == 0 || numChars > kBufSize) | ||
130 | return c; | ||
131 | s[numChars] = 0; | ||
132 | ::CharUpperA(s); | ||
133 | ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); | ||
134 | return c; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | wchar_t MyCharLower_WIN(wchar_t c) | ||
139 | { | ||
140 | wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); | ||
141 | if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | ||
142 | return (wchar_t)(unsigned)(UINT_PTR)res; | ||
143 | const int kBufSize = 4; | ||
144 | char s[kBufSize + 1]; | ||
145 | int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0); | ||
146 | if (numChars == 0 || numChars > kBufSize) | ||
147 | return c; | ||
148 | s[numChars] = 0; | ||
149 | ::CharLowerA(s); | ||
150 | ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); | ||
151 | return c; | ||
152 | } | ||
153 | */ | ||
154 | |||
155 | /* | ||
156 | wchar_t * MyStringUpper(wchar_t *s) | ||
157 | { | ||
158 | if (s == 0) | ||
159 | return 0; | ||
160 | wchar_t *res = CharUpperW(s); | ||
161 | if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | ||
162 | return res; | ||
163 | AString a = UnicodeStringToMultiByte(s); | ||
164 | a.MakeUpper(); | ||
165 | MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); | ||
166 | return s; | ||
167 | } | ||
168 | */ | ||
169 | |||
170 | /* | ||
171 | wchar_t * MyStringLower(wchar_t *s) | ||
172 | { | ||
173 | if (s == 0) | ||
174 | return 0; | ||
175 | wchar_t *res = CharLowerW(s); | ||
176 | if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) | ||
177 | return res; | ||
178 | AString a = UnicodeStringToMultiByte(s); | ||
179 | a.MakeLower(); | ||
180 | MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); | ||
181 | return s; | ||
182 | } | ||
183 | */ | ||
184 | |||
185 | #endif | ||
186 | |||
187 | #endif | ||
188 | |||
189 | bool IsString1PrefixedByString2(const char *s1, const char *s2) throw() | ||
190 | { | ||
191 | for (;;) | ||
192 | { | ||
193 | unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true; | ||
194 | unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw() | ||
199 | { | ||
200 | for (;;) | ||
201 | { | ||
202 | wchar_t c1 = *s1++; | ||
203 | wchar_t c2 = *s2++; | ||
204 | if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false; | ||
205 | if (c1 == 0) return true; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | // ---------- ASCII ---------- | ||
210 | |||
211 | bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() | ||
212 | { | ||
213 | const char *s1 = _chars; | ||
214 | for (;;) | ||
215 | { | ||
216 | char c2 = *s++; | ||
217 | if (c2 == 0) | ||
218 | return true; | ||
219 | char c1 = *s1++; | ||
220 | if (MyCharLower_Ascii(c1) != | ||
221 | MyCharLower_Ascii(c2)) | ||
222 | return false; | ||
223 | } | ||
224 | } | ||
225 | |||
226 | bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw() | ||
227 | { | ||
228 | const wchar_t *s1 = _chars; | ||
229 | for (;;) | ||
230 | { | ||
231 | char c2 = *s++; | ||
232 | if (c2 == 0) | ||
233 | return true; | ||
234 | wchar_t c1 = *s1++; | ||
235 | if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) | ||
236 | return false; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | bool StringsAreEqual_Ascii(const char *u, const char *a) throw() | ||
241 | { | ||
242 | for (;;) | ||
243 | { | ||
244 | char c = *a; | ||
245 | if (c != *u) | ||
246 | return false; | ||
247 | if (c == 0) | ||
248 | return true; | ||
249 | a++; | ||
250 | u++; | ||
251 | } | ||
252 | } | ||
253 | |||
254 | bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw() | ||
255 | { | ||
256 | for (;;) | ||
257 | { | ||
258 | unsigned char c = (unsigned char)*a; | ||
259 | if (c != *u) | ||
260 | return false; | ||
261 | if (c == 0) | ||
262 | return true; | ||
263 | a++; | ||
264 | u++; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw() | ||
269 | { | ||
270 | for (;;) | ||
271 | { | ||
272 | char c1 = *s1++; | ||
273 | char c2 = *s2++; | ||
274 | if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) | ||
275 | return false; | ||
276 | if (c1 == 0) | ||
277 | return true; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw() | ||
282 | { | ||
283 | for (;;) | ||
284 | { | ||
285 | wchar_t c1 = *s1++; | ||
286 | wchar_t c2 = *s2++; | ||
287 | if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) | ||
288 | return false; | ||
289 | if (c1 == 0) | ||
290 | return true; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw() | ||
295 | { | ||
296 | for (;;) | ||
297 | { | ||
298 | wchar_t c1 = *s1++; | ||
299 | char c2 = *s2++; | ||
300 | if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))) | ||
301 | return false; | ||
302 | if (c1 == 0) | ||
303 | return true; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw() | ||
308 | { | ||
309 | for (;;) | ||
310 | { | ||
311 | wchar_t c2 = *s2++; if (c2 == 0) return true; | ||
312 | wchar_t c1 = *s1++; if (c1 != c2) return false; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw() | ||
317 | { | ||
318 | for (;;) | ||
319 | { | ||
320 | unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true; | ||
321 | wchar_t c1 = *s1++; if (c1 != c2) return false; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw() | ||
326 | { | ||
327 | for (;;) | ||
328 | { | ||
329 | char c2 = *s2++; if (c2 == 0) return true; | ||
330 | char c1 = *s1++; | ||
331 | if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) | ||
332 | return false; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *s1, const char *s2) throw() | ||
337 | { | ||
338 | for (;;) | ||
339 | { | ||
340 | char c2 = *s2++; if (c2 == 0) return true; | ||
341 | wchar_t c1 = *s1++; | ||
342 | if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)) | ||
343 | return false; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw() | ||
348 | { | ||
349 | for (;;) | ||
350 | { | ||
351 | wchar_t c2 = *s2++; if (c2 == 0) return true; | ||
352 | wchar_t c1 = *s1++; | ||
353 | if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) | ||
354 | return false; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | // NTFS order: uses upper case | ||
359 | int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw() | ||
360 | { | ||
361 | for (;;) | ||
362 | { | ||
363 | wchar_t c1 = *s1++; | ||
364 | wchar_t c2 = *s2++; | ||
365 | if (c1 != c2) | ||
366 | { | ||
367 | wchar_t u1 = MyCharUpper(c1); | ||
368 | wchar_t u2 = MyCharUpper(c2); | ||
369 | if (u1 < u2) return -1; | ||
370 | if (u1 > u2) return 1; | ||
371 | } | ||
372 | if (c1 == 0) return 0; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) | ||
378 | { | ||
379 | for (; num != 0; num--) | ||
380 | { | ||
381 | wchar_t c1 = *s1++; | ||
382 | wchar_t c2 = *s2++; | ||
383 | if (c1 != c2) | ||
384 | { | ||
385 | wchar_t u1 = MyCharUpper(c1); | ||
386 | wchar_t u2 = MyCharUpper(c2); | ||
387 | if (u1 < u2) return -1; | ||
388 | if (u1 > u2) return 1; | ||
389 | } | ||
390 | if (c1 == 0) return 0; | ||
391 | } | ||
392 | return 0; | ||
393 | } | ||
394 | */ | ||
395 | |||
396 | // ---------- AString ---------- | ||
397 | |||
398 | void AString::InsertSpace(unsigned &index, unsigned size) | ||
399 | { | ||
400 | Grow(size); | ||
401 | MoveItems(index + size, index); | ||
402 | } | ||
403 | |||
404 | #define k_Alloc_Len_Limit 0x40000000 | ||
405 | |||
406 | void AString::ReAlloc(unsigned newLimit) | ||
407 | { | ||
408 | if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130220; | ||
409 | // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1); | ||
410 | char *newBuf = MY_STRING_NEW_char(newLimit + 1); | ||
411 | memcpy(newBuf, _chars, (size_t)(_len + 1)); | ||
412 | MY_STRING_DELETE(_chars); | ||
413 | _chars = newBuf; | ||
414 | _limit = newLimit; | ||
415 | } | ||
416 | |||
417 | void AString::ReAlloc2(unsigned newLimit) | ||
418 | { | ||
419 | if (newLimit >= k_Alloc_Len_Limit) throw 20130220; | ||
420 | // MY_STRING_REALLOC(_chars, char, newLimit + 1, 0); | ||
421 | char *newBuf = MY_STRING_NEW_char(newLimit + 1); | ||
422 | newBuf[0] = 0; | ||
423 | MY_STRING_DELETE(_chars); | ||
424 | _chars = newBuf; | ||
425 | _limit = newLimit; | ||
426 | } | ||
427 | |||
428 | void AString::SetStartLen(unsigned len) | ||
429 | { | ||
430 | _chars = 0; | ||
431 | _chars = MY_STRING_NEW_char(len + 1); | ||
432 | _len = len; | ||
433 | _limit = len; | ||
434 | } | ||
435 | |||
436 | void AString::Grow_1() | ||
437 | { | ||
438 | unsigned next = _len; | ||
439 | next += next / 2; | ||
440 | next += 16; | ||
441 | next &= ~(unsigned)15; | ||
442 | ReAlloc(next - 1); | ||
443 | } | ||
444 | |||
445 | void AString::Grow(unsigned n) | ||
446 | { | ||
447 | unsigned freeSize = _limit - _len; | ||
448 | if (n <= freeSize) | ||
449 | return; | ||
450 | |||
451 | unsigned next = _len + n; | ||
452 | next += next / 2; | ||
453 | next += 16; | ||
454 | next &= ~(unsigned)15; | ||
455 | ReAlloc(next - 1); | ||
456 | } | ||
457 | |||
458 | AString::AString(unsigned num, const char *s) | ||
459 | { | ||
460 | unsigned len = MyStringLen(s); | ||
461 | if (num > len) | ||
462 | num = len; | ||
463 | SetStartLen(num); | ||
464 | memcpy(_chars, s, num); | ||
465 | _chars[num] = 0; | ||
466 | } | ||
467 | |||
468 | AString::AString(unsigned num, const AString &s) | ||
469 | { | ||
470 | if (num > s._len) | ||
471 | num = s._len; | ||
472 | SetStartLen(num); | ||
473 | memcpy(_chars, s._chars, num); | ||
474 | _chars[num] = 0; | ||
475 | } | ||
476 | |||
477 | AString::AString(const AString &s, char c) | ||
478 | { | ||
479 | SetStartLen(s.Len() + 1); | ||
480 | char *chars = _chars; | ||
481 | unsigned len = s.Len(); | ||
482 | memcpy(chars, s, len); | ||
483 | chars[len] = c; | ||
484 | chars[(size_t)len + 1] = 0; | ||
485 | } | ||
486 | |||
487 | AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2) | ||
488 | { | ||
489 | SetStartLen(num1 + num2); | ||
490 | char *chars = _chars; | ||
491 | memcpy(chars, s1, num1); | ||
492 | memcpy(chars + num1, s2, num2 + 1); | ||
493 | } | ||
494 | |||
495 | AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); } | ||
496 | AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); } | ||
497 | AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); } | ||
498 | |||
499 | static const unsigned kStartStringCapacity = 4; | ||
500 | |||
501 | AString::AString() | ||
502 | { | ||
503 | _chars = 0; | ||
504 | _chars = MY_STRING_NEW_char(kStartStringCapacity); | ||
505 | _len = 0; | ||
506 | _limit = kStartStringCapacity - 1; | ||
507 | _chars[0] = 0; | ||
508 | } | ||
509 | |||
510 | AString::AString(char c) | ||
511 | { | ||
512 | SetStartLen(1); | ||
513 | char *chars = _chars; | ||
514 | chars[0] = c; | ||
515 | chars[1] = 0; | ||
516 | } | ||
517 | |||
518 | AString::AString(const char *s) | ||
519 | { | ||
520 | SetStartLen(MyStringLen(s)); | ||
521 | MyStringCopy(_chars, s); | ||
522 | } | ||
523 | |||
524 | AString::AString(const AString &s) | ||
525 | { | ||
526 | SetStartLen(s._len); | ||
527 | MyStringCopy(_chars, s._chars); | ||
528 | } | ||
529 | |||
530 | AString &AString::operator=(char c) | ||
531 | { | ||
532 | if (1 > _limit) | ||
533 | { | ||
534 | char *newBuf = MY_STRING_NEW_char(1 + 1); | ||
535 | MY_STRING_DELETE(_chars); | ||
536 | _chars = newBuf; | ||
537 | _limit = 1; | ||
538 | } | ||
539 | _len = 1; | ||
540 | char *chars = _chars; | ||
541 | chars[0] = c; | ||
542 | chars[1] = 0; | ||
543 | return *this; | ||
544 | } | ||
545 | |||
546 | AString &AString::operator=(const char *s) | ||
547 | { | ||
548 | unsigned len = MyStringLen(s); | ||
549 | if (len > _limit) | ||
550 | { | ||
551 | char *newBuf = MY_STRING_NEW_char(len + 1); | ||
552 | MY_STRING_DELETE(_chars); | ||
553 | _chars = newBuf; | ||
554 | _limit = len; | ||
555 | } | ||
556 | _len = len; | ||
557 | MyStringCopy(_chars, s); | ||
558 | return *this; | ||
559 | } | ||
560 | |||
561 | AString &AString::operator=(const AString &s) | ||
562 | { | ||
563 | if (&s == this) | ||
564 | return *this; | ||
565 | unsigned len = s._len; | ||
566 | if (len > _limit) | ||
567 | { | ||
568 | char *newBuf = MY_STRING_NEW_char(len + 1); | ||
569 | MY_STRING_DELETE(_chars); | ||
570 | _chars = newBuf; | ||
571 | _limit = len; | ||
572 | } | ||
573 | _len = len; | ||
574 | MyStringCopy(_chars, s._chars); | ||
575 | return *this; | ||
576 | } | ||
577 | |||
578 | void AString::SetFromWStr_if_Ascii(const wchar_t *s) | ||
579 | { | ||
580 | unsigned len = 0; | ||
581 | { | ||
582 | for (;; len++) | ||
583 | { | ||
584 | wchar_t c = s[len]; | ||
585 | if (c == 0) | ||
586 | break; | ||
587 | if (c >= 0x80) | ||
588 | return; | ||
589 | } | ||
590 | } | ||
591 | if (len > _limit) | ||
592 | { | ||
593 | char *newBuf = MY_STRING_NEW_char(len + 1); | ||
594 | MY_STRING_DELETE(_chars); | ||
595 | _chars = newBuf; | ||
596 | _limit = len; | ||
597 | } | ||
598 | _len = len; | ||
599 | char *dest = _chars; | ||
600 | unsigned i; | ||
601 | for (i = 0; i < len; i++) | ||
602 | dest[i] = (char)s[i]; | ||
603 | dest[i] = 0; | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | void AString::SetFromBstr_if_Ascii(BSTR s) | ||
608 | { | ||
609 | unsigned len = ::SysStringLen(s); | ||
610 | { | ||
611 | for (unsigned i = 0; i < len; i++) | ||
612 | if (s[i] <= 0 || s[i] >= 0x80) | ||
613 | return; | ||
614 | } | ||
615 | if (len > _limit) | ||
616 | { | ||
617 | char *newBuf = MY_STRING_NEW_char(len + 1); | ||
618 | MY_STRING_DELETE(_chars); | ||
619 | _chars = newBuf; | ||
620 | _limit = len; | ||
621 | } | ||
622 | _len = len; | ||
623 | char *dest = _chars; | ||
624 | unsigned i; | ||
625 | for (i = 0; i < len; i++) | ||
626 | dest[i] = (char)s[i]; | ||
627 | dest[i] = 0; | ||
628 | } | ||
629 | */ | ||
630 | |||
631 | void AString::Add_Space() { operator+=(' '); } | ||
632 | void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } | ||
633 | void AString::Add_LF() { operator+=('\n'); } | ||
634 | |||
635 | AString &AString::operator+=(const char *s) | ||
636 | { | ||
637 | unsigned len = MyStringLen(s); | ||
638 | Grow(len); | ||
639 | MyStringCopy(_chars + _len, s); | ||
640 | _len += len; | ||
641 | return *this; | ||
642 | } | ||
643 | |||
644 | void AString::Add_OptSpaced(const char *s) | ||
645 | { | ||
646 | Add_Space_if_NotEmpty(); | ||
647 | (*this) += s; | ||
648 | } | ||
649 | |||
650 | AString &AString::operator+=(const AString &s) | ||
651 | { | ||
652 | Grow(s._len); | ||
653 | MyStringCopy(_chars + _len, s._chars); | ||
654 | _len += s._len; | ||
655 | return *this; | ||
656 | } | ||
657 | |||
658 | void AString::Add_UInt32(UInt32 v) | ||
659 | { | ||
660 | Grow(10); | ||
661 | _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars); | ||
662 | } | ||
663 | |||
664 | void UString::Add_UInt64(UInt64 v) | ||
665 | { | ||
666 | Grow(20); | ||
667 | _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); | ||
668 | } | ||
669 | |||
670 | void AString::SetFrom(const char *s, unsigned len) // no check | ||
671 | { | ||
672 | if (len > _limit) | ||
673 | { | ||
674 | char *newBuf = MY_STRING_NEW_char(len + 1); | ||
675 | MY_STRING_DELETE(_chars); | ||
676 | _chars = newBuf; | ||
677 | _limit = len; | ||
678 | } | ||
679 | if (len != 0) | ||
680 | memcpy(_chars, s, len); | ||
681 | _chars[len] = 0; | ||
682 | _len = len; | ||
683 | } | ||
684 | |||
685 | void AString::SetFrom_CalcLen(const char *s, unsigned len) // no check | ||
686 | { | ||
687 | unsigned i; | ||
688 | for (i = 0; i < len; i++) | ||
689 | if (s[i] == 0) | ||
690 | break; | ||
691 | SetFrom(s, i); | ||
692 | } | ||
693 | |||
694 | int AString::Find(const char *s, unsigned startIndex) const throw() | ||
695 | { | ||
696 | const char *fs = strstr(_chars + startIndex, s); | ||
697 | if (!fs) | ||
698 | return -1; | ||
699 | return (int)(fs - _chars); | ||
700 | |||
701 | /* | ||
702 | if (s[0] == 0) | ||
703 | return startIndex; | ||
704 | unsigned len = MyStringLen(s); | ||
705 | const char *p = _chars + startIndex; | ||
706 | for (;; p++) | ||
707 | { | ||
708 | const char c = *p; | ||
709 | if (c != s[0]) | ||
710 | { | ||
711 | if (c == 0) | ||
712 | return -1; | ||
713 | continue; | ||
714 | } | ||
715 | unsigned i; | ||
716 | for (i = 1; i < len; i++) | ||
717 | if (p[i] != s[i]) | ||
718 | break; | ||
719 | if (i == len) | ||
720 | return (int)(p - _chars); | ||
721 | } | ||
722 | */ | ||
723 | } | ||
724 | |||
725 | int AString::ReverseFind(char c) const throw() | ||
726 | { | ||
727 | if (_len == 0) | ||
728 | return -1; | ||
729 | const char *p = _chars + _len - 1; | ||
730 | for (;;) | ||
731 | { | ||
732 | if (*p == c) | ||
733 | return (int)(p - _chars); | ||
734 | if (p == _chars) | ||
735 | return -1; | ||
736 | p--; // p = GetPrevCharPointer(_chars, p); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | int AString::ReverseFind_PathSepar() const throw() | ||
741 | { | ||
742 | if (_len == 0) | ||
743 | return -1; | ||
744 | const char *p = _chars + _len - 1; | ||
745 | for (;;) | ||
746 | { | ||
747 | char c = *p; | ||
748 | if (IS_PATH_SEPAR(c)) | ||
749 | return (int)(p - _chars); | ||
750 | if (p == _chars) | ||
751 | return -1; | ||
752 | p--; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | void AString::TrimLeft() throw() | ||
757 | { | ||
758 | const char *p = _chars; | ||
759 | for (;; p++) | ||
760 | { | ||
761 | char c = *p; | ||
762 | if (c != ' ' && c != '\n' && c != '\t') | ||
763 | break; | ||
764 | } | ||
765 | unsigned pos = (unsigned)(p - _chars); | ||
766 | if (pos != 0) | ||
767 | { | ||
768 | MoveItems(0, pos); | ||
769 | _len -= pos; | ||
770 | } | ||
771 | } | ||
772 | |||
773 | void AString::TrimRight() throw() | ||
774 | { | ||
775 | const char *p = _chars; | ||
776 | unsigned i; | ||
777 | for (i = _len; i != 0; i--) | ||
778 | { | ||
779 | char c = p[(size_t)i - 1]; | ||
780 | if (c != ' ' && c != '\n' && c != '\t') | ||
781 | break; | ||
782 | } | ||
783 | if (i != _len) | ||
784 | { | ||
785 | _chars[i] = 0; | ||
786 | _len = i; | ||
787 | } | ||
788 | } | ||
789 | |||
790 | void AString::InsertAtFront(char c) | ||
791 | { | ||
792 | if (_limit == _len) | ||
793 | Grow_1(); | ||
794 | MoveItems(1, 0); | ||
795 | _chars[0] = c; | ||
796 | _len++; | ||
797 | } | ||
798 | |||
799 | /* | ||
800 | void AString::Insert(unsigned index, char c) | ||
801 | { | ||
802 | InsertSpace(index, 1); | ||
803 | _chars[index] = c; | ||
804 | _len++; | ||
805 | } | ||
806 | */ | ||
807 | |||
808 | void AString::Insert(unsigned index, const char *s) | ||
809 | { | ||
810 | unsigned num = MyStringLen(s); | ||
811 | if (num != 0) | ||
812 | { | ||
813 | InsertSpace(index, num); | ||
814 | memcpy(_chars + index, s, num); | ||
815 | _len += num; | ||
816 | } | ||
817 | } | ||
818 | |||
819 | void AString::Insert(unsigned index, const AString &s) | ||
820 | { | ||
821 | unsigned num = s.Len(); | ||
822 | if (num != 0) | ||
823 | { | ||
824 | InsertSpace(index, num); | ||
825 | memcpy(_chars + index, s, num); | ||
826 | _len += num; | ||
827 | } | ||
828 | } | ||
829 | |||
830 | void AString::RemoveChar(char ch) throw() | ||
831 | { | ||
832 | char *src = _chars; | ||
833 | |||
834 | for (;;) | ||
835 | { | ||
836 | char c = *src++; | ||
837 | if (c == 0) | ||
838 | return; | ||
839 | if (c == ch) | ||
840 | break; | ||
841 | } | ||
842 | |||
843 | char *dest = src - 1; | ||
844 | |||
845 | for (;;) | ||
846 | { | ||
847 | char c = *src++; | ||
848 | if (c == 0) | ||
849 | break; | ||
850 | if (c != ch) | ||
851 | *dest++ = c; | ||
852 | } | ||
853 | |||
854 | *dest = 0; | ||
855 | _len = (unsigned)(dest - _chars); | ||
856 | } | ||
857 | |||
858 | // !!!!!!!!!!!!!!! test it if newChar = '\0' | ||
859 | void AString::Replace(char oldChar, char newChar) throw() | ||
860 | { | ||
861 | if (oldChar == newChar) | ||
862 | return; // 0; | ||
863 | // unsigned number = 0; | ||
864 | int pos = 0; | ||
865 | char *chars = _chars; | ||
866 | while ((unsigned)pos < _len) | ||
867 | { | ||
868 | pos = Find(oldChar, (unsigned)pos); | ||
869 | if (pos < 0) | ||
870 | break; | ||
871 | chars[(unsigned)pos] = newChar; | ||
872 | pos++; | ||
873 | // number++; | ||
874 | } | ||
875 | return; // number; | ||
876 | } | ||
877 | |||
878 | void AString::Replace(const AString &oldString, const AString &newString) | ||
879 | { | ||
880 | if (oldString.IsEmpty()) | ||
881 | return; // 0; | ||
882 | if (oldString == newString) | ||
883 | return; // 0; | ||
884 | unsigned oldLen = oldString.Len(); | ||
885 | unsigned newLen = newString.Len(); | ||
886 | // unsigned number = 0; | ||
887 | int pos = 0; | ||
888 | while ((unsigned)pos < _len) | ||
889 | { | ||
890 | pos = Find(oldString, (unsigned)pos); | ||
891 | if (pos < 0) | ||
892 | break; | ||
893 | Delete((unsigned)pos, oldLen); | ||
894 | Insert((unsigned)pos, newString); | ||
895 | pos += newLen; | ||
896 | // number++; | ||
897 | } | ||
898 | // return number; | ||
899 | } | ||
900 | |||
901 | void AString::Delete(unsigned index) throw() | ||
902 | { | ||
903 | MoveItems(index, index + 1); | ||
904 | _len--; | ||
905 | } | ||
906 | |||
907 | void AString::Delete(unsigned index, unsigned count) throw() | ||
908 | { | ||
909 | if (index + count > _len) | ||
910 | count = _len - index; | ||
911 | if (count > 0) | ||
912 | { | ||
913 | MoveItems(index, index + count); | ||
914 | _len -= count; | ||
915 | } | ||
916 | } | ||
917 | |||
918 | void AString::DeleteFrontal(unsigned num) throw() | ||
919 | { | ||
920 | if (num != 0) | ||
921 | { | ||
922 | MoveItems(0, num); | ||
923 | _len -= num; | ||
924 | } | ||
925 | } | ||
926 | |||
927 | /* | ||
928 | AString operator+(const AString &s1, const AString &s2) | ||
929 | { | ||
930 | AString result(s1); | ||
931 | result += s2; | ||
932 | return result; | ||
933 | } | ||
934 | |||
935 | AString operator+(const AString &s, const char *chars) | ||
936 | { | ||
937 | AString result(s); | ||
938 | result += chars; | ||
939 | return result; | ||
940 | } | ||
941 | |||
942 | AString operator+(const char *chars, const AString &s) | ||
943 | { | ||
944 | AString result(chars); | ||
945 | result += s; | ||
946 | return result; | ||
947 | } | ||
948 | |||
949 | AString operator+(const AString &s, char c) | ||
950 | { | ||
951 | AString result(s); | ||
952 | result += c; | ||
953 | return result; | ||
954 | } | ||
955 | */ | ||
956 | |||
957 | /* | ||
958 | AString operator+(char c, const AString &s) | ||
959 | { | ||
960 | AString result(c); | ||
961 | result += s; | ||
962 | return result; | ||
963 | } | ||
964 | */ | ||
965 | |||
966 | |||
967 | |||
968 | |||
969 | // ---------- UString ---------- | ||
970 | |||
971 | void UString::InsertSpace(unsigned index, unsigned size) | ||
972 | { | ||
973 | Grow(size); | ||
974 | MoveItems(index + size, index); | ||
975 | } | ||
976 | |||
977 | void UString::ReAlloc(unsigned newLimit) | ||
978 | { | ||
979 | if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130221; | ||
980 | // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1); | ||
981 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1); | ||
982 | wmemcpy(newBuf, _chars, _len + 1); | ||
983 | MY_STRING_DELETE(_chars); | ||
984 | _chars = newBuf; | ||
985 | _limit = newLimit; | ||
986 | } | ||
987 | |||
988 | void UString::ReAlloc2(unsigned newLimit) | ||
989 | { | ||
990 | if (newLimit >= k_Alloc_Len_Limit) throw 20130221; | ||
991 | // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); | ||
992 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1); | ||
993 | newBuf[0] = 0; | ||
994 | MY_STRING_DELETE(_chars); | ||
995 | _chars = newBuf; | ||
996 | _limit = newLimit; | ||
997 | } | ||
998 | |||
999 | void UString::SetStartLen(unsigned len) | ||
1000 | { | ||
1001 | _chars = 0; | ||
1002 | _chars = MY_STRING_NEW_wchar_t(len + 1); | ||
1003 | _len = len; | ||
1004 | _limit = len; | ||
1005 | } | ||
1006 | |||
1007 | void UString::Grow_1() | ||
1008 | { | ||
1009 | unsigned next = _len; | ||
1010 | next += next / 2; | ||
1011 | next += 16; | ||
1012 | next &= ~(unsigned)15; | ||
1013 | ReAlloc(next - 1); | ||
1014 | } | ||
1015 | |||
1016 | void UString::Grow(unsigned n) | ||
1017 | { | ||
1018 | unsigned freeSize = _limit - _len; | ||
1019 | if (n <= freeSize) | ||
1020 | return; | ||
1021 | |||
1022 | unsigned next = _len + n; | ||
1023 | next += next / 2; | ||
1024 | next += 16; | ||
1025 | next &= ~(unsigned)15; | ||
1026 | ReAlloc(next - 1); | ||
1027 | } | ||
1028 | |||
1029 | |||
1030 | UString::UString(unsigned num, const wchar_t *s) | ||
1031 | { | ||
1032 | unsigned len = MyStringLen(s); | ||
1033 | if (num > len) | ||
1034 | num = len; | ||
1035 | SetStartLen(num); | ||
1036 | wmemcpy(_chars, s, num); | ||
1037 | _chars[num] = 0; | ||
1038 | } | ||
1039 | |||
1040 | |||
1041 | UString::UString(unsigned num, const UString &s) | ||
1042 | { | ||
1043 | if (num > s._len) | ||
1044 | num = s._len; | ||
1045 | SetStartLen(num); | ||
1046 | wmemcpy(_chars, s._chars, num); | ||
1047 | _chars[num] = 0; | ||
1048 | } | ||
1049 | |||
1050 | UString::UString(const UString &s, wchar_t c) | ||
1051 | { | ||
1052 | SetStartLen(s.Len() + 1); | ||
1053 | wchar_t *chars = _chars; | ||
1054 | unsigned len = s.Len(); | ||
1055 | wmemcpy(chars, s, len); | ||
1056 | chars[len] = c; | ||
1057 | chars[(size_t)len + 1] = 0; | ||
1058 | } | ||
1059 | |||
1060 | UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2) | ||
1061 | { | ||
1062 | SetStartLen(num1 + num2); | ||
1063 | wchar_t *chars = _chars; | ||
1064 | wmemcpy(chars, s1, num1); | ||
1065 | wmemcpy(chars + num1, s2, num2 + 1); | ||
1066 | } | ||
1067 | |||
1068 | UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); } | ||
1069 | UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); } | ||
1070 | UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); } | ||
1071 | |||
1072 | UString::UString() | ||
1073 | { | ||
1074 | _chars = 0; | ||
1075 | _chars = MY_STRING_NEW_wchar_t(kStartStringCapacity); | ||
1076 | _len = 0; | ||
1077 | _limit = kStartStringCapacity - 1; | ||
1078 | _chars[0] = 0; | ||
1079 | } | ||
1080 | |||
1081 | UString::UString(wchar_t c) | ||
1082 | { | ||
1083 | SetStartLen(1); | ||
1084 | wchar_t *chars = _chars; | ||
1085 | chars[0] = c; | ||
1086 | chars[1] = 0; | ||
1087 | } | ||
1088 | |||
1089 | UString::UString(char c) | ||
1090 | { | ||
1091 | SetStartLen(1); | ||
1092 | wchar_t *chars = _chars; | ||
1093 | chars[0] = (unsigned char)c; | ||
1094 | chars[1] = 0; | ||
1095 | } | ||
1096 | |||
1097 | UString::UString(const wchar_t *s) | ||
1098 | { | ||
1099 | const unsigned len = MyStringLen(s); | ||
1100 | SetStartLen(len); | ||
1101 | wmemcpy(_chars, s, len + 1); | ||
1102 | } | ||
1103 | |||
1104 | UString::UString(const char *s) | ||
1105 | { | ||
1106 | const unsigned len = MyStringLen(s); | ||
1107 | SetStartLen(len); | ||
1108 | wchar_t *chars = _chars; | ||
1109 | for (unsigned i = 0; i < len; i++) | ||
1110 | chars[i] = (unsigned char)s[i]; | ||
1111 | chars[len] = 0; | ||
1112 | } | ||
1113 | |||
1114 | UString::UString(const AString &s) | ||
1115 | { | ||
1116 | const unsigned len = s.Len(); | ||
1117 | SetStartLen(len); | ||
1118 | wchar_t *chars = _chars; | ||
1119 | const char *s2 = s.Ptr(); | ||
1120 | for (unsigned i = 0; i < len; i++) | ||
1121 | chars[i] = (unsigned char)s2[i]; | ||
1122 | chars[len] = 0; | ||
1123 | } | ||
1124 | |||
1125 | UString::UString(const UString &s) | ||
1126 | { | ||
1127 | SetStartLen(s._len); | ||
1128 | wmemcpy(_chars, s._chars, s._len + 1); | ||
1129 | } | ||
1130 | |||
1131 | UString &UString::operator=(wchar_t c) | ||
1132 | { | ||
1133 | if (1 > _limit) | ||
1134 | { | ||
1135 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1); | ||
1136 | MY_STRING_DELETE(_chars); | ||
1137 | _chars = newBuf; | ||
1138 | _limit = 1; | ||
1139 | } | ||
1140 | _len = 1; | ||
1141 | wchar_t *chars = _chars; | ||
1142 | chars[0] = c; | ||
1143 | chars[1] = 0; | ||
1144 | return *this; | ||
1145 | } | ||
1146 | |||
1147 | UString &UString::operator=(const wchar_t *s) | ||
1148 | { | ||
1149 | unsigned len = MyStringLen(s); | ||
1150 | if (len > _limit) | ||
1151 | { | ||
1152 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1153 | MY_STRING_DELETE(_chars); | ||
1154 | _chars = newBuf; | ||
1155 | _limit = len; | ||
1156 | } | ||
1157 | _len = len; | ||
1158 | wmemcpy(_chars, s, len + 1); | ||
1159 | return *this; | ||
1160 | } | ||
1161 | |||
1162 | UString &UString::operator=(const UString &s) | ||
1163 | { | ||
1164 | if (&s == this) | ||
1165 | return *this; | ||
1166 | unsigned len = s._len; | ||
1167 | if (len > _limit) | ||
1168 | { | ||
1169 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1170 | MY_STRING_DELETE(_chars); | ||
1171 | _chars = newBuf; | ||
1172 | _limit = len; | ||
1173 | } | ||
1174 | _len = len; | ||
1175 | wmemcpy(_chars, s._chars, len + 1); | ||
1176 | return *this; | ||
1177 | } | ||
1178 | |||
1179 | void UString::SetFrom(const wchar_t *s, unsigned len) // no check | ||
1180 | { | ||
1181 | if (len > _limit) | ||
1182 | { | ||
1183 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1184 | MY_STRING_DELETE(_chars); | ||
1185 | _chars = newBuf; | ||
1186 | _limit = len; | ||
1187 | } | ||
1188 | if (len != 0) | ||
1189 | wmemcpy(_chars, s, len); | ||
1190 | _chars[len] = 0; | ||
1191 | _len = len; | ||
1192 | } | ||
1193 | |||
1194 | void UString::SetFromBstr(LPCOLESTR s) | ||
1195 | { | ||
1196 | unsigned len = ::SysStringLen((BSTR)(void *)(s)); | ||
1197 | |||
1198 | /* | ||
1199 | #if WCHAR_MAX > 0xffff | ||
1200 | size_t num_wchars = 0; | ||
1201 | for (size_t i = 0; i < len;) | ||
1202 | { | ||
1203 | wchar_t c = s[i++]; | ||
1204 | if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) | ||
1205 | { | ||
1206 | wchar_t c2 = s[i]; | ||
1207 | if (c2 >= 0xdc00 && c2 < 0x10000) | ||
1208 | { | ||
1209 | c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); | ||
1210 | i++; | ||
1211 | } | ||
1212 | } | ||
1213 | num_wchars++; | ||
1214 | } | ||
1215 | len = num_wchars; | ||
1216 | #endif | ||
1217 | */ | ||
1218 | |||
1219 | if (len > _limit) | ||
1220 | { | ||
1221 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1222 | MY_STRING_DELETE(_chars); | ||
1223 | _chars = newBuf; | ||
1224 | _limit = len; | ||
1225 | } | ||
1226 | _len = len; | ||
1227 | |||
1228 | /* | ||
1229 | #if WCHAR_MAX > 0xffff | ||
1230 | |||
1231 | wchar_t *chars = _chars; | ||
1232 | for (size_t i = 0; i <= len; i++) | ||
1233 | { | ||
1234 | wchar_t c = *s++; | ||
1235 | if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) | ||
1236 | { | ||
1237 | wchar_t c2 = *s; | ||
1238 | if (c2 >= 0xdc00 && c2 < 0x10000) | ||
1239 | { | ||
1240 | s++; | ||
1241 | c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); | ||
1242 | } | ||
1243 | } | ||
1244 | chars[i] = c; | ||
1245 | } | ||
1246 | |||
1247 | #else | ||
1248 | */ | ||
1249 | |||
1250 | // if (s) | ||
1251 | wmemcpy(_chars, s, len + 1); | ||
1252 | |||
1253 | // #endif | ||
1254 | } | ||
1255 | |||
1256 | UString &UString::operator=(const char *s) | ||
1257 | { | ||
1258 | unsigned len = MyStringLen(s); | ||
1259 | if (len > _limit) | ||
1260 | { | ||
1261 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1262 | MY_STRING_DELETE(_chars); | ||
1263 | _chars = newBuf; | ||
1264 | _limit = len; | ||
1265 | } | ||
1266 | wchar_t *chars = _chars; | ||
1267 | for (unsigned i = 0; i < len; i++) | ||
1268 | chars[i] = (unsigned char)s[i]; | ||
1269 | chars[len] = 0; | ||
1270 | _len = len; | ||
1271 | return *this; | ||
1272 | } | ||
1273 | |||
1274 | void UString::Add_Space() { operator+=(L' '); } | ||
1275 | void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); } | ||
1276 | |||
1277 | void UString::Add_LF() | ||
1278 | { | ||
1279 | if (_limit == _len) | ||
1280 | Grow_1(); | ||
1281 | unsigned len = _len; | ||
1282 | wchar_t *chars = _chars; | ||
1283 | chars[len++] = L'\n'; | ||
1284 | chars[len] = 0; | ||
1285 | _len = len; | ||
1286 | } | ||
1287 | |||
1288 | UString &UString::operator+=(const wchar_t *s) | ||
1289 | { | ||
1290 | unsigned len = MyStringLen(s); | ||
1291 | Grow(len); | ||
1292 | wmemcpy(_chars + _len, s, len + 1); | ||
1293 | _len += len; | ||
1294 | return *this; | ||
1295 | } | ||
1296 | |||
1297 | UString &UString::operator+=(const UString &s) | ||
1298 | { | ||
1299 | Grow(s._len); | ||
1300 | wmemcpy(_chars + _len, s._chars, s._len + 1); | ||
1301 | _len += s._len; | ||
1302 | return *this; | ||
1303 | } | ||
1304 | |||
1305 | UString &UString::operator+=(const char *s) | ||
1306 | { | ||
1307 | unsigned len = MyStringLen(s); | ||
1308 | Grow(len); | ||
1309 | wchar_t *chars = _chars + _len; | ||
1310 | for (unsigned i = 0; i < len; i++) | ||
1311 | chars[i] = (unsigned char)s[i]; | ||
1312 | chars[len] = 0; | ||
1313 | _len += len; | ||
1314 | return *this; | ||
1315 | } | ||
1316 | |||
1317 | |||
1318 | void UString::Add_UInt32(UInt32 v) | ||
1319 | { | ||
1320 | Grow(10); | ||
1321 | _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars); | ||
1322 | } | ||
1323 | |||
1324 | void AString::Add_UInt64(UInt64 v) | ||
1325 | { | ||
1326 | Grow(20); | ||
1327 | _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars); | ||
1328 | } | ||
1329 | |||
1330 | |||
1331 | int UString::Find(const wchar_t *s, unsigned startIndex) const throw() | ||
1332 | { | ||
1333 | const wchar_t *fs = wcsstr(_chars + startIndex, s); | ||
1334 | if (!fs) | ||
1335 | return -1; | ||
1336 | return (int)(fs - _chars); | ||
1337 | |||
1338 | /* | ||
1339 | if (s[0] == 0) | ||
1340 | return startIndex; | ||
1341 | unsigned len = MyStringLen(s); | ||
1342 | const wchar_t *p = _chars + startIndex; | ||
1343 | for (;; p++) | ||
1344 | { | ||
1345 | const wchar_t c = *p; | ||
1346 | if (c != s[0]) | ||
1347 | { | ||
1348 | if (c == 0) | ||
1349 | return -1; | ||
1350 | continue; | ||
1351 | } | ||
1352 | unsigned i; | ||
1353 | for (i = 1; i < len; i++) | ||
1354 | if (p[i] != s[i]) | ||
1355 | break; | ||
1356 | if (i == len) | ||
1357 | return (int)(p - _chars); | ||
1358 | } | ||
1359 | */ | ||
1360 | } | ||
1361 | |||
1362 | int UString::ReverseFind(wchar_t c) const throw() | ||
1363 | { | ||
1364 | if (_len == 0) | ||
1365 | return -1; | ||
1366 | const wchar_t *p = _chars + _len - 1; | ||
1367 | for (;;) | ||
1368 | { | ||
1369 | if (*p == c) | ||
1370 | return (int)(p - _chars); | ||
1371 | if (p == _chars) | ||
1372 | return -1; | ||
1373 | p--; | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | int UString::ReverseFind_PathSepar() const throw() | ||
1378 | { | ||
1379 | if (_len == 0) | ||
1380 | return -1; | ||
1381 | const wchar_t *p = _chars + _len - 1; | ||
1382 | for (;;) | ||
1383 | { | ||
1384 | wchar_t c = *p; | ||
1385 | if (IS_PATH_SEPAR(c)) | ||
1386 | return (int)(p - _chars); | ||
1387 | if (p == _chars) | ||
1388 | return -1; | ||
1389 | p--; | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | void UString::TrimLeft() throw() | ||
1394 | { | ||
1395 | const wchar_t *p = _chars; | ||
1396 | for (;; p++) | ||
1397 | { | ||
1398 | wchar_t c = *p; | ||
1399 | if (c != ' ' && c != '\n' && c != '\t') | ||
1400 | break; | ||
1401 | } | ||
1402 | unsigned pos = (unsigned)(p - _chars); | ||
1403 | if (pos != 0) | ||
1404 | { | ||
1405 | MoveItems(0, pos); | ||
1406 | _len -= pos; | ||
1407 | } | ||
1408 | } | ||
1409 | |||
1410 | void UString::TrimRight() throw() | ||
1411 | { | ||
1412 | const wchar_t *p = _chars; | ||
1413 | unsigned i; | ||
1414 | for (i = _len; i != 0; i--) | ||
1415 | { | ||
1416 | wchar_t c = p[(size_t)i - 1]; | ||
1417 | if (c != ' ' && c != '\n' && c != '\t') | ||
1418 | break; | ||
1419 | } | ||
1420 | if (i != _len) | ||
1421 | { | ||
1422 | _chars[i] = 0; | ||
1423 | _len = i; | ||
1424 | } | ||
1425 | } | ||
1426 | |||
1427 | void UString::InsertAtFront(wchar_t c) | ||
1428 | { | ||
1429 | if (_limit == _len) | ||
1430 | Grow_1(); | ||
1431 | MoveItems(1, 0); | ||
1432 | _chars[0] = c; | ||
1433 | _len++; | ||
1434 | } | ||
1435 | |||
1436 | /* | ||
1437 | void UString::Insert_wchar_t(unsigned index, wchar_t c) | ||
1438 | { | ||
1439 | InsertSpace(index, 1); | ||
1440 | _chars[index] = c; | ||
1441 | _len++; | ||
1442 | } | ||
1443 | */ | ||
1444 | |||
1445 | void UString::Insert(unsigned index, const wchar_t *s) | ||
1446 | { | ||
1447 | unsigned num = MyStringLen(s); | ||
1448 | if (num != 0) | ||
1449 | { | ||
1450 | InsertSpace(index, num); | ||
1451 | wmemcpy(_chars + index, s, num); | ||
1452 | _len += num; | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | void UString::Insert(unsigned index, const UString &s) | ||
1457 | { | ||
1458 | unsigned num = s.Len(); | ||
1459 | if (num != 0) | ||
1460 | { | ||
1461 | InsertSpace(index, num); | ||
1462 | wmemcpy(_chars + index, s, num); | ||
1463 | _len += num; | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | void UString::RemoveChar(wchar_t ch) throw() | ||
1468 | { | ||
1469 | wchar_t *src = _chars; | ||
1470 | |||
1471 | for (;;) | ||
1472 | { | ||
1473 | wchar_t c = *src++; | ||
1474 | if (c == 0) | ||
1475 | return; | ||
1476 | if (c == ch) | ||
1477 | break; | ||
1478 | } | ||
1479 | |||
1480 | wchar_t *dest = src - 1; | ||
1481 | |||
1482 | for (;;) | ||
1483 | { | ||
1484 | wchar_t c = *src++; | ||
1485 | if (c == 0) | ||
1486 | break; | ||
1487 | if (c != ch) | ||
1488 | *dest++ = c; | ||
1489 | } | ||
1490 | |||
1491 | *dest = 0; | ||
1492 | _len = (unsigned)(dest - _chars); | ||
1493 | } | ||
1494 | |||
1495 | // !!!!!!!!!!!!!!! test it if newChar = '\0' | ||
1496 | void UString::Replace(wchar_t oldChar, wchar_t newChar) throw() | ||
1497 | { | ||
1498 | if (oldChar == newChar) | ||
1499 | return; // 0; | ||
1500 | // unsigned number = 0; | ||
1501 | int pos = 0; | ||
1502 | wchar_t *chars = _chars; | ||
1503 | while ((unsigned)pos < _len) | ||
1504 | { | ||
1505 | pos = Find(oldChar, (unsigned)pos); | ||
1506 | if (pos < 0) | ||
1507 | break; | ||
1508 | chars[(unsigned)pos] = newChar; | ||
1509 | pos++; | ||
1510 | // number++; | ||
1511 | } | ||
1512 | return; // number; | ||
1513 | } | ||
1514 | |||
1515 | void UString::Replace(const UString &oldString, const UString &newString) | ||
1516 | { | ||
1517 | if (oldString.IsEmpty()) | ||
1518 | return; // 0; | ||
1519 | if (oldString == newString) | ||
1520 | return; // 0; | ||
1521 | unsigned oldLen = oldString.Len(); | ||
1522 | unsigned newLen = newString.Len(); | ||
1523 | // unsigned number = 0; | ||
1524 | int pos = 0; | ||
1525 | while ((unsigned)pos < _len) | ||
1526 | { | ||
1527 | pos = Find(oldString, (unsigned)pos); | ||
1528 | if (pos < 0) | ||
1529 | break; | ||
1530 | Delete((unsigned)pos, oldLen); | ||
1531 | Insert((unsigned)pos, newString); | ||
1532 | pos += newLen; | ||
1533 | // number++; | ||
1534 | } | ||
1535 | // return number; | ||
1536 | } | ||
1537 | |||
1538 | void UString::Delete(unsigned index) throw() | ||
1539 | { | ||
1540 | MoveItems(index, index + 1); | ||
1541 | _len--; | ||
1542 | } | ||
1543 | |||
1544 | void UString::Delete(unsigned index, unsigned count) throw() | ||
1545 | { | ||
1546 | if (index + count > _len) | ||
1547 | count = _len - index; | ||
1548 | if (count > 0) | ||
1549 | { | ||
1550 | MoveItems(index, index + count); | ||
1551 | _len -= count; | ||
1552 | } | ||
1553 | } | ||
1554 | |||
1555 | void UString::DeleteFrontal(unsigned num) throw() | ||
1556 | { | ||
1557 | if (num != 0) | ||
1558 | { | ||
1559 | MoveItems(0, num); | ||
1560 | _len -= num; | ||
1561 | } | ||
1562 | } | ||
1563 | |||
1564 | |||
1565 | // ---------- UString2 ---------- | ||
1566 | |||
1567 | void UString2::ReAlloc2(unsigned newLimit) | ||
1568 | { | ||
1569 | if (newLimit >= k_Alloc_Len_Limit) throw 20130221; | ||
1570 | // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0); | ||
1571 | _chars = MY_STRING_NEW_wchar_t(newLimit + 1); | ||
1572 | } | ||
1573 | |||
1574 | void UString2::SetStartLen(unsigned len) | ||
1575 | { | ||
1576 | _chars = 0; | ||
1577 | _chars = MY_STRING_NEW_wchar_t(len + 1); | ||
1578 | _len = len; | ||
1579 | } | ||
1580 | |||
1581 | |||
1582 | /* | ||
1583 | UString2::UString2(wchar_t c) | ||
1584 | { | ||
1585 | SetStartLen(1); | ||
1586 | wchar_t *chars = _chars; | ||
1587 | chars[0] = c; | ||
1588 | chars[1] = 0; | ||
1589 | } | ||
1590 | */ | ||
1591 | |||
1592 | UString2::UString2(const wchar_t *s) | ||
1593 | { | ||
1594 | unsigned len = MyStringLen(s); | ||
1595 | SetStartLen(len); | ||
1596 | wmemcpy(_chars, s, len + 1); | ||
1597 | } | ||
1598 | |||
1599 | UString2::UString2(const UString2 &s): _chars(NULL), _len(0) | ||
1600 | { | ||
1601 | if (s._chars) | ||
1602 | { | ||
1603 | SetStartLen(s._len); | ||
1604 | wmemcpy(_chars, s._chars, s._len + 1); | ||
1605 | } | ||
1606 | } | ||
1607 | |||
1608 | /* | ||
1609 | UString2 &UString2::operator=(wchar_t c) | ||
1610 | { | ||
1611 | if (1 > _len) | ||
1612 | { | ||
1613 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1); | ||
1614 | if (_chars) | ||
1615 | MY_STRING_DELETE(_chars); | ||
1616 | _chars = newBuf; | ||
1617 | } | ||
1618 | _len = 1; | ||
1619 | wchar_t *chars = _chars; | ||
1620 | chars[0] = c; | ||
1621 | chars[1] = 0; | ||
1622 | return *this; | ||
1623 | } | ||
1624 | */ | ||
1625 | |||
1626 | UString2 &UString2::operator=(const wchar_t *s) | ||
1627 | { | ||
1628 | unsigned len = MyStringLen(s); | ||
1629 | if (len > _len) | ||
1630 | { | ||
1631 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1632 | if (_chars) | ||
1633 | MY_STRING_DELETE(_chars); | ||
1634 | _chars = newBuf; | ||
1635 | } | ||
1636 | _len = len; | ||
1637 | MyStringCopy(_chars, s); | ||
1638 | return *this; | ||
1639 | } | ||
1640 | |||
1641 | void UString2::SetFromAscii(const char *s) | ||
1642 | { | ||
1643 | unsigned len = MyStringLen(s); | ||
1644 | if (len > _len) | ||
1645 | { | ||
1646 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1647 | if (_chars) | ||
1648 | MY_STRING_DELETE(_chars); | ||
1649 | _chars = newBuf; | ||
1650 | } | ||
1651 | wchar_t *chars = _chars; | ||
1652 | for (unsigned i = 0; i < len; i++) | ||
1653 | chars[i] = (unsigned char)s[i]; | ||
1654 | chars[len] = 0; | ||
1655 | _len = len; | ||
1656 | } | ||
1657 | |||
1658 | UString2 &UString2::operator=(const UString2 &s) | ||
1659 | { | ||
1660 | if (&s == this) | ||
1661 | return *this; | ||
1662 | unsigned len = s._len; | ||
1663 | if (len > _len) | ||
1664 | { | ||
1665 | wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1); | ||
1666 | if (_chars) | ||
1667 | MY_STRING_DELETE(_chars); | ||
1668 | _chars = newBuf; | ||
1669 | } | ||
1670 | _len = len; | ||
1671 | MyStringCopy(_chars, s._chars); | ||
1672 | return *this; | ||
1673 | } | ||
1674 | |||
1675 | bool operator==(const UString2 &s1, const UString2 &s2) | ||
1676 | { | ||
1677 | return s1.Len() == s2.Len() && (s1.IsEmpty() || wcscmp(s1.GetRawPtr(), s2.GetRawPtr()) == 0); | ||
1678 | } | ||
1679 | |||
1680 | bool operator==(const UString2 &s1, const wchar_t *s2) | ||
1681 | { | ||
1682 | if (s1.IsEmpty()) | ||
1683 | return (*s2 == 0); | ||
1684 | return wcscmp(s1.GetRawPtr(), s2) == 0; | ||
1685 | } | ||
1686 | |||
1687 | bool operator==(const wchar_t *s1, const UString2 &s2) | ||
1688 | { | ||
1689 | if (s2.IsEmpty()) | ||
1690 | return (*s1 == 0); | ||
1691 | return wcscmp(s1, s2.GetRawPtr()) == 0; | ||
1692 | } | ||
1693 | |||
1694 | |||
1695 | |||
1696 | // ---------------------------------------- | ||
1697 | |||
1698 | /* | ||
1699 | int MyStringCompareNoCase(const char *s1, const char *s2) | ||
1700 | { | ||
1701 | return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2)); | ||
1702 | } | ||
1703 | */ | ||
1704 | |||
1705 | #if !defined(USE_UNICODE_FSTRING) || !defined(_UNICODE) | ||
1706 | |||
1707 | static inline UINT GetCurrentCodePage() | ||
1708 | { | ||
1709 | #if defined(UNDER_CE) || !defined(_WIN32) | ||
1710 | return CP_ACP; | ||
1711 | #else | ||
1712 | return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; | ||
1713 | #endif | ||
1714 | } | ||
1715 | |||
1716 | #endif | ||
1717 | |||
1718 | #ifdef USE_UNICODE_FSTRING | ||
1719 | |||
1720 | #ifndef _UNICODE | ||
1721 | |||
1722 | AString fs2fas(CFSTR s) | ||
1723 | { | ||
1724 | return UnicodeStringToMultiByte(s, GetCurrentCodePage()); | ||
1725 | } | ||
1726 | |||
1727 | FString fas2fs(const char *s) | ||
1728 | { | ||
1729 | return MultiByteToUnicodeString(s, GetCurrentCodePage()); | ||
1730 | } | ||
1731 | |||
1732 | FString fas2fs(const AString &s) | ||
1733 | { | ||
1734 | return MultiByteToUnicodeString(s, GetCurrentCodePage()); | ||
1735 | } | ||
1736 | |||
1737 | #endif // _UNICODE | ||
1738 | |||
1739 | #else // USE_UNICODE_FSTRING | ||
1740 | |||
1741 | UString fs2us(const FChar *s) | ||
1742 | { | ||
1743 | return MultiByteToUnicodeString(s, GetCurrentCodePage()); | ||
1744 | } | ||
1745 | |||
1746 | UString fs2us(const FString &s) | ||
1747 | { | ||
1748 | return MultiByteToUnicodeString(s, GetCurrentCodePage()); | ||
1749 | } | ||
1750 | |||
1751 | FString us2fs(const wchar_t *s) | ||
1752 | { | ||
1753 | return UnicodeStringToMultiByte(s, GetCurrentCodePage()); | ||
1754 | } | ||
1755 | |||
1756 | #endif // USE_UNICODE_FSTRING | ||
diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h new file mode 100644 index 0000000..aa3c301 --- /dev/null +++ b/CPP/Common/MyString.h | |||
@@ -0,0 +1,1012 @@ | |||
1 | // Common/MyString.h | ||
2 | |||
3 | #ifndef __COMMON_MY_STRING_H | ||
4 | #define __COMMON_MY_STRING_H | ||
5 | |||
6 | #include <string.h> | ||
7 | |||
8 | #ifndef _WIN32 | ||
9 | #include <wctype.h> | ||
10 | #include <wchar.h> | ||
11 | #endif | ||
12 | |||
13 | #include "MyWindows.h" | ||
14 | #include "MyTypes.h" | ||
15 | #include "MyVector.h" | ||
16 | |||
17 | |||
18 | /* if (DEBUG_FSTRING_INHERITS_ASTRING is defined), then | ||
19 | FString inherits from AString, so we can find bugs related to FString at compile time. | ||
20 | DON'T define DEBUG_FSTRING_INHERITS_ASTRING in release code */ | ||
21 | |||
22 | // #define DEBUG_FSTRING_INHERITS_ASTRING | ||
23 | |||
24 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
25 | class FString; | ||
26 | #endif | ||
27 | |||
28 | |||
29 | #ifdef _MSC_VER | ||
30 | #ifdef _NATIVE_WCHAR_T_DEFINED | ||
31 | #define MY_NATIVE_WCHAR_T_DEFINED | ||
32 | #endif | ||
33 | #else | ||
34 | #define MY_NATIVE_WCHAR_T_DEFINED | ||
35 | #endif | ||
36 | |||
37 | /* | ||
38 | native support for wchar_t: | ||
39 | _MSC_VER == 1600 : /Zc:wchar_t is not supported | ||
40 | _MSC_VER == 1310 (VS2003) | ||
41 | ? _MSC_VER == 1400 (VS2005) : wchar_t <- unsigned short | ||
42 | /Zc:wchar_t : wchar_t <- __wchar_t, _WCHAR_T_DEFINED and _NATIVE_WCHAR_T_DEFINED | ||
43 | _MSC_VER > 1400 (VS2008+) | ||
44 | /Zc:wchar_t[-] | ||
45 | /Zc:wchar_t is on by default | ||
46 | */ | ||
47 | |||
48 | #ifdef _WIN32 | ||
49 | #define IS_PATH_SEPAR(c) ((c) == '\\' || (c) == '/') | ||
50 | #else | ||
51 | #define IS_PATH_SEPAR(c) ((c) == CHAR_PATH_SEPARATOR) | ||
52 | #endif | ||
53 | |||
54 | inline bool IsPathSepar(char c) { return IS_PATH_SEPAR(c); } | ||
55 | inline bool IsPathSepar(wchar_t c) { return IS_PATH_SEPAR(c); } | ||
56 | |||
57 | inline unsigned MyStringLen(const char *s) | ||
58 | { | ||
59 | unsigned i; | ||
60 | for (i = 0; s[i] != 0; i++); | ||
61 | return i; | ||
62 | } | ||
63 | |||
64 | inline void MyStringCopy(char *dest, const char *src) | ||
65 | { | ||
66 | while ((*dest++ = *src++) != 0); | ||
67 | } | ||
68 | |||
69 | inline char *MyStpCpy(char *dest, const char *src) | ||
70 | { | ||
71 | for (;;) | ||
72 | { | ||
73 | char c = *src; | ||
74 | *dest = c; | ||
75 | if (c == 0) | ||
76 | return dest; | ||
77 | src++; | ||
78 | dest++; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | inline unsigned MyStringLen(const wchar_t *s) | ||
83 | { | ||
84 | unsigned i; | ||
85 | for (i = 0; s[i] != 0; i++); | ||
86 | return i; | ||
87 | } | ||
88 | |||
89 | inline void MyStringCopy(wchar_t *dest, const wchar_t *src) | ||
90 | { | ||
91 | while ((*dest++ = *src++) != 0); | ||
92 | } | ||
93 | |||
94 | inline void MyStringCat(wchar_t *dest, const wchar_t *src) | ||
95 | { | ||
96 | MyStringCopy(dest + MyStringLen(dest), src); | ||
97 | } | ||
98 | |||
99 | |||
100 | /* | ||
101 | inline wchar_t *MyWcpCpy(wchar_t *dest, const wchar_t *src) | ||
102 | { | ||
103 | for (;;) | ||
104 | { | ||
105 | wchar_t c = *src; | ||
106 | *dest = c; | ||
107 | if (c == 0) | ||
108 | return dest; | ||
109 | src++; | ||
110 | dest++; | ||
111 | } | ||
112 | } | ||
113 | */ | ||
114 | |||
115 | int FindCharPosInString(const char *s, char c) throw(); | ||
116 | int FindCharPosInString(const wchar_t *s, wchar_t c) throw(); | ||
117 | |||
118 | #ifdef _WIN32 | ||
119 | #ifndef _UNICODE | ||
120 | #define STRING_UNICODE_THROW | ||
121 | #endif | ||
122 | #endif | ||
123 | |||
124 | #ifndef STRING_UNICODE_THROW | ||
125 | #define STRING_UNICODE_THROW throw() | ||
126 | #endif | ||
127 | |||
128 | |||
129 | inline char MyCharUpper_Ascii(char c) | ||
130 | { | ||
131 | if (c >= 'a' && c <= 'z') | ||
132 | return (char)((unsigned char)c - 0x20); | ||
133 | return c; | ||
134 | } | ||
135 | |||
136 | /* | ||
137 | inline wchar_t MyCharUpper_Ascii(wchar_t c) | ||
138 | { | ||
139 | if (c >= 'a' && c <= 'z') | ||
140 | return (wchar_t)(c - 0x20); | ||
141 | return c; | ||
142 | } | ||
143 | */ | ||
144 | |||
145 | inline char MyCharLower_Ascii(char c) | ||
146 | { | ||
147 | if (c >= 'A' && c <= 'Z') | ||
148 | return (char)((unsigned char)c + 0x20); | ||
149 | return c; | ||
150 | } | ||
151 | |||
152 | inline wchar_t MyCharLower_Ascii(wchar_t c) | ||
153 | { | ||
154 | if (c >= 'A' && c <= 'Z') | ||
155 | return (wchar_t)(c + 0x20); | ||
156 | return c; | ||
157 | } | ||
158 | |||
159 | wchar_t MyCharUpper_WIN(wchar_t c) throw(); | ||
160 | |||
161 | inline wchar_t MyCharUpper(wchar_t c) throw() | ||
162 | { | ||
163 | if (c < 'a') return c; | ||
164 | if (c <= 'z') return (wchar_t)(c - 0x20); | ||
165 | if (c <= 0x7F) return c; | ||
166 | #ifdef _WIN32 | ||
167 | #ifdef _UNICODE | ||
168 | return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c); | ||
169 | #else | ||
170 | return (wchar_t)MyCharUpper_WIN(c); | ||
171 | #endif | ||
172 | #else | ||
173 | return (wchar_t)towupper((wint_t)c); | ||
174 | #endif | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | wchar_t MyCharLower_WIN(wchar_t c) throw(); | ||
179 | |||
180 | inline wchar_t MyCharLower(wchar_t c) throw() | ||
181 | { | ||
182 | if (c < 'A') return c; | ||
183 | if (c <= 'Z') return (wchar_t)(c + 0x20); | ||
184 | if (c <= 0x7F) return c; | ||
185 | #ifdef _WIN32 | ||
186 | #ifdef _UNICODE | ||
187 | return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c); | ||
188 | #else | ||
189 | return (wchar_t)MyCharLower_WIN(c); | ||
190 | #endif | ||
191 | #else | ||
192 | return (wchar_t)tolower(c); | ||
193 | #endif | ||
194 | } | ||
195 | */ | ||
196 | |||
197 | // char *MyStringUpper(char *s) throw(); | ||
198 | // char *MyStringLower(char *s) throw(); | ||
199 | |||
200 | // void MyStringUpper_Ascii(char *s) throw(); | ||
201 | // void MyStringUpper_Ascii(wchar_t *s) throw(); | ||
202 | void MyStringLower_Ascii(char *s) throw(); | ||
203 | void MyStringLower_Ascii(wchar_t *s) throw(); | ||
204 | // wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW; | ||
205 | // wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW; | ||
206 | |||
207 | bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw(); | ||
208 | |||
209 | bool IsString1PrefixedByString2(const char *s1, const char *s2) throw(); | ||
210 | bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw(); | ||
211 | bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw(); | ||
212 | bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw(); | ||
213 | bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *u, const char *a) throw(); | ||
214 | bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw(); | ||
215 | |||
216 | #define MyStringCompare(s1, s2) wcscmp(s1, s2) | ||
217 | int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw(); | ||
218 | // int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw(); | ||
219 | |||
220 | // ---------- ASCII ---------- | ||
221 | // char values in ASCII strings must be less then 128 | ||
222 | bool StringsAreEqual_Ascii(const char *u, const char *a) throw(); | ||
223 | bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw(); | ||
224 | bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw(); | ||
225 | bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw(); | ||
226 | bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw(); | ||
227 | |||
228 | #define MY_STRING_DELETE(_p_) delete []_p_; | ||
229 | // #define MY_STRING_DELETE(_p_) my_delete(_p_); | ||
230 | |||
231 | |||
232 | #define FORBID_STRING_OPS_2(cls, t) \ | ||
233 | void Find(t) const; \ | ||
234 | void Find(t, unsigned startIndex) const; \ | ||
235 | void ReverseFind(t) const; \ | ||
236 | void InsertAtFront(t); \ | ||
237 | void RemoveChar(t); \ | ||
238 | void Replace(t, t); \ | ||
239 | |||
240 | #define FORBID_STRING_OPS(cls, t) \ | ||
241 | explicit cls(t); \ | ||
242 | explicit cls(const t *); \ | ||
243 | cls &operator=(t); \ | ||
244 | cls &operator=(const t *); \ | ||
245 | cls &operator+=(t); \ | ||
246 | cls &operator+=(const t *); \ | ||
247 | FORBID_STRING_OPS_2(cls, t) \ | ||
248 | |||
249 | /* | ||
250 | cls &operator+(t); \ | ||
251 | cls &operator+(const t *); \ | ||
252 | */ | ||
253 | |||
254 | #define FORBID_STRING_OPS_AString(t) FORBID_STRING_OPS(AString, t) | ||
255 | #define FORBID_STRING_OPS_UString(t) FORBID_STRING_OPS(UString, t) | ||
256 | #define FORBID_STRING_OPS_UString2(t) FORBID_STRING_OPS(UString2, t) | ||
257 | |||
258 | class AString | ||
259 | { | ||
260 | char *_chars; | ||
261 | unsigned _len; | ||
262 | unsigned _limit; | ||
263 | |||
264 | void MoveItems(unsigned dest, unsigned src) | ||
265 | { | ||
266 | memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char)); | ||
267 | } | ||
268 | |||
269 | void InsertSpace(unsigned &index, unsigned size); | ||
270 | |||
271 | void ReAlloc(unsigned newLimit); | ||
272 | void ReAlloc2(unsigned newLimit); | ||
273 | void SetStartLen(unsigned len); | ||
274 | void Grow_1(); | ||
275 | void Grow(unsigned n); | ||
276 | |||
277 | AString(unsigned num, const char *s); | ||
278 | AString(unsigned num, const AString &s); | ||
279 | AString(const AString &s, char c); // it's for String + char | ||
280 | AString(const char *s1, unsigned num1, const char *s2, unsigned num2); | ||
281 | |||
282 | friend AString operator+(const AString &s, char c) { return AString(s, c); } | ||
283 | // friend AString operator+(char c, const AString &s); // is not supported | ||
284 | |||
285 | friend AString operator+(const AString &s1, const AString &s2); | ||
286 | friend AString operator+(const AString &s1, const char *s2); | ||
287 | friend AString operator+(const char *s1, const AString &s2); | ||
288 | |||
289 | // ---------- forbidden functions ---------- | ||
290 | |||
291 | #ifdef MY_NATIVE_WCHAR_T_DEFINED | ||
292 | FORBID_STRING_OPS_AString(wchar_t) | ||
293 | #endif | ||
294 | |||
295 | FORBID_STRING_OPS_AString(signed char) | ||
296 | FORBID_STRING_OPS_AString(unsigned char) | ||
297 | FORBID_STRING_OPS_AString(short) | ||
298 | FORBID_STRING_OPS_AString(unsigned short) | ||
299 | FORBID_STRING_OPS_AString(int) | ||
300 | FORBID_STRING_OPS_AString(unsigned) | ||
301 | FORBID_STRING_OPS_AString(long) | ||
302 | FORBID_STRING_OPS_AString(unsigned long) | ||
303 | |||
304 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
305 | AString(const FString &s); | ||
306 | AString &operator=(const FString &s); | ||
307 | AString &operator+=(const FString &s); | ||
308 | #endif | ||
309 | |||
310 | public: | ||
311 | explicit AString(); | ||
312 | explicit AString(char c); | ||
313 | explicit AString(const char *s); | ||
314 | AString(const AString &s); | ||
315 | ~AString() { MY_STRING_DELETE(_chars); } | ||
316 | |||
317 | unsigned Len() const { return _len; } | ||
318 | bool IsEmpty() const { return _len == 0; } | ||
319 | void Empty() { _len = 0; _chars[0] = 0; } | ||
320 | |||
321 | operator const char *() const { return _chars; } | ||
322 | char *Ptr_non_const() const { return _chars; } | ||
323 | const char *Ptr() const { return _chars; } | ||
324 | const char *Ptr(unsigned pos) const { return _chars + pos; } | ||
325 | const char *RightPtr(unsigned num) const { return _chars + _len - num; } | ||
326 | char Back() const { return _chars[(size_t)_len - 1]; } | ||
327 | |||
328 | void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; } | ||
329 | |||
330 | char *GetBuf() { return _chars; } | ||
331 | /* GetBuf(minLen): provides the buffer that can store | ||
332 | at least (minLen) characters and additional null terminator. | ||
333 | 9.35: GetBuf doesn't preserve old characters and terminator */ | ||
334 | char *GetBuf(unsigned minLen) | ||
335 | { | ||
336 | if (minLen > _limit) | ||
337 | ReAlloc2(minLen); | ||
338 | return _chars; | ||
339 | } | ||
340 | char *GetBuf_SetEnd(unsigned minLen) | ||
341 | { | ||
342 | if (minLen > _limit) | ||
343 | ReAlloc2(minLen); | ||
344 | char *chars = _chars; | ||
345 | chars[minLen] = 0; | ||
346 | _len = minLen; | ||
347 | return chars; | ||
348 | } | ||
349 | |||
350 | void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } | ||
351 | void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } | ||
352 | void ReleaseBuf_CalcLen(unsigned maxLen) | ||
353 | { | ||
354 | char *chars = _chars; | ||
355 | chars[maxLen] = 0; | ||
356 | _len = MyStringLen(chars); | ||
357 | } | ||
358 | |||
359 | AString &operator=(char c); | ||
360 | AString &operator=(const char *s); | ||
361 | AString &operator=(const AString &s); | ||
362 | void SetFromWStr_if_Ascii(const wchar_t *s); | ||
363 | // void SetFromBstr_if_Ascii(BSTR s); | ||
364 | |||
365 | AString &operator+=(char c) | ||
366 | { | ||
367 | if (_limit == _len) | ||
368 | Grow_1(); | ||
369 | unsigned len = _len; | ||
370 | char *chars = _chars; | ||
371 | chars[len++] = c; | ||
372 | chars[len] = 0; | ||
373 | _len = len; | ||
374 | return *this; | ||
375 | } | ||
376 | |||
377 | void Add_Space(); | ||
378 | void Add_Space_if_NotEmpty(); | ||
379 | void Add_OptSpaced(const char *s); | ||
380 | void Add_LF(); | ||
381 | void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); } | ||
382 | |||
383 | AString &operator+=(const char *s); | ||
384 | AString &operator+=(const AString &s); | ||
385 | |||
386 | void Add_UInt32(UInt32 v); | ||
387 | void Add_UInt64(UInt64 v); | ||
388 | |||
389 | void SetFrom(const char *s, unsigned len); // no check | ||
390 | void SetFrom_CalcLen(const char *s, unsigned len); | ||
391 | |||
392 | AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); } | ||
393 | AString Left(unsigned count) const { return AString(count, *this); } | ||
394 | |||
395 | // void MakeUpper() { MyStringUpper(_chars); } | ||
396 | // void MakeLower() { MyStringLower(_chars); } | ||
397 | void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } | ||
398 | |||
399 | |||
400 | bool IsEqualTo(const char *s) const { return strcmp(_chars, s) == 0; } | ||
401 | bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } | ||
402 | // int Compare(const char *s) const { return MyStringCompare(_chars, s); } | ||
403 | // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); } | ||
404 | // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); } | ||
405 | // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); } | ||
406 | bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); } | ||
407 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); | ||
408 | |||
409 | bool IsAscii() const | ||
410 | { | ||
411 | unsigned len = Len(); | ||
412 | const char *s = _chars; | ||
413 | for (unsigned i = 0; i < len; i++) | ||
414 | if ((unsigned char)s[i] >= 0x80) | ||
415 | return false; | ||
416 | return true; | ||
417 | } | ||
418 | int Find(char c) const { return FindCharPosInString(_chars, c); } | ||
419 | int Find(char c, unsigned startIndex) const | ||
420 | { | ||
421 | int pos = FindCharPosInString(_chars + startIndex, c); | ||
422 | return pos < 0 ? -1 : (int)startIndex + pos; | ||
423 | } | ||
424 | |||
425 | int ReverseFind(char c) const throw(); | ||
426 | int ReverseFind_Dot() const throw() { return ReverseFind('.'); } | ||
427 | int ReverseFind_PathSepar() const throw(); | ||
428 | |||
429 | int Find(const char *s) const { return Find(s, 0); } | ||
430 | int Find(const char *s, unsigned startIndex) const throw(); | ||
431 | |||
432 | void TrimLeft() throw(); | ||
433 | void TrimRight() throw(); | ||
434 | void Trim() | ||
435 | { | ||
436 | TrimRight(); | ||
437 | TrimLeft(); | ||
438 | } | ||
439 | |||
440 | void InsertAtFront(char c); | ||
441 | // void Insert(unsigned index, char c); | ||
442 | void Insert(unsigned index, const char *s); | ||
443 | void Insert(unsigned index, const AString &s); | ||
444 | |||
445 | void RemoveChar(char ch) throw(); | ||
446 | |||
447 | void Replace(char oldChar, char newChar) throw(); | ||
448 | void Replace(const AString &oldString, const AString &newString); | ||
449 | |||
450 | void Delete(unsigned index) throw(); | ||
451 | void Delete(unsigned index, unsigned count) throw(); | ||
452 | void DeleteFrontal(unsigned num) throw(); | ||
453 | void DeleteBack() { _chars[--_len] = 0; } | ||
454 | void DeleteFrom(unsigned index) | ||
455 | { | ||
456 | if (index < _len) | ||
457 | { | ||
458 | _len = index; | ||
459 | _chars[index] = 0; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | void Wipe_and_Empty() | ||
464 | { | ||
465 | if (_chars) | ||
466 | { | ||
467 | memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); | ||
468 | _len = 0; | ||
469 | } | ||
470 | } | ||
471 | }; | ||
472 | |||
473 | |||
474 | class AString_Wipe: public AString | ||
475 | { | ||
476 | CLASS_NO_COPY(AString_Wipe) | ||
477 | public: | ||
478 | AString_Wipe(): AString() {} | ||
479 | // AString_Wipe(const AString &s): AString(s) {} | ||
480 | // AString_Wipe &operator=(const AString &s) { AString::operator=(s); return *this; } | ||
481 | // AString_Wipe &operator=(const char *s) { AString::operator=(s); return *this; } | ||
482 | ~AString_Wipe() { Wipe_and_Empty(); } | ||
483 | }; | ||
484 | |||
485 | |||
486 | bool operator<(const AString &s1, const AString &s2); | ||
487 | bool operator>(const AString &s1, const AString &s2); | ||
488 | |||
489 | /* | ||
490 | bool operator==(const AString &s1, const AString &s2); | ||
491 | bool operator==(const AString &s1, const char *s2); | ||
492 | bool operator==(const char *s1, const AString &s2); | ||
493 | |||
494 | bool operator!=(const AString &s1, const AString &s2); | ||
495 | bool operator!=(const AString &s1, const char *s2); | ||
496 | bool operator!=(const char *s1, const AString &s2); | ||
497 | */ | ||
498 | |||
499 | inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; } | ||
500 | inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; } | ||
501 | inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; } | ||
502 | |||
503 | inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; } | ||
504 | inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; } | ||
505 | inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; } | ||
506 | |||
507 | // ---------- forbidden functions ---------- | ||
508 | |||
509 | void operator==(char c1, const AString &s2); | ||
510 | void operator==(const AString &s1, char c2); | ||
511 | |||
512 | void operator+(char c, const AString &s); // this function can be OK, but we don't use it | ||
513 | |||
514 | void operator+(const AString &s, int c); | ||
515 | void operator+(const AString &s, unsigned c); | ||
516 | void operator+(int c, const AString &s); | ||
517 | void operator+(unsigned c, const AString &s); | ||
518 | void operator-(const AString &s, int c); | ||
519 | void operator-(const AString &s, unsigned c); | ||
520 | |||
521 | |||
522 | class UString | ||
523 | { | ||
524 | wchar_t *_chars; | ||
525 | unsigned _len; | ||
526 | unsigned _limit; | ||
527 | |||
528 | void MoveItems(unsigned dest, unsigned src) | ||
529 | { | ||
530 | memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t)); | ||
531 | } | ||
532 | |||
533 | void InsertSpace(unsigned index, unsigned size); | ||
534 | |||
535 | void ReAlloc(unsigned newLimit); | ||
536 | void ReAlloc2(unsigned newLimit); | ||
537 | void SetStartLen(unsigned len); | ||
538 | void Grow_1(); | ||
539 | void Grow(unsigned n); | ||
540 | |||
541 | UString(unsigned num, const wchar_t *s); // for Mid | ||
542 | UString(unsigned num, const UString &s); // for Left | ||
543 | UString(const UString &s, wchar_t c); // it's for String + char | ||
544 | UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2); | ||
545 | |||
546 | friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); } | ||
547 | // friend UString operator+(wchar_t c, const UString &s); // is not supported | ||
548 | |||
549 | friend UString operator+(const UString &s1, const UString &s2); | ||
550 | friend UString operator+(const UString &s1, const wchar_t *s2); | ||
551 | friend UString operator+(const wchar_t *s1, const UString &s2); | ||
552 | |||
553 | // ---------- forbidden functions ---------- | ||
554 | |||
555 | FORBID_STRING_OPS_UString(signed char) | ||
556 | FORBID_STRING_OPS_UString(unsigned char) | ||
557 | FORBID_STRING_OPS_UString(short) | ||
558 | |||
559 | #ifdef MY_NATIVE_WCHAR_T_DEFINED | ||
560 | FORBID_STRING_OPS_UString(unsigned short) | ||
561 | #endif | ||
562 | |||
563 | FORBID_STRING_OPS_UString(int) | ||
564 | FORBID_STRING_OPS_UString(unsigned) | ||
565 | FORBID_STRING_OPS_UString(long) | ||
566 | FORBID_STRING_OPS_UString(unsigned long) | ||
567 | |||
568 | FORBID_STRING_OPS_2(UString, char) | ||
569 | |||
570 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
571 | UString(const FString &s); | ||
572 | UString &operator=(const FString &s); | ||
573 | UString &operator+=(const FString &s); | ||
574 | #endif | ||
575 | |||
576 | public: | ||
577 | UString(); | ||
578 | explicit UString(wchar_t c); | ||
579 | explicit UString(char c); | ||
580 | explicit UString(const char *s); | ||
581 | explicit UString(const AString &s); | ||
582 | UString(const wchar_t *s); | ||
583 | UString(const UString &s); | ||
584 | ~UString() { MY_STRING_DELETE(_chars); } | ||
585 | |||
586 | unsigned Len() const { return _len; } | ||
587 | bool IsEmpty() const { return _len == 0; } | ||
588 | void Empty() { _len = 0; _chars[0] = 0; } | ||
589 | |||
590 | operator const wchar_t *() const { return _chars; } | ||
591 | wchar_t *Ptr_non_const() const { return _chars; } | ||
592 | const wchar_t *Ptr() const { return _chars; } | ||
593 | const wchar_t *Ptr(unsigned pos) const { return _chars + pos; } | ||
594 | const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; } | ||
595 | wchar_t Back() const { return _chars[(size_t)_len - 1]; } | ||
596 | |||
597 | void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; } | ||
598 | |||
599 | wchar_t *GetBuf() { return _chars; } | ||
600 | |||
601 | wchar_t *GetBuf(unsigned minLen) | ||
602 | { | ||
603 | if (minLen > _limit) | ||
604 | ReAlloc2(minLen); | ||
605 | return _chars; | ||
606 | } | ||
607 | wchar_t *GetBuf_SetEnd(unsigned minLen) | ||
608 | { | ||
609 | if (minLen > _limit) | ||
610 | ReAlloc2(minLen); | ||
611 | wchar_t *chars = _chars; | ||
612 | chars[minLen] = 0; | ||
613 | _len = minLen; | ||
614 | return chars; | ||
615 | } | ||
616 | |||
617 | void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } | ||
618 | void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; } | ||
619 | void ReleaseBuf_CalcLen(unsigned maxLen) | ||
620 | { | ||
621 | wchar_t *chars = _chars; | ||
622 | chars[maxLen] = 0; | ||
623 | _len = MyStringLen(chars); | ||
624 | } | ||
625 | |||
626 | UString &operator=(wchar_t c); | ||
627 | UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); } | ||
628 | UString &operator=(const wchar_t *s); | ||
629 | UString &operator=(const UString &s); | ||
630 | void SetFrom(const wchar_t *s, unsigned len); // no check | ||
631 | void SetFromBstr(LPCOLESTR s); | ||
632 | UString &operator=(const char *s); | ||
633 | UString &operator=(const AString &s) { return operator=(s.Ptr()); } | ||
634 | |||
635 | UString &operator+=(wchar_t c) | ||
636 | { | ||
637 | if (_limit == _len) | ||
638 | Grow_1(); | ||
639 | unsigned len = _len; | ||
640 | wchar_t *chars = _chars; | ||
641 | chars[len++] = c; | ||
642 | chars[len] = 0; | ||
643 | _len = len; | ||
644 | return *this; | ||
645 | } | ||
646 | |||
647 | UString &operator+=(char c) { return (*this)+=((wchar_t)(unsigned char)c); } | ||
648 | |||
649 | void Add_Space(); | ||
650 | void Add_Space_if_NotEmpty(); | ||
651 | void Add_LF(); | ||
652 | void Add_PathSepar() { operator+=(WCHAR_PATH_SEPARATOR); } | ||
653 | |||
654 | UString &operator+=(const wchar_t *s); | ||
655 | UString &operator+=(const UString &s); | ||
656 | UString &operator+=(const char *s); | ||
657 | UString &operator+=(const AString &s) { return operator+=(s.Ptr()); } | ||
658 | |||
659 | void Add_UInt32(UInt32 v); | ||
660 | void Add_UInt64(UInt64 v); | ||
661 | |||
662 | UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); } | ||
663 | UString Left(unsigned count) const { return UString(count, *this); } | ||
664 | |||
665 | // void MakeUpper() { MyStringUpper(_chars); } | ||
666 | // void MakeUpper() { MyStringUpper_Ascii(_chars); } | ||
667 | // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); } | ||
668 | void MakeLower_Ascii() { MyStringLower_Ascii(_chars); } | ||
669 | |||
670 | bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); } | ||
671 | bool IsEqualTo_NoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); } | ||
672 | bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); } | ||
673 | int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } | ||
674 | // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); } | ||
675 | // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); } | ||
676 | // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); } | ||
677 | bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); } | ||
678 | bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); } | ||
679 | bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw(); | ||
680 | |||
681 | bool IsAscii() const | ||
682 | { | ||
683 | unsigned len = Len(); | ||
684 | const wchar_t *s = _chars; | ||
685 | for (unsigned i = 0; i < len; i++) | ||
686 | if (s[i] >= 0x80) | ||
687 | return false; | ||
688 | return true; | ||
689 | } | ||
690 | int Find(wchar_t c) const { return FindCharPosInString(_chars, c); } | ||
691 | int Find(wchar_t c, unsigned startIndex) const | ||
692 | { | ||
693 | int pos = FindCharPosInString(_chars + startIndex, c); | ||
694 | return pos < 0 ? -1 : (int)startIndex + pos; | ||
695 | } | ||
696 | |||
697 | int ReverseFind(wchar_t c) const throw(); | ||
698 | int ReverseFind_Dot() const throw() { return ReverseFind(L'.'); } | ||
699 | int ReverseFind_PathSepar() const throw(); | ||
700 | |||
701 | int Find(const wchar_t *s) const { return Find(s, 0); } | ||
702 | int Find(const wchar_t *s, unsigned startIndex) const throw(); | ||
703 | |||
704 | void TrimLeft() throw(); | ||
705 | void TrimRight() throw(); | ||
706 | void Trim() | ||
707 | { | ||
708 | TrimRight(); | ||
709 | TrimLeft(); | ||
710 | } | ||
711 | |||
712 | void InsertAtFront(wchar_t c); | ||
713 | // void Insert_wchar_t(unsigned index, wchar_t c); | ||
714 | void Insert(unsigned index, const wchar_t *s); | ||
715 | void Insert(unsigned index, const UString &s); | ||
716 | |||
717 | void RemoveChar(wchar_t ch) throw(); | ||
718 | |||
719 | void Replace(wchar_t oldChar, wchar_t newChar) throw(); | ||
720 | void Replace(const UString &oldString, const UString &newString); | ||
721 | |||
722 | void Delete(unsigned index) throw(); | ||
723 | void Delete(unsigned index, unsigned count) throw(); | ||
724 | void DeleteFrontal(unsigned num) throw(); | ||
725 | void DeleteBack() { _chars[--_len] = 0; } | ||
726 | void DeleteFrom(unsigned index) | ||
727 | { | ||
728 | if (index < _len) | ||
729 | { | ||
730 | _len = index; | ||
731 | _chars[index] = 0; | ||
732 | } | ||
733 | } | ||
734 | |||
735 | void Wipe_and_Empty() | ||
736 | { | ||
737 | if (_chars) | ||
738 | { | ||
739 | memset(_chars, 0, (_limit + 1) * sizeof(*_chars)); | ||
740 | _len = 0; | ||
741 | } | ||
742 | } | ||
743 | }; | ||
744 | |||
745 | |||
746 | class UString_Wipe: public UString | ||
747 | { | ||
748 | CLASS_NO_COPY(UString_Wipe) | ||
749 | public: | ||
750 | UString_Wipe(): UString() {} | ||
751 | // UString_Wipe(const UString &s): UString(s) {} | ||
752 | // UString_Wipe &operator=(const UString &s) { UString::operator=(s); return *this; } | ||
753 | // UString_Wipe &operator=(const wchar_t *s) { UString::operator=(s); return *this; } | ||
754 | ~UString_Wipe() { Wipe_and_Empty(); } | ||
755 | }; | ||
756 | |||
757 | |||
758 | bool operator<(const UString &s1, const UString &s2); | ||
759 | bool operator>(const UString &s1, const UString &s2); | ||
760 | |||
761 | inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; } | ||
762 | inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; } | ||
763 | inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; } | ||
764 | |||
765 | inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; } | ||
766 | inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; } | ||
767 | inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; } | ||
768 | |||
769 | |||
770 | // ---------- forbidden functions ---------- | ||
771 | |||
772 | void operator==(wchar_t c1, const UString &s2); | ||
773 | void operator==(const UString &s1, wchar_t c2); | ||
774 | |||
775 | void operator+(wchar_t c, const UString &s); // this function can be OK, but we don't use it | ||
776 | |||
777 | void operator+(const AString &s1, const UString &s2); | ||
778 | void operator+(const UString &s1, const AString &s2); | ||
779 | |||
780 | void operator+(const UString &s1, const char *s2); | ||
781 | void operator+(const char *s1, const UString &s2); | ||
782 | |||
783 | void operator+(const UString &s, char c); | ||
784 | void operator+(const UString &s, unsigned char c); | ||
785 | void operator+(char c, const UString &s); | ||
786 | void operator+(unsigned char c, const UString &s); | ||
787 | void operator-(const UString &s1, wchar_t c); | ||
788 | |||
789 | #ifdef _WIN32 | ||
790 | // can we forbid these functions, if wchar_t is 32-bit ? | ||
791 | void operator+(const UString &s, int c); | ||
792 | void operator+(const UString &s, unsigned c); | ||
793 | void operator+(int c, const UString &s); | ||
794 | void operator+(unsigned c, const UString &s); | ||
795 | void operator-(const UString &s1, int c); | ||
796 | void operator-(const UString &s1, unsigned c); | ||
797 | #endif | ||
798 | |||
799 | |||
800 | |||
801 | |||
802 | |||
803 | |||
804 | |||
805 | class UString2 | ||
806 | { | ||
807 | wchar_t *_chars; | ||
808 | unsigned _len; | ||
809 | |||
810 | void ReAlloc2(unsigned newLimit); | ||
811 | void SetStartLen(unsigned len); | ||
812 | |||
813 | // ---------- forbidden functions ---------- | ||
814 | |||
815 | FORBID_STRING_OPS_UString2(char) | ||
816 | FORBID_STRING_OPS_UString2(signed char) | ||
817 | FORBID_STRING_OPS_UString2(unsigned char) | ||
818 | FORBID_STRING_OPS_UString2(short) | ||
819 | |||
820 | UString2 &operator=(wchar_t c); | ||
821 | |||
822 | UString2(const AString &s); | ||
823 | UString2 &operator=(const AString &s); | ||
824 | UString2 &operator+=(const AString &s); | ||
825 | |||
826 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
827 | UString2(const FString &s); | ||
828 | UString2 &operator=(const FString &s); | ||
829 | UString2 &operator+=(const FString &s); | ||
830 | #endif | ||
831 | |||
832 | public: | ||
833 | UString2(): _chars(NULL), _len(0) {} | ||
834 | UString2(const wchar_t *s); | ||
835 | UString2(const UString2 &s); | ||
836 | ~UString2() { if (_chars) MY_STRING_DELETE(_chars); } | ||
837 | |||
838 | unsigned Len() const { return _len; } | ||
839 | bool IsEmpty() const { return _len == 0; } | ||
840 | // void Empty() { _len = 0; _chars[0] = 0; } | ||
841 | |||
842 | // operator const wchar_t *() const { return _chars; } | ||
843 | const wchar_t *GetRawPtr() const { return _chars; } | ||
844 | |||
845 | int Compare(const wchar_t *s) const { return wcscmp(_chars, s); } | ||
846 | |||
847 | wchar_t *GetBuf(unsigned minLen) | ||
848 | { | ||
849 | if (!_chars || minLen > _len) | ||
850 | ReAlloc2(minLen); | ||
851 | return _chars; | ||
852 | } | ||
853 | void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; } | ||
854 | |||
855 | UString2 &operator=(const wchar_t *s); | ||
856 | UString2 &operator=(const UString2 &s); | ||
857 | void SetFromAscii(const char *s); | ||
858 | }; | ||
859 | |||
860 | bool operator==(const UString2 &s1, const UString2 &s2); | ||
861 | bool operator==(const UString2 &s1, const wchar_t *s2); | ||
862 | bool operator==(const wchar_t *s1, const UString2 &s2); | ||
863 | |||
864 | inline bool operator!=(const UString2 &s1, const UString2 &s2) { return !(s1 == s2); } | ||
865 | inline bool operator!=(const UString2 &s1, const wchar_t *s2) { return !(s1 == s2); } | ||
866 | inline bool operator!=(const wchar_t *s1, const UString2 &s2) { return !(s1 == s2); } | ||
867 | |||
868 | |||
869 | // ---------- forbidden functions ---------- | ||
870 | |||
871 | void operator==(wchar_t c1, const UString2 &s2); | ||
872 | void operator==(const UString2 &s1, wchar_t c2); | ||
873 | bool operator<(const UString2 &s1, const UString2 &s2); | ||
874 | bool operator>(const UString2 &s1, const UString2 &s2); | ||
875 | |||
876 | void operator+(const UString2 &s1, const UString2 &s2); | ||
877 | void operator+(const UString2 &s1, const wchar_t *s2); | ||
878 | void operator+(const wchar_t *s1, const UString2 &s2); | ||
879 | void operator+(wchar_t c, const UString2 &s); | ||
880 | void operator+(const UString2 &s, wchar_t c); | ||
881 | void operator+(const UString2 &s, char c); | ||
882 | void operator+(const UString2 &s, unsigned char c); | ||
883 | void operator+(char c, const UString2 &s); | ||
884 | void operator+(unsigned char c, const UString2 &s); | ||
885 | void operator-(const UString2 &s1, wchar_t c); | ||
886 | |||
887 | |||
888 | |||
889 | |||
890 | |||
891 | |||
892 | typedef CObjectVector<AString> AStringVector; | ||
893 | typedef CObjectVector<UString> UStringVector; | ||
894 | |||
895 | #ifdef _UNICODE | ||
896 | typedef UString CSysString; | ||
897 | #else | ||
898 | typedef AString CSysString; | ||
899 | #endif | ||
900 | |||
901 | typedef CObjectVector<CSysString> CSysStringVector; | ||
902 | |||
903 | |||
904 | // ---------- FString ---------- | ||
905 | |||
906 | #ifndef DEBUG_FSTRING_INHERITS_ASTRING | ||
907 | #ifdef _WIN32 | ||
908 | #define USE_UNICODE_FSTRING | ||
909 | #endif | ||
910 | #endif | ||
911 | |||
912 | #ifdef USE_UNICODE_FSTRING | ||
913 | |||
914 | #define __FTEXT(quote) L##quote | ||
915 | |||
916 | typedef wchar_t FChar; | ||
917 | typedef UString FString; | ||
918 | |||
919 | #define fs2us(_x_) (_x_) | ||
920 | #define us2fs(_x_) (_x_) | ||
921 | FString fas2fs(const char *s); | ||
922 | FString fas2fs(const AString &s); | ||
923 | AString fs2fas(const FChar *s); | ||
924 | |||
925 | #else | ||
926 | |||
927 | #define __FTEXT(quote) quote | ||
928 | |||
929 | typedef char FChar; | ||
930 | |||
931 | #ifdef DEBUG_FSTRING_INHERITS_ASTRING | ||
932 | |||
933 | class FString: public AString | ||
934 | { | ||
935 | // FString &operator=(const char *s); | ||
936 | FString &operator=(const AString &s); | ||
937 | // FString &operator+=(const AString &s); | ||
938 | public: | ||
939 | FString(const AString &s): AString(s.Ptr()) {} | ||
940 | FString(const FString &s): AString(s.Ptr()) {} | ||
941 | FString(const char *s): AString(s) {} | ||
942 | FString() {} | ||
943 | FString &operator=(const FString &s) { AString::operator=((const AString &)s); return *this; } | ||
944 | FString &operator=(char c) { AString::operator=(c); return *this; } | ||
945 | FString &operator+=(char c) { AString::operator+=(c); return *this; } | ||
946 | FString &operator+=(const FString &s) { AString::operator+=((const AString &)s); return *this; } | ||
947 | FString Left(unsigned count) const { return FString(AString::Left(count)); } | ||
948 | }; | ||
949 | void operator+(const AString &s1, const FString &s2); | ||
950 | void operator+(const FString &s1, const AString &s2); | ||
951 | |||
952 | inline FString operator+(const FString &s1, const FString &s2) | ||
953 | { | ||
954 | AString s =(const AString &)s1 + (const AString &)s2; | ||
955 | return FString(s.Ptr()); | ||
956 | // return FString((const AString &)s1 + (const AString &)s2); | ||
957 | } | ||
958 | inline FString operator+(const FString &s1, const FChar *s2) | ||
959 | { | ||
960 | return s1 + (FString)s2; | ||
961 | } | ||
962 | /* | ||
963 | inline FString operator+(const FChar *s1, const FString &s2) | ||
964 | { | ||
965 | return (FString)s1 + s2; | ||
966 | } | ||
967 | */ | ||
968 | |||
969 | inline FString fas2fs(const char *s) { return FString(s); } | ||
970 | |||
971 | #else // DEBUG_FSTRING_INHERITS_ASTRING | ||
972 | typedef AString FString; | ||
973 | #define fas2fs(_x_) (_x_) | ||
974 | #endif // DEBUG_FSTRING_INHERITS_ASTRING | ||
975 | |||
976 | UString fs2us(const FChar *s); | ||
977 | UString fs2us(const FString &s); | ||
978 | FString us2fs(const wchar_t *s); | ||
979 | #define fs2fas(_x_) (_x_) | ||
980 | |||
981 | #endif | ||
982 | |||
983 | #define FTEXT(quote) __FTEXT(quote) | ||
984 | |||
985 | #define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR) | ||
986 | #define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR) | ||
987 | |||
988 | // #define FCHAR_ANY_MASK FTEXT('*') | ||
989 | // #define FSTRING_ANY_MASK FTEXT("*") | ||
990 | |||
991 | typedef const FChar *CFSTR; | ||
992 | |||
993 | typedef CObjectVector<FString> FStringVector; | ||
994 | |||
995 | #endif | ||
996 | |||
997 | |||
998 | |||
999 | #if defined(_WIN32) | ||
1000 | // #include <wchar.h> | ||
1001 | // WCHAR_MAX is defined as ((wchar_t)-1) | ||
1002 | #define _WCHART_IS_16BIT 1 | ||
1003 | #elif (defined(WCHAR_MAX) && (WCHAR_MAX <= 0xffff)) \ | ||
1004 | || (defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ == 2)) | ||
1005 | #define _WCHART_IS_16BIT 1 | ||
1006 | #endif | ||
1007 | |||
1008 | #if WCHAR_PATH_SEPARATOR == L'\\' | ||
1009 | // WSL scheme | ||
1010 | #define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT ((wchar_t)((unsigned)(0xF000) + (unsigned)'\\')) | ||
1011 | // #define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT '_' | ||
1012 | #endif | ||
diff --git a/CPP/Common/MyTypes.h b/CPP/Common/MyTypes.h new file mode 100644 index 0000000..71b8e7f --- /dev/null +++ b/CPP/Common/MyTypes.h | |||
@@ -0,0 +1,52 @@ | |||
1 | // Common/MyTypes.h | ||
2 | |||
3 | #ifndef __COMMON_MY_TYPES_H | ||
4 | #define __COMMON_MY_TYPES_H | ||
5 | |||
6 | #include "../../C/7zTypes.h" | ||
7 | |||
8 | typedef int HRes; | ||
9 | |||
10 | struct CBoolPair | ||
11 | { | ||
12 | bool Val; | ||
13 | bool Def; | ||
14 | |||
15 | CBoolPair(): Val(false), Def(false) {} | ||
16 | |||
17 | void Init() | ||
18 | { | ||
19 | Val = false; | ||
20 | Def = false; | ||
21 | } | ||
22 | |||
23 | void SetTrueTrue() | ||
24 | { | ||
25 | Val = true; | ||
26 | Def = true; | ||
27 | } | ||
28 | |||
29 | void SetVal_as_Defined(bool val) | ||
30 | { | ||
31 | Val = val; | ||
32 | Def = true; | ||
33 | } | ||
34 | }; | ||
35 | |||
36 | #define CLASS_NO_COPY(cls) \ | ||
37 | private: \ | ||
38 | cls(const cls &); \ | ||
39 | cls &operator=(const cls &); | ||
40 | |||
41 | class CUncopyable | ||
42 | { | ||
43 | protected: | ||
44 | CUncopyable() {} // allow constructor | ||
45 | // ~CUncopyable() {} | ||
46 | CLASS_NO_COPY(CUncopyable) | ||
47 | }; | ||
48 | |||
49 | #define MY_UNCOPYABLE :private CUncopyable | ||
50 | // #define MY_UNCOPYABLE | ||
51 | |||
52 | #endif | ||
diff --git a/CPP/Common/MyUnknown.h b/CPP/Common/MyUnknown.h new file mode 100644 index 0000000..ff025cb --- /dev/null +++ b/CPP/Common/MyUnknown.h | |||
@@ -0,0 +1,17 @@ | |||
1 | // MyUnknown.h | ||
2 | |||
3 | #ifndef __MY_UNKNOWN_H | ||
4 | #define __MY_UNKNOWN_H | ||
5 | |||
6 | #include "MyWindows.h" | ||
7 | |||
8 | /* | ||
9 | #ifdef _WIN32 | ||
10 | #include <basetyps.h> | ||
11 | #include <unknwn.h> | ||
12 | #else | ||
13 | #include "MyWindows.h" | ||
14 | #endif | ||
15 | */ | ||
16 | |||
17 | #endif | ||
diff --git a/CPP/Common/MyVector.cpp b/CPP/Common/MyVector.cpp new file mode 100644 index 0000000..0b1baf4 --- /dev/null +++ b/CPP/Common/MyVector.cpp | |||
@@ -0,0 +1,3 @@ | |||
1 | // Common/MyVector.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
diff --git a/CPP/Common/MyVector.h b/CPP/Common/MyVector.h new file mode 100644 index 0000000..c851234 --- /dev/null +++ b/CPP/Common/MyVector.h | |||
@@ -0,0 +1,634 @@ | |||
1 | // Common/MyVector.h | ||
2 | |||
3 | #ifndef __COMMON_MY_VECTOR_H | ||
4 | #define __COMMON_MY_VECTOR_H | ||
5 | |||
6 | #include <string.h> | ||
7 | |||
8 | template <class T> | ||
9 | class CRecordVector | ||
10 | { | ||
11 | T *_items; | ||
12 | unsigned _size; | ||
13 | unsigned _capacity; | ||
14 | |||
15 | void MoveItems(unsigned destIndex, unsigned srcIndex) | ||
16 | { | ||
17 | memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T)); | ||
18 | } | ||
19 | |||
20 | void ReserveOnePosition() | ||
21 | { | ||
22 | if (_size == _capacity) | ||
23 | { | ||
24 | unsigned newCapacity = _capacity + (_capacity >> 2) + 1; | ||
25 | T *p; | ||
26 | MY_ARRAY_NEW(p, T, newCapacity); | ||
27 | // p = new T[newCapacity]; | ||
28 | if (_size != 0) | ||
29 | memcpy(p, _items, (size_t)_size * sizeof(T)); | ||
30 | delete []_items; | ||
31 | _items = p; | ||
32 | _capacity = newCapacity; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | public: | ||
37 | |||
38 | CRecordVector(): _items(NULL), _size(0), _capacity(0) {} | ||
39 | |||
40 | CRecordVector(const CRecordVector &v): _items(0), _size(0), _capacity(0) | ||
41 | { | ||
42 | unsigned size = v.Size(); | ||
43 | if (size != 0) | ||
44 | { | ||
45 | _items = new T[size]; | ||
46 | _size = size; | ||
47 | _capacity = size; | ||
48 | memcpy(_items, v._items, (size_t)size * sizeof(T)); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | unsigned Size() const { return _size; } | ||
53 | bool IsEmpty() const { return _size == 0; } | ||
54 | |||
55 | void ConstructReserve(unsigned size) | ||
56 | { | ||
57 | if (size != 0) | ||
58 | { | ||
59 | MY_ARRAY_NEW(_items, T, size) | ||
60 | // _items = new T[size]; | ||
61 | _capacity = size; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | void Reserve(unsigned newCapacity) | ||
66 | { | ||
67 | if (newCapacity > _capacity) | ||
68 | { | ||
69 | T *p; | ||
70 | MY_ARRAY_NEW(p, T, newCapacity); | ||
71 | // p = new T[newCapacity]; | ||
72 | if (_size != 0) | ||
73 | memcpy(p, _items, (size_t)_size * sizeof(T)); | ||
74 | delete []_items; | ||
75 | _items = p; | ||
76 | _capacity = newCapacity; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | void ClearAndReserve(unsigned newCapacity) | ||
81 | { | ||
82 | Clear(); | ||
83 | if (newCapacity > _capacity) | ||
84 | { | ||
85 | delete []_items; | ||
86 | _items = NULL; | ||
87 | _capacity = 0; | ||
88 | MY_ARRAY_NEW(_items, T, newCapacity) | ||
89 | // _items = new T[newCapacity]; | ||
90 | _capacity = newCapacity; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | void ClearAndSetSize(unsigned newSize) | ||
95 | { | ||
96 | ClearAndReserve(newSize); | ||
97 | _size = newSize; | ||
98 | } | ||
99 | |||
100 | void ChangeSize_KeepData(unsigned newSize) | ||
101 | { | ||
102 | if (newSize > _capacity) | ||
103 | { | ||
104 | T *p; | ||
105 | MY_ARRAY_NEW(p, T, newSize) | ||
106 | // p = new T[newSize]; | ||
107 | if (_size != 0) | ||
108 | memcpy(p, _items, (size_t)_size * sizeof(T)); | ||
109 | delete []_items; | ||
110 | _items = p; | ||
111 | _capacity = newSize; | ||
112 | } | ||
113 | _size = newSize; | ||
114 | } | ||
115 | |||
116 | void ReserveDown() | ||
117 | { | ||
118 | if (_size == _capacity) | ||
119 | return; | ||
120 | T *p = NULL; | ||
121 | if (_size != 0) | ||
122 | { | ||
123 | p = new T[_size]; | ||
124 | memcpy(p, _items, (size_t)_size * sizeof(T)); | ||
125 | } | ||
126 | delete []_items; | ||
127 | _items = p; | ||
128 | _capacity = _size; | ||
129 | } | ||
130 | |||
131 | ~CRecordVector() { delete []_items; } | ||
132 | |||
133 | void ClearAndFree() | ||
134 | { | ||
135 | delete []_items; | ||
136 | _items = NULL; | ||
137 | _size = 0; | ||
138 | _capacity = 0; | ||
139 | } | ||
140 | |||
141 | void Clear() { _size = 0; } | ||
142 | |||
143 | void DeleteBack() { _size--; } | ||
144 | |||
145 | void DeleteFrom(unsigned index) | ||
146 | { | ||
147 | // if (index <= _size) | ||
148 | _size = index; | ||
149 | } | ||
150 | |||
151 | void DeleteFrontal(unsigned num) | ||
152 | { | ||
153 | if (num != 0) | ||
154 | { | ||
155 | MoveItems(0, num); | ||
156 | _size -= num; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void Delete(unsigned index) | ||
161 | { | ||
162 | MoveItems(index, index + 1); | ||
163 | _size -= 1; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | void Delete(unsigned index, unsigned num) | ||
168 | { | ||
169 | if (num > 0) | ||
170 | { | ||
171 | MoveItems(index, index + num); | ||
172 | _size -= num; | ||
173 | } | ||
174 | } | ||
175 | */ | ||
176 | |||
177 | CRecordVector& operator=(const CRecordVector &v) | ||
178 | { | ||
179 | if (&v == this) | ||
180 | return *this; | ||
181 | unsigned size = v.Size(); | ||
182 | if (size > _capacity) | ||
183 | { | ||
184 | delete []_items; | ||
185 | _capacity = 0; | ||
186 | _size = 0; | ||
187 | _items = NULL; | ||
188 | _items = new T[size]; | ||
189 | _capacity = size; | ||
190 | } | ||
191 | _size = size; | ||
192 | if (size != 0) | ||
193 | memcpy(_items, v._items, (size_t)size * sizeof(T)); | ||
194 | return *this; | ||
195 | } | ||
196 | |||
197 | CRecordVector& operator+=(const CRecordVector &v) | ||
198 | { | ||
199 | unsigned size = v.Size(); | ||
200 | Reserve(_size + size); | ||
201 | if (size != 0) | ||
202 | memcpy(_items + _size, v._items, (size_t)size * sizeof(T)); | ||
203 | _size += size; | ||
204 | return *this; | ||
205 | } | ||
206 | |||
207 | unsigned Add(const T item) | ||
208 | { | ||
209 | ReserveOnePosition(); | ||
210 | _items[_size] = item; | ||
211 | return _size++; | ||
212 | } | ||
213 | |||
214 | void AddInReserved(const T item) | ||
215 | { | ||
216 | _items[_size++] = item; | ||
217 | } | ||
218 | |||
219 | void Insert(unsigned index, const T item) | ||
220 | { | ||
221 | ReserveOnePosition(); | ||
222 | MoveItems(index + 1, index); | ||
223 | _items[index] = item; | ||
224 | _size++; | ||
225 | } | ||
226 | |||
227 | void MoveToFront(unsigned index) | ||
228 | { | ||
229 | if (index != 0) | ||
230 | { | ||
231 | T temp = _items[index]; | ||
232 | memmove(_items + 1, _items, (size_t)index * sizeof(T)); | ||
233 | _items[0] = temp; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | const T& operator[](unsigned index) const { return _items[index]; } | ||
238 | T& operator[](unsigned index) { return _items[index]; } | ||
239 | const T& Front() const { return _items[0]; } | ||
240 | T& Front() { return _items[0]; } | ||
241 | const T& Back() const { return _items[(size_t)_size - 1]; } | ||
242 | T& Back() { return _items[(size_t)_size - 1]; } | ||
243 | |||
244 | /* | ||
245 | void Swap(unsigned i, unsigned j) | ||
246 | { | ||
247 | T temp = _items[i]; | ||
248 | _items[i] = _items[j]; | ||
249 | _items[j] = temp; | ||
250 | } | ||
251 | */ | ||
252 | |||
253 | int FindInSorted(const T item, unsigned left, unsigned right) const | ||
254 | { | ||
255 | while (left != right) | ||
256 | { | ||
257 | unsigned mid = (left + right) / 2; | ||
258 | const T midVal = (*this)[mid]; | ||
259 | if (item == midVal) | ||
260 | return (int)mid; | ||
261 | if (item < midVal) | ||
262 | right = mid; | ||
263 | else | ||
264 | left = mid + 1; | ||
265 | } | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | int FindInSorted2(const T &item, unsigned left, unsigned right) const | ||
270 | { | ||
271 | while (left != right) | ||
272 | { | ||
273 | unsigned mid = (left + right) / 2; | ||
274 | const T& midVal = (*this)[mid]; | ||
275 | int comp = item.Compare(midVal); | ||
276 | if (comp == 0) | ||
277 | return (int)mid; | ||
278 | if (comp < 0) | ||
279 | right = mid; | ||
280 | else | ||
281 | left = mid + 1; | ||
282 | } | ||
283 | return -1; | ||
284 | } | ||
285 | |||
286 | int FindInSorted(const T item) const | ||
287 | { | ||
288 | return FindInSorted(item, 0, _size); | ||
289 | } | ||
290 | |||
291 | int FindInSorted2(const T &item) const | ||
292 | { | ||
293 | return FindInSorted2(item, 0, _size); | ||
294 | } | ||
295 | |||
296 | unsigned AddToUniqueSorted(const T item) | ||
297 | { | ||
298 | unsigned left = 0, right = _size; | ||
299 | while (left != right) | ||
300 | { | ||
301 | unsigned mid = (left + right) / 2; | ||
302 | const T midVal = (*this)[mid]; | ||
303 | if (item == midVal) | ||
304 | return mid; | ||
305 | if (item < midVal) | ||
306 | right = mid; | ||
307 | else | ||
308 | left = mid + 1; | ||
309 | } | ||
310 | Insert(right, item); | ||
311 | return right; | ||
312 | } | ||
313 | |||
314 | unsigned AddToUniqueSorted2(const T &item) | ||
315 | { | ||
316 | unsigned left = 0, right = _size; | ||
317 | while (left != right) | ||
318 | { | ||
319 | unsigned mid = (left + right) / 2; | ||
320 | const T& midVal = (*this)[mid]; | ||
321 | int comp = item.Compare(midVal); | ||
322 | if (comp == 0) | ||
323 | return mid; | ||
324 | if (comp < 0) | ||
325 | right = mid; | ||
326 | else | ||
327 | left = mid + 1; | ||
328 | } | ||
329 | Insert(right, item); | ||
330 | return right; | ||
331 | } | ||
332 | |||
333 | static void SortRefDown(T* p, unsigned k, unsigned size, int (*compare)(const T*, const T*, void *), void *param) | ||
334 | { | ||
335 | T temp = p[k]; | ||
336 | for (;;) | ||
337 | { | ||
338 | unsigned s = (k << 1); | ||
339 | if (s > size) | ||
340 | break; | ||
341 | if (s < size && compare(p + s + 1, p + s, param) > 0) | ||
342 | s++; | ||
343 | if (compare(&temp, p + s, param) >= 0) | ||
344 | break; | ||
345 | p[k] = p[s]; | ||
346 | k = s; | ||
347 | } | ||
348 | p[k] = temp; | ||
349 | } | ||
350 | |||
351 | void Sort(int (*compare)(const T*, const T*, void *), void *param) | ||
352 | { | ||
353 | unsigned size = _size; | ||
354 | if (size <= 1) | ||
355 | return; | ||
356 | T* p = (&Front()) - 1; | ||
357 | { | ||
358 | unsigned i = size >> 1; | ||
359 | do | ||
360 | SortRefDown(p, i, size, compare, param); | ||
361 | while (--i != 0); | ||
362 | } | ||
363 | do | ||
364 | { | ||
365 | T temp = p[size]; | ||
366 | p[size--] = p[1]; | ||
367 | p[1] = temp; | ||
368 | SortRefDown(p, 1, size, compare, param); | ||
369 | } | ||
370 | while (size > 1); | ||
371 | } | ||
372 | |||
373 | static void SortRefDown2(T* p, unsigned k, unsigned size) | ||
374 | { | ||
375 | T temp = p[k]; | ||
376 | for (;;) | ||
377 | { | ||
378 | unsigned s = (k << 1); | ||
379 | if (s > size) | ||
380 | break; | ||
381 | if (s < size && p[(size_t)s + 1].Compare(p[s]) > 0) | ||
382 | s++; | ||
383 | if (temp.Compare(p[s]) >= 0) | ||
384 | break; | ||
385 | p[k] = p[s]; | ||
386 | k = s; | ||
387 | } | ||
388 | p[k] = temp; | ||
389 | } | ||
390 | |||
391 | void Sort2() | ||
392 | { | ||
393 | unsigned size = _size; | ||
394 | if (size <= 1) | ||
395 | return; | ||
396 | T* p = (&Front()) - 1; | ||
397 | { | ||
398 | unsigned i = size >> 1; | ||
399 | do | ||
400 | SortRefDown2(p, i, size); | ||
401 | while (--i != 0); | ||
402 | } | ||
403 | do | ||
404 | { | ||
405 | T temp = p[size]; | ||
406 | p[size--] = p[1]; | ||
407 | p[1] = temp; | ||
408 | SortRefDown2(p, 1, size); | ||
409 | } | ||
410 | while (size > 1); | ||
411 | } | ||
412 | }; | ||
413 | |||
414 | typedef CRecordVector<int> CIntVector; | ||
415 | typedef CRecordVector<unsigned int> CUIntVector; | ||
416 | typedef CRecordVector<bool> CBoolVector; | ||
417 | typedef CRecordVector<unsigned char> CByteVector; | ||
418 | typedef CRecordVector<void *> CPointerVector; | ||
419 | |||
420 | template <class T> | ||
421 | class CObjectVector | ||
422 | { | ||
423 | CPointerVector _v; | ||
424 | public: | ||
425 | unsigned Size() const { return _v.Size(); } | ||
426 | bool IsEmpty() const { return _v.IsEmpty(); } | ||
427 | void ReserveDown() { _v.ReserveDown(); } | ||
428 | // void Reserve(unsigned newCapacity) { _v.Reserve(newCapacity); } | ||
429 | void ClearAndReserve(unsigned newCapacity) { Clear(); _v.ClearAndReserve(newCapacity); } | ||
430 | |||
431 | CObjectVector() {} | ||
432 | CObjectVector(const CObjectVector &v) | ||
433 | { | ||
434 | unsigned size = v.Size(); | ||
435 | _v.ConstructReserve(size); | ||
436 | for (unsigned i = 0; i < size; i++) | ||
437 | _v.AddInReserved(new T(v[i])); | ||
438 | } | ||
439 | CObjectVector& operator=(const CObjectVector &v) | ||
440 | { | ||
441 | if (&v == this) | ||
442 | return *this; | ||
443 | Clear(); | ||
444 | unsigned size = v.Size(); | ||
445 | _v.Reserve(size); | ||
446 | for (unsigned i = 0; i < size; i++) | ||
447 | _v.AddInReserved(new T(v[i])); | ||
448 | return *this; | ||
449 | } | ||
450 | |||
451 | CObjectVector& operator+=(const CObjectVector &v) | ||
452 | { | ||
453 | unsigned size = v.Size(); | ||
454 | _v.Reserve(Size() + size); | ||
455 | for (unsigned i = 0; i < size; i++) | ||
456 | _v.AddInReserved(new T(v[i])); | ||
457 | return *this; | ||
458 | } | ||
459 | |||
460 | const T& operator[](unsigned index) const { return *((T *)_v[index]); } | ||
461 | T& operator[](unsigned index) { return *((T *)_v[index]); } | ||
462 | const T& Front() const { return operator[](0); } | ||
463 | T& Front() { return operator[](0); } | ||
464 | const T& Back() const { return *(T *)_v.Back(); } | ||
465 | T& Back() { return *(T *)_v.Back(); } | ||
466 | |||
467 | void MoveToFront(unsigned index) { _v.MoveToFront(index); } | ||
468 | |||
469 | unsigned Add(const T& item) { return _v.Add(new T(item)); } | ||
470 | |||
471 | void AddInReserved(const T& item) { _v.AddInReserved(new T(item)); } | ||
472 | |||
473 | T& AddNew() | ||
474 | { | ||
475 | T *p = new T; | ||
476 | _v.Add(p); | ||
477 | return *p; | ||
478 | } | ||
479 | |||
480 | T& AddNewInReserved() | ||
481 | { | ||
482 | T *p = new T; | ||
483 | _v.AddInReserved(p); | ||
484 | return *p; | ||
485 | } | ||
486 | |||
487 | void Insert(unsigned index, const T& item) { _v.Insert(index, new T(item)); } | ||
488 | |||
489 | T& InsertNew(unsigned index) | ||
490 | { | ||
491 | T *p = new T; | ||
492 | _v.Insert(index, p); | ||
493 | return *p; | ||
494 | } | ||
495 | |||
496 | ~CObjectVector() | ||
497 | { | ||
498 | for (unsigned i = _v.Size(); i != 0;) | ||
499 | delete (T *)_v[--i]; | ||
500 | } | ||
501 | |||
502 | void ClearAndFree() | ||
503 | { | ||
504 | Clear(); | ||
505 | _v.ClearAndFree(); | ||
506 | } | ||
507 | |||
508 | void Clear() | ||
509 | { | ||
510 | for (unsigned i = _v.Size(); i != 0;) | ||
511 | delete (T *)_v[--i]; | ||
512 | _v.Clear(); | ||
513 | } | ||
514 | |||
515 | void DeleteFrom(unsigned index) | ||
516 | { | ||
517 | unsigned size = _v.Size(); | ||
518 | for (unsigned i = index; i < size; i++) | ||
519 | delete (T *)_v[i]; | ||
520 | _v.DeleteFrom(index); | ||
521 | } | ||
522 | |||
523 | void DeleteFrontal(unsigned num) | ||
524 | { | ||
525 | for (unsigned i = 0; i < num; i++) | ||
526 | delete (T *)_v[i]; | ||
527 | _v.DeleteFrontal(num); | ||
528 | } | ||
529 | |||
530 | void DeleteBack() | ||
531 | { | ||
532 | delete (T *)_v.Back(); | ||
533 | _v.DeleteBack(); | ||
534 | } | ||
535 | |||
536 | void Delete(unsigned index) | ||
537 | { | ||
538 | delete (T *)_v[index]; | ||
539 | _v.Delete(index); | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | void Delete(unsigned index, unsigned num) | ||
544 | { | ||
545 | for (unsigned i = 0; i < num; i++) | ||
546 | delete (T *)_v[index + i]; | ||
547 | _v.Delete(index, num); | ||
548 | } | ||
549 | */ | ||
550 | |||
551 | /* | ||
552 | int Find(const T& item) const | ||
553 | { | ||
554 | unsigned size = Size(); | ||
555 | for (unsigned i = 0; i < size; i++) | ||
556 | if (item == (*this)[i]) | ||
557 | return i; | ||
558 | return -1; | ||
559 | } | ||
560 | */ | ||
561 | |||
562 | int FindInSorted(const T& item) const | ||
563 | { | ||
564 | unsigned left = 0, right = Size(); | ||
565 | while (left != right) | ||
566 | { | ||
567 | unsigned mid = (left + right) / 2; | ||
568 | const T& midVal = (*this)[mid]; | ||
569 | int comp = item.Compare(midVal); | ||
570 | if (comp == 0) | ||
571 | return (int)mid; | ||
572 | if (comp < 0) | ||
573 | right = mid; | ||
574 | else | ||
575 | left = mid + 1; | ||
576 | } | ||
577 | return -1; | ||
578 | } | ||
579 | |||
580 | unsigned AddToUniqueSorted(const T& item) | ||
581 | { | ||
582 | unsigned left = 0, right = Size(); | ||
583 | while (left != right) | ||
584 | { | ||
585 | unsigned mid = (left + right) / 2; | ||
586 | const T& midVal = (*this)[mid]; | ||
587 | int comp = item.Compare(midVal); | ||
588 | if (comp == 0) | ||
589 | return mid; | ||
590 | if (comp < 0) | ||
591 | right = mid; | ||
592 | else | ||
593 | left = mid + 1; | ||
594 | } | ||
595 | Insert(right, item); | ||
596 | return right; | ||
597 | } | ||
598 | |||
599 | /* | ||
600 | unsigned AddToSorted(const T& item) | ||
601 | { | ||
602 | unsigned left = 0, right = Size(); | ||
603 | while (left != right) | ||
604 | { | ||
605 | unsigned mid = (left + right) / 2; | ||
606 | const T& midVal = (*this)[mid]; | ||
607 | int comp = item.Compare(midVal); | ||
608 | if (comp == 0) | ||
609 | { | ||
610 | right = mid + 1; | ||
611 | break; | ||
612 | } | ||
613 | if (comp < 0) | ||
614 | right = mid; | ||
615 | else | ||
616 | left = mid + 1; | ||
617 | } | ||
618 | Insert(right, item); | ||
619 | return right; | ||
620 | } | ||
621 | */ | ||
622 | |||
623 | void Sort(int (*compare)(void *const *, void *const *, void *), void *param) | ||
624 | { _v.Sort(compare, param); } | ||
625 | |||
626 | static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */) | ||
627 | { return (*(*((const T *const *)a1))).Compare(*(*((const T *const *)a2))); } | ||
628 | |||
629 | void Sort() { _v.Sort(CompareObjectItems, NULL); } | ||
630 | }; | ||
631 | |||
632 | #define FOR_VECTOR(_i_, _v_) for (unsigned _i_ = 0; _i_ < (_v_).Size(); _i_++) | ||
633 | |||
634 | #endif | ||
diff --git a/CPP/Common/MyWindows.cpp b/CPP/Common/MyWindows.cpp new file mode 100644 index 0000000..88f312f --- /dev/null +++ b/CPP/Common/MyWindows.cpp | |||
@@ -0,0 +1,292 @@ | |||
1 | // MyWindows.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #ifndef _WIN32 | ||
6 | |||
7 | #include <stdlib.h> | ||
8 | #include <time.h> | ||
9 | #ifdef __GNUC__ | ||
10 | #include <sys/time.h> | ||
11 | #endif | ||
12 | |||
13 | #include "MyWindows.h" | ||
14 | |||
15 | static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); } | ||
16 | static inline void FreeForBSTR(void *pv) { ::free(pv);} | ||
17 | |||
18 | /* Win32 uses DWORD (32-bit) type to store size of string before (OLECHAR *) string. | ||
19 | We must select CBstrSizeType for another systems (not Win32): | ||
20 | |||
21 | if (CBstrSizeType is UINT32), | ||
22 | then we support only strings smaller than 4 GB. | ||
23 | Win32 version always has that limitation. | ||
24 | |||
25 | if (CBstrSizeType is UINT), | ||
26 | (UINT can be 16/32/64-bit) | ||
27 | We can support strings larger than 4 GB (if UINT is 64-bit), | ||
28 | but sizeof(UINT) can be different in parts compiled by | ||
29 | different compilers/settings, | ||
30 | and we can't send such BSTR strings between such parts. | ||
31 | */ | ||
32 | |||
33 | typedef UINT32 CBstrSizeType; | ||
34 | // typedef UINT CBstrSizeType; | ||
35 | |||
36 | #define k_BstrSize_Max 0xFFFFFFFF | ||
37 | // #define k_BstrSize_Max UINT_MAX | ||
38 | // #define k_BstrSize_Max ((UINT)(INT)-1) | ||
39 | |||
40 | BSTR SysAllocStringByteLen(LPCSTR s, UINT len) | ||
41 | { | ||
42 | /* Original SysAllocStringByteLen in Win32 maybe fills only unaligned null OLECHAR at the end. | ||
43 | We provide also aligned null OLECHAR at the end. */ | ||
44 | |||
45 | if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType))) | ||
46 | return NULL; | ||
47 | |||
48 | UINT size = (len + (UINT)sizeof(OLECHAR) + (UINT)sizeof(OLECHAR) - 1) & ~((UINT)sizeof(OLECHAR) - 1); | ||
49 | void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType)); | ||
50 | if (!p) | ||
51 | return NULL; | ||
52 | *(CBstrSizeType *)p = (CBstrSizeType)len; | ||
53 | BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); | ||
54 | if (s) | ||
55 | memcpy(bstr, s, len); | ||
56 | for (; len < size; len++) | ||
57 | ((Byte *)bstr)[len] = 0; | ||
58 | return bstr; | ||
59 | } | ||
60 | |||
61 | BSTR SysAllocStringLen(const OLECHAR *s, UINT len) | ||
62 | { | ||
63 | if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType)) / (UINT)sizeof(OLECHAR)) | ||
64 | return NULL; | ||
65 | |||
66 | UINT size = len * (UINT)sizeof(OLECHAR); | ||
67 | void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType) + (UINT)sizeof(OLECHAR)); | ||
68 | if (!p) | ||
69 | return NULL; | ||
70 | *(CBstrSizeType *)p = (CBstrSizeType)size; | ||
71 | BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); | ||
72 | if (s) | ||
73 | memcpy(bstr, s, size); | ||
74 | bstr[len] = 0; | ||
75 | return bstr; | ||
76 | } | ||
77 | |||
78 | BSTR SysAllocString(const OLECHAR *s) | ||
79 | { | ||
80 | if (!s) | ||
81 | return 0; | ||
82 | const OLECHAR *s2 = s; | ||
83 | while (*s2 != 0) | ||
84 | s2++; | ||
85 | return SysAllocStringLen(s, (UINT)(s2 - s)); | ||
86 | } | ||
87 | |||
88 | void SysFreeString(BSTR bstr) | ||
89 | { | ||
90 | if (bstr) | ||
91 | FreeForBSTR((CBstrSizeType *)bstr - 1); | ||
92 | } | ||
93 | |||
94 | UINT SysStringByteLen(BSTR bstr) | ||
95 | { | ||
96 | if (!bstr) | ||
97 | return 0; | ||
98 | return *((CBstrSizeType *)bstr - 1); | ||
99 | } | ||
100 | |||
101 | UINT SysStringLen(BSTR bstr) | ||
102 | { | ||
103 | if (!bstr) | ||
104 | return 0; | ||
105 | return *((CBstrSizeType *)bstr - 1) / (UINT)sizeof(OLECHAR); | ||
106 | } | ||
107 | |||
108 | |||
109 | HRESULT VariantClear(VARIANTARG *prop) | ||
110 | { | ||
111 | if (prop->vt == VT_BSTR) | ||
112 | SysFreeString(prop->bstrVal); | ||
113 | prop->vt = VT_EMPTY; | ||
114 | return S_OK; | ||
115 | } | ||
116 | |||
117 | HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src) | ||
118 | { | ||
119 | HRESULT res = ::VariantClear(dest); | ||
120 | if (res != S_OK) | ||
121 | return res; | ||
122 | if (src->vt == VT_BSTR) | ||
123 | { | ||
124 | dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal, | ||
125 | SysStringByteLen(src->bstrVal)); | ||
126 | if (!dest->bstrVal) | ||
127 | return E_OUTOFMEMORY; | ||
128 | dest->vt = VT_BSTR; | ||
129 | } | ||
130 | else | ||
131 | *dest = *src; | ||
132 | return S_OK; | ||
133 | } | ||
134 | |||
135 | LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2) | ||
136 | { | ||
137 | if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1; | ||
138 | if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1; | ||
139 | if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1; | ||
140 | if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1; | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | DWORD GetLastError() | ||
145 | { | ||
146 | return (DWORD)errno; | ||
147 | } | ||
148 | |||
149 | void SetLastError(DWORD dw) | ||
150 | { | ||
151 | errno = (int)dw; | ||
152 | } | ||
153 | |||
154 | |||
155 | static LONG TIME_GetBias() | ||
156 | { | ||
157 | time_t utc = time(NULL); | ||
158 | struct tm *ptm = localtime(&utc); | ||
159 | int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ | ||
160 | ptm = gmtime(&utc); | ||
161 | ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ | ||
162 | LONG bias = (int)(mktime(ptm)-utc); | ||
163 | return bias; | ||
164 | } | ||
165 | |||
166 | #define TICKS_PER_SEC 10000000 | ||
167 | /* | ||
168 | #define SECS_PER_DAY (24 * 60 * 60) | ||
169 | #define SECS_1601_TO_1970 ((369 * 365 + 89) * (UInt64)SECS_PER_DAY) | ||
170 | #define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKS_PER_SEC) | ||
171 | */ | ||
172 | |||
173 | #define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) | ||
174 | |||
175 | #define SET_FILETIME(ft, v64) \ | ||
176 | (ft)->dwLowDateTime = (DWORD)v64; \ | ||
177 | (ft)->dwHighDateTime = (DWORD)(v64 >> 32); | ||
178 | |||
179 | |||
180 | BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) | ||
181 | { | ||
182 | UInt64 v = GET_TIME_64(fileTime); | ||
183 | v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); | ||
184 | SET_FILETIME(localFileTime, v); | ||
185 | return TRUE; | ||
186 | } | ||
187 | |||
188 | BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime) | ||
189 | { | ||
190 | UInt64 v = GET_TIME_64(localFileTime); | ||
191 | v = (UInt64)((Int64)v + (Int64)TIME_GetBias() * TICKS_PER_SEC); | ||
192 | SET_FILETIME(fileTime, v); | ||
193 | return TRUE; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | VOID WINAPI GetSystemTimeAsFileTime(FILETIME *ft) | ||
198 | { | ||
199 | UInt64 t = 0; | ||
200 | timeval tv; | ||
201 | if (gettimeofday(&tv, NULL) == 0) | ||
202 | { | ||
203 | t = tv.tv_sec * (UInt64)TICKS_PER_SEC + TICKS_1601_TO_1970; | ||
204 | t += tv.tv_usec * 10; | ||
205 | } | ||
206 | SET_FILETIME(ft, t); | ||
207 | } | ||
208 | */ | ||
209 | |||
210 | DWORD WINAPI GetTickCount(VOID) | ||
211 | { | ||
212 | #ifndef _WIN32 | ||
213 | // gettimeofday() doesn't work in some MINGWs by unknown reason | ||
214 | timeval tv; | ||
215 | if (gettimeofday(&tv, NULL) == 0) | ||
216 | { | ||
217 | // tv_sec and tv_usec are (long) | ||
218 | return (DWORD)((UInt64)(Int64)tv.tv_sec * (UInt64)1000 + (UInt64)(Int64)tv.tv_usec / 1000); | ||
219 | } | ||
220 | #endif | ||
221 | return (DWORD)time(NULL) * 1000; | ||
222 | } | ||
223 | |||
224 | |||
225 | #define PERIOD_4 (4 * 365 + 1) | ||
226 | #define PERIOD_100 (PERIOD_4 * 25 - 1) | ||
227 | #define PERIOD_400 (PERIOD_100 * 4 + 1) | ||
228 | |||
229 | BOOL WINAPI FileTimeToSystemTime(const FILETIME *ft, SYSTEMTIME *st) | ||
230 | { | ||
231 | UInt32 v; | ||
232 | UInt64 v64 = GET_TIME_64(ft); | ||
233 | v64 /= 10000; | ||
234 | st->wMilliseconds = (WORD)(v64 % 1000); v64 /= 1000; | ||
235 | st->wSecond = (WORD)(v64 % 60); v64 /= 60; | ||
236 | st->wMinute = (WORD)(v64 % 60); v64 /= 60; | ||
237 | v = (UInt32)v64; | ||
238 | st->wHour = (WORD)(v % 24); v /= 24; | ||
239 | |||
240 | // 1601-01-01 was Monday | ||
241 | st->wDayOfWeek = (WORD)((v + 1) % 7); | ||
242 | |||
243 | UInt32 leaps, year, day, mon; | ||
244 | leaps = (3 * ((4 * v + (365 - 31 - 28) * 4 + 3) / PERIOD_400) + 3) / 4; | ||
245 | v += 28188 + leaps; | ||
246 | // leaps - the number of exceptions from PERIOD_4 rules starting from 1600-03-01 | ||
247 | // (1959 / 64) - converts day from 03-01 to month | ||
248 | year = (20 * v - 2442) / (5 * PERIOD_4); | ||
249 | day = v - (year * PERIOD_4) / 4; | ||
250 | mon = (64 * day) / 1959; | ||
251 | st->wDay = (WORD)(day - (1959 * mon) / 64); | ||
252 | mon -= 1; | ||
253 | year += 1524; | ||
254 | if (mon > 12) | ||
255 | { | ||
256 | mon -= 12; | ||
257 | year++; | ||
258 | } | ||
259 | st->wMonth = (WORD)mon; | ||
260 | st->wYear = (WORD)year; | ||
261 | |||
262 | /* | ||
263 | unsigned year, mon; | ||
264 | unsigned char ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
265 | unsigned t; | ||
266 | |||
267 | year = (WORD)(1601 + v / PERIOD_400 * 400); | ||
268 | v %= PERIOD_400; | ||
269 | |||
270 | t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; | ||
271 | t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; | ||
272 | t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; | ||
273 | |||
274 | st->wYear = (WORD)year; | ||
275 | |||
276 | if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) | ||
277 | ms[1] = 29; | ||
278 | for (mon = 0;; mon++) | ||
279 | { | ||
280 | unsigned d = ms[mon]; | ||
281 | if (v < d) | ||
282 | break; | ||
283 | v -= d; | ||
284 | } | ||
285 | st->wDay = (WORD)(v + 1); | ||
286 | st->wMonth = (WORD)(mon + 1); | ||
287 | */ | ||
288 | |||
289 | return TRUE; | ||
290 | } | ||
291 | |||
292 | #endif | ||
diff --git a/CPP/Common/MyWindows.h b/CPP/Common/MyWindows.h new file mode 100644 index 0000000..0664a5e --- /dev/null +++ b/CPP/Common/MyWindows.h | |||
@@ -0,0 +1,268 @@ | |||
1 | // MyWindows.h | ||
2 | |||
3 | #ifndef __MY_WINDOWS_H | ||
4 | #define __MY_WINDOWS_H | ||
5 | |||
6 | #ifdef _WIN32 | ||
7 | |||
8 | #include <Windows.h> | ||
9 | |||
10 | #ifdef UNDER_CE | ||
11 | #undef VARIANT_TRUE | ||
12 | #define VARIANT_TRUE ((VARIANT_BOOL)-1) | ||
13 | #endif | ||
14 | |||
15 | #else // _WIN32 | ||
16 | |||
17 | #include <stddef.h> // for wchar_t | ||
18 | #include <string.h> | ||
19 | // #include <stdint.h> // for uintptr_t | ||
20 | |||
21 | #include "MyGuidDef.h" | ||
22 | |||
23 | // WINAPI is __stdcall in Windows-MSVC in windef.h | ||
24 | #define WINAPI | ||
25 | #define EXTERN_C MY_EXTERN_C | ||
26 | |||
27 | typedef char CHAR; | ||
28 | typedef unsigned char UCHAR; | ||
29 | |||
30 | #undef BYTE | ||
31 | typedef unsigned char BYTE; | ||
32 | |||
33 | typedef short SHORT; | ||
34 | typedef unsigned short USHORT; | ||
35 | |||
36 | #undef WORD | ||
37 | typedef unsigned short WORD; | ||
38 | typedef short VARIANT_BOOL; | ||
39 | |||
40 | #define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) | ||
41 | #define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) | ||
42 | |||
43 | // MS uses long for BOOL, but long is 32-bit in MS. So we use int. | ||
44 | // typedef long BOOL; | ||
45 | typedef int BOOL; | ||
46 | |||
47 | #ifndef FALSE | ||
48 | #define FALSE 0 | ||
49 | #define TRUE 1 | ||
50 | #endif | ||
51 | |||
52 | // typedef size_t ULONG_PTR; | ||
53 | // typedef size_t DWORD_PTR; | ||
54 | // typedef uintptr_t UINT_PTR; | ||
55 | // typedef ptrdiff_t UINT_PTR; | ||
56 | |||
57 | typedef Int64 LONGLONG; | ||
58 | typedef UInt64 ULONGLONG; | ||
59 | |||
60 | typedef struct _LARGE_INTEGER { LONGLONG QuadPart; } LARGE_INTEGER; | ||
61 | typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart; } ULARGE_INTEGER; | ||
62 | |||
63 | typedef const CHAR *LPCSTR; | ||
64 | typedef CHAR TCHAR; | ||
65 | typedef const TCHAR *LPCTSTR; | ||
66 | typedef wchar_t WCHAR; | ||
67 | typedef WCHAR OLECHAR; | ||
68 | typedef const WCHAR *LPCWSTR; | ||
69 | typedef OLECHAR *BSTR; | ||
70 | typedef const OLECHAR *LPCOLESTR; | ||
71 | typedef OLECHAR *LPOLESTR; | ||
72 | |||
73 | typedef struct _FILETIME | ||
74 | { | ||
75 | DWORD dwLowDateTime; | ||
76 | DWORD dwHighDateTime; | ||
77 | } FILETIME; | ||
78 | |||
79 | #define HRESULT LONG | ||
80 | #define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) | ||
81 | #define FAILED(hr) ((HRESULT)(hr) < 0) | ||
82 | typedef ULONG PROPID; | ||
83 | typedef LONG SCODE; | ||
84 | |||
85 | |||
86 | #define S_OK ((HRESULT)0x00000000L) | ||
87 | #define S_FALSE ((HRESULT)0x00000001L) | ||
88 | #define E_NOTIMPL ((HRESULT)0x80004001L) | ||
89 | #define E_NOINTERFACE ((HRESULT)0x80004002L) | ||
90 | #define E_ABORT ((HRESULT)0x80004004L) | ||
91 | #define E_FAIL ((HRESULT)0x80004005L) | ||
92 | #define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) | ||
93 | #define CLASS_E_CLASSNOTAVAILABLE ((HRESULT)0x80040111L) | ||
94 | |||
95 | |||
96 | #ifdef _MSC_VER | ||
97 | #define STDMETHODCALLTYPE __stdcall | ||
98 | #define STDAPICALLTYPE __stdcall | ||
99 | #else | ||
100 | // do we need __export here? | ||
101 | #define STDMETHODCALLTYPE | ||
102 | #define STDAPICALLTYPE | ||
103 | #endif | ||
104 | |||
105 | #define STDAPI EXTERN_C HRESULT STDAPICALLTYPE | ||
106 | |||
107 | #define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f | ||
108 | #define STDMETHOD(f) STDMETHOD_(HRESULT, f) | ||
109 | #define STDMETHODIMP_(type) type STDMETHODCALLTYPE | ||
110 | #define STDMETHODIMP STDMETHODIMP_(HRESULT) | ||
111 | |||
112 | #define PURE = 0 | ||
113 | |||
114 | #define MIDL_INTERFACE(x) struct | ||
115 | |||
116 | #ifdef __cplusplus | ||
117 | |||
118 | DEFINE_GUID(IID_IUnknown, | ||
119 | 0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); | ||
120 | struct IUnknown | ||
121 | { | ||
122 | STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE; | ||
123 | STDMETHOD_(ULONG, AddRef)() PURE; | ||
124 | STDMETHOD_(ULONG, Release)() PURE; | ||
125 | virtual ~IUnknown() {} | ||
126 | // We use virtual ~IUnknown() here for binary compatibility with 7z.so from p7zip | ||
127 | }; | ||
128 | |||
129 | typedef IUnknown *LPUNKNOWN; | ||
130 | |||
131 | #endif | ||
132 | |||
133 | #define VARIANT_TRUE ((VARIANT_BOOL)-1) | ||
134 | #define VARIANT_FALSE ((VARIANT_BOOL)0) | ||
135 | |||
136 | enum VARENUM | ||
137 | { | ||
138 | VT_EMPTY = 0, | ||
139 | VT_NULL = 1, | ||
140 | VT_I2 = 2, | ||
141 | VT_I4 = 3, | ||
142 | VT_R4 = 4, | ||
143 | VT_R8 = 5, | ||
144 | VT_CY = 6, | ||
145 | VT_DATE = 7, | ||
146 | VT_BSTR = 8, | ||
147 | VT_DISPATCH = 9, | ||
148 | VT_ERROR = 10, | ||
149 | VT_BOOL = 11, | ||
150 | VT_VARIANT = 12, | ||
151 | VT_UNKNOWN = 13, | ||
152 | VT_DECIMAL = 14, | ||
153 | VT_I1 = 16, | ||
154 | VT_UI1 = 17, | ||
155 | VT_UI2 = 18, | ||
156 | VT_UI4 = 19, | ||
157 | VT_I8 = 20, | ||
158 | VT_UI8 = 21, | ||
159 | VT_INT = 22, | ||
160 | VT_UINT = 23, | ||
161 | VT_VOID = 24, | ||
162 | VT_HRESULT = 25, | ||
163 | VT_FILETIME = 64 | ||
164 | }; | ||
165 | |||
166 | typedef unsigned short VARTYPE; | ||
167 | typedef WORD PROPVAR_PAD1; | ||
168 | typedef WORD PROPVAR_PAD2; | ||
169 | typedef WORD PROPVAR_PAD3; | ||
170 | |||
171 | typedef struct tagPROPVARIANT | ||
172 | { | ||
173 | VARTYPE vt; | ||
174 | PROPVAR_PAD1 wReserved1; | ||
175 | PROPVAR_PAD2 wReserved2; | ||
176 | PROPVAR_PAD3 wReserved3; | ||
177 | union | ||
178 | { | ||
179 | CHAR cVal; | ||
180 | UCHAR bVal; | ||
181 | SHORT iVal; | ||
182 | USHORT uiVal; | ||
183 | LONG lVal; | ||
184 | ULONG ulVal; | ||
185 | INT intVal; | ||
186 | UINT uintVal; | ||
187 | LARGE_INTEGER hVal; | ||
188 | ULARGE_INTEGER uhVal; | ||
189 | VARIANT_BOOL boolVal; | ||
190 | SCODE scode; | ||
191 | FILETIME filetime; | ||
192 | BSTR bstrVal; | ||
193 | }; | ||
194 | } PROPVARIANT; | ||
195 | |||
196 | typedef PROPVARIANT tagVARIANT; | ||
197 | typedef tagVARIANT VARIANT; | ||
198 | typedef VARIANT VARIANTARG; | ||
199 | |||
200 | MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop); | ||
201 | MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src); | ||
202 | |||
203 | typedef struct tagSTATPROPSTG | ||
204 | { | ||
205 | LPOLESTR lpwstrName; | ||
206 | PROPID propid; | ||
207 | VARTYPE vt; | ||
208 | } STATPROPSTG; | ||
209 | |||
210 | MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len); | ||
211 | MY_EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len); | ||
212 | MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz); | ||
213 | MY_EXTERN_C void SysFreeString(BSTR bstr); | ||
214 | MY_EXTERN_C UINT SysStringByteLen(BSTR bstr); | ||
215 | MY_EXTERN_C UINT SysStringLen(BSTR bstr); | ||
216 | |||
217 | MY_EXTERN_C DWORD GetLastError(); | ||
218 | MY_EXTERN_C void SetLastError(DWORD dwCode); | ||
219 | MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2); | ||
220 | |||
221 | MY_EXTERN_C DWORD GetCurrentThreadId(); | ||
222 | MY_EXTERN_C DWORD GetCurrentProcessId(); | ||
223 | |||
224 | #define MAX_PATH 1024 | ||
225 | |||
226 | #define CP_ACP 0 | ||
227 | #define CP_OEMCP 1 | ||
228 | #define CP_UTF8 65001 | ||
229 | |||
230 | typedef enum tagSTREAM_SEEK | ||
231 | { | ||
232 | STREAM_SEEK_SET = 0, | ||
233 | STREAM_SEEK_CUR = 1, | ||
234 | STREAM_SEEK_END = 2 | ||
235 | } STREAM_SEEK; | ||
236 | |||
237 | |||
238 | |||
239 | typedef struct _SYSTEMTIME | ||
240 | { | ||
241 | WORD wYear; | ||
242 | WORD wMonth; | ||
243 | WORD wDayOfWeek; | ||
244 | WORD wDay; | ||
245 | WORD wHour; | ||
246 | WORD wMinute; | ||
247 | WORD wSecond; | ||
248 | WORD wMilliseconds; | ||
249 | } SYSTEMTIME; | ||
250 | |||
251 | BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime); | ||
252 | BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime); | ||
253 | BOOL WINAPI FileTimeToSystemTime(const FILETIME *fileTime, SYSTEMTIME *systemTime); | ||
254 | // VOID WINAPI GetSystemTimeAsFileTime(FILETIME *systemTimeAsFileTime); | ||
255 | |||
256 | DWORD GetTickCount(); | ||
257 | |||
258 | |||
259 | #define CREATE_NEW 1 | ||
260 | #define CREATE_ALWAYS 2 | ||
261 | #define OPEN_EXISTING 3 | ||
262 | #define OPEN_ALWAYS 4 | ||
263 | #define TRUNCATE_EXISTING 5 | ||
264 | |||
265 | |||
266 | #endif // _WIN32 | ||
267 | |||
268 | #endif | ||
diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp new file mode 100644 index 0000000..e014518 --- /dev/null +++ b/CPP/Common/MyXml.cpp | |||
@@ -0,0 +1,260 @@ | |||
1 | // MyXml.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "MyXml.h" | ||
6 | |||
7 | static bool IsValidChar(char c) | ||
8 | { | ||
9 | return | ||
10 | (c >= 'a' && c <= 'z') || | ||
11 | (c >= 'A' && c <= 'Z') || | ||
12 | (c >= '0' && c <= '9') || | ||
13 | c == '-'; | ||
14 | } | ||
15 | |||
16 | static bool IsSpaceChar(char c) | ||
17 | { | ||
18 | return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A); | ||
19 | } | ||
20 | |||
21 | #define SKIP_SPACES(s) while (IsSpaceChar(*s)) s++; | ||
22 | |||
23 | int CXmlItem::FindProp(const char *propName) const throw() | ||
24 | { | ||
25 | FOR_VECTOR (i, Props) | ||
26 | if (Props[i].Name == propName) | ||
27 | return (int)i; | ||
28 | return -1; | ||
29 | } | ||
30 | |||
31 | AString CXmlItem::GetPropVal(const char *propName) const | ||
32 | { | ||
33 | int index = FindProp(propName); | ||
34 | if (index >= 0) | ||
35 | return Props[(unsigned)index].Value; | ||
36 | return AString(); | ||
37 | } | ||
38 | |||
39 | bool CXmlItem::IsTagged(const char *tag) const throw() | ||
40 | { | ||
41 | return (IsTag && Name == tag); | ||
42 | } | ||
43 | |||
44 | int CXmlItem::FindSubTag(const char *tag) const throw() | ||
45 | { | ||
46 | FOR_VECTOR (i, SubItems) | ||
47 | if (SubItems[i].IsTagged(tag)) | ||
48 | return (int)i; | ||
49 | return -1; | ||
50 | } | ||
51 | |||
52 | AString CXmlItem::GetSubString() const | ||
53 | { | ||
54 | if (SubItems.Size() == 1) | ||
55 | { | ||
56 | const CXmlItem &item = SubItems[0]; | ||
57 | if (!item.IsTag) | ||
58 | return item.Name; | ||
59 | } | ||
60 | return AString(); | ||
61 | } | ||
62 | |||
63 | const AString * CXmlItem::GetSubStringPtr() const throw() | ||
64 | { | ||
65 | if (SubItems.Size() == 1) | ||
66 | { | ||
67 | const CXmlItem &item = SubItems[0]; | ||
68 | if (!item.IsTag) | ||
69 | return &item.Name; | ||
70 | } | ||
71 | return NULL; | ||
72 | } | ||
73 | |||
74 | AString CXmlItem::GetSubStringForTag(const char *tag) const | ||
75 | { | ||
76 | int index = FindSubTag(tag); | ||
77 | if (index >= 0) | ||
78 | return SubItems[(unsigned)index].GetSubString(); | ||
79 | return AString(); | ||
80 | } | ||
81 | |||
82 | const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels) | ||
83 | { | ||
84 | SKIP_SPACES(s); | ||
85 | |||
86 | const char *beg = s; | ||
87 | for (;;) | ||
88 | { | ||
89 | char c; | ||
90 | c = *s; if (c == 0 || c == '<') break; s++; | ||
91 | c = *s; if (c == 0 || c == '<') break; s++; | ||
92 | } | ||
93 | if (*s == 0) | ||
94 | return NULL; | ||
95 | if (s != beg) | ||
96 | { | ||
97 | IsTag = false; | ||
98 | Name.SetFrom(beg, (unsigned)(s - beg)); | ||
99 | return s; | ||
100 | } | ||
101 | |||
102 | IsTag = true; | ||
103 | |||
104 | s++; | ||
105 | SKIP_SPACES(s); | ||
106 | |||
107 | beg = s; | ||
108 | for (;; s++) | ||
109 | if (!IsValidChar(*s)) | ||
110 | break; | ||
111 | if (s == beg || *s == 0) | ||
112 | return NULL; | ||
113 | Name.SetFrom(beg, (unsigned)(s - beg)); | ||
114 | |||
115 | for (;;) | ||
116 | { | ||
117 | beg = s; | ||
118 | SKIP_SPACES(s); | ||
119 | if (*s == '/') | ||
120 | { | ||
121 | s++; | ||
122 | // SKIP_SPACES(s); | ||
123 | if (*s != '>') | ||
124 | return NULL; | ||
125 | return s + 1; | ||
126 | } | ||
127 | if (*s == '>') | ||
128 | { | ||
129 | s++; | ||
130 | if (numAllowedLevels == 0) | ||
131 | return NULL; | ||
132 | SubItems.Clear(); | ||
133 | for (;;) | ||
134 | { | ||
135 | SKIP_SPACES(s); | ||
136 | if (s[0] == '<' && s[1] == '/') | ||
137 | break; | ||
138 | CXmlItem &item = SubItems.AddNew(); | ||
139 | s = item.ParseItem(s, numAllowedLevels - 1); | ||
140 | if (!s) | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | s += 2; | ||
145 | unsigned len = Name.Len(); | ||
146 | for (unsigned i = 0; i < len; i++) | ||
147 | if (s[i] != Name[i]) | ||
148 | return NULL; | ||
149 | s += len; | ||
150 | if (s[0] != '>') | ||
151 | return NULL; | ||
152 | return s + 1; | ||
153 | } | ||
154 | if (beg == s) | ||
155 | return NULL; | ||
156 | |||
157 | // ReadProperty | ||
158 | CXmlProp &prop = Props.AddNew(); | ||
159 | |||
160 | beg = s; | ||
161 | for (;; s++) | ||
162 | { | ||
163 | char c = *s; | ||
164 | if (!IsValidChar(c)) | ||
165 | break; | ||
166 | } | ||
167 | if (s == beg) | ||
168 | return NULL; | ||
169 | prop.Name.SetFrom(beg, (unsigned)(s - beg)); | ||
170 | |||
171 | SKIP_SPACES(s); | ||
172 | if (*s != '=') | ||
173 | return NULL; | ||
174 | s++; | ||
175 | SKIP_SPACES(s); | ||
176 | if (*s != '\"') | ||
177 | return NULL; | ||
178 | s++; | ||
179 | |||
180 | beg = s; | ||
181 | for (;;) | ||
182 | { | ||
183 | char c = *s; | ||
184 | if (c == 0) | ||
185 | return NULL; | ||
186 | if (c == '\"') | ||
187 | break; | ||
188 | s++; | ||
189 | } | ||
190 | prop.Value.SetFrom(beg, (unsigned)(s - beg)); | ||
191 | s++; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static const char * SkipHeader(const char *s, const char *startString, const char *endString) | ||
196 | { | ||
197 | SKIP_SPACES(s); | ||
198 | if (IsString1PrefixedByString2(s, startString)) | ||
199 | { | ||
200 | s = strstr(s, endString); | ||
201 | if (!s) | ||
202 | return NULL; | ||
203 | s += strlen(endString); | ||
204 | } | ||
205 | return s; | ||
206 | } | ||
207 | |||
208 | void CXmlItem::AppendTo(AString &s) const | ||
209 | { | ||
210 | if (IsTag) | ||
211 | s += '<'; | ||
212 | s += Name; | ||
213 | if (IsTag) | ||
214 | { | ||
215 | FOR_VECTOR (i, Props) | ||
216 | { | ||
217 | const CXmlProp &prop = Props[i]; | ||
218 | s += ' '; | ||
219 | s += prop.Name; | ||
220 | s += '='; | ||
221 | s += '\"'; | ||
222 | s += prop.Value; | ||
223 | s += '\"'; | ||
224 | } | ||
225 | s += '>'; | ||
226 | } | ||
227 | FOR_VECTOR (i, SubItems) | ||
228 | { | ||
229 | const CXmlItem &item = SubItems[i]; | ||
230 | if (i != 0 && !SubItems[i - 1].IsTag) | ||
231 | s += ' '; | ||
232 | item.AppendTo(s); | ||
233 | } | ||
234 | if (IsTag) | ||
235 | { | ||
236 | s += '<'; | ||
237 | s += '/'; | ||
238 | s += Name; | ||
239 | s += '>'; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | bool CXml::Parse(const char *s) | ||
244 | { | ||
245 | s = SkipHeader(s, "<?xml", "?>"); if (!s) return false; | ||
246 | s = SkipHeader(s, "<!DOCTYPE", ">"); if (!s) return false; | ||
247 | |||
248 | s = Root.ParseItem(s, 1000); | ||
249 | if (!s || !Root.IsTag) | ||
250 | return false; | ||
251 | SKIP_SPACES(s); | ||
252 | return *s == 0; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | void CXml::AppendTo(AString &s) const | ||
257 | { | ||
258 | Root.AppendTo(s); | ||
259 | } | ||
260 | */ | ||
diff --git a/CPP/Common/MyXml.h b/CPP/Common/MyXml.h new file mode 100644 index 0000000..00b7113 --- /dev/null +++ b/CPP/Common/MyXml.h | |||
@@ -0,0 +1,43 @@ | |||
1 | // MyXml.h | ||
2 | |||
3 | #ifndef __MY_XML_H | ||
4 | #define __MY_XML_H | ||
5 | |||
6 | #include "MyString.h" | ||
7 | |||
8 | struct CXmlProp | ||
9 | { | ||
10 | AString Name; | ||
11 | AString Value; | ||
12 | }; | ||
13 | |||
14 | class CXmlItem | ||
15 | { | ||
16 | public: | ||
17 | AString Name; | ||
18 | bool IsTag; | ||
19 | CObjectVector<CXmlProp> Props; | ||
20 | CObjectVector<CXmlItem> SubItems; | ||
21 | |||
22 | const char * ParseItem(const char *s, int numAllowedLevels); | ||
23 | |||
24 | bool IsTagged(const char *tag) const throw(); | ||
25 | int FindProp(const char *propName) const throw(); | ||
26 | AString GetPropVal(const char *propName) const; | ||
27 | AString GetSubString() const; | ||
28 | const AString * GetSubStringPtr() const throw(); | ||
29 | int FindSubTag(const char *tag) const throw(); | ||
30 | AString GetSubStringForTag(const char *tag) const; | ||
31 | |||
32 | void AppendTo(AString &s) const; | ||
33 | }; | ||
34 | |||
35 | struct CXml | ||
36 | { | ||
37 | CXmlItem Root; | ||
38 | |||
39 | bool Parse(const char *s); | ||
40 | // void AppendTo(AString &s) const; | ||
41 | }; | ||
42 | |||
43 | #endif | ||
diff --git a/CPP/Common/NewHandler.cpp b/CPP/Common/NewHandler.cpp new file mode 100644 index 0000000..7e5b1d4 --- /dev/null +++ b/CPP/Common/NewHandler.cpp | |||
@@ -0,0 +1,163 @@ | |||
1 | // NewHandler.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | |||
7 | #include "NewHandler.h" | ||
8 | |||
9 | // #define DEBUG_MEMORY_LEAK | ||
10 | |||
11 | #ifndef DEBUG_MEMORY_LEAK | ||
12 | |||
13 | #ifdef _7ZIP_REDEFINE_OPERATOR_NEW | ||
14 | |||
15 | /* | ||
16 | void * my_new(size_t size) | ||
17 | { | ||
18 | // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); | ||
19 | void *p = ::malloc(size); | ||
20 | if (p == 0) | ||
21 | throw CNewException(); | ||
22 | return p; | ||
23 | } | ||
24 | |||
25 | void my_delete(void *p) throw() | ||
26 | { | ||
27 | // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p); | ||
28 | ::free(p); | ||
29 | } | ||
30 | |||
31 | void * my_Realloc(void *p, size_t newSize, size_t oldSize) | ||
32 | { | ||
33 | void *newBuf = my_new(newSize); | ||
34 | if (oldSize != 0) | ||
35 | memcpy(newBuf, p, oldSize); | ||
36 | my_delete(p); | ||
37 | return newBuf; | ||
38 | } | ||
39 | */ | ||
40 | |||
41 | void * | ||
42 | #ifdef _MSC_VER | ||
43 | __cdecl | ||
44 | #endif | ||
45 | operator new(size_t size) | ||
46 | { | ||
47 | // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); | ||
48 | void *p = ::malloc(size); | ||
49 | if (p == 0) | ||
50 | throw CNewException(); | ||
51 | return p; | ||
52 | } | ||
53 | |||
54 | void | ||
55 | #ifdef _MSC_VER | ||
56 | __cdecl | ||
57 | #endif | ||
58 | operator delete(void *p) throw() | ||
59 | { | ||
60 | // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p); | ||
61 | ::free(p); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | void * | ||
66 | #ifdef _MSC_VER | ||
67 | __cdecl | ||
68 | #endif | ||
69 | operator new[](size_t size) | ||
70 | { | ||
71 | // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); | ||
72 | void *p = ::malloc(size); | ||
73 | if (p == 0) | ||
74 | throw CNewException(); | ||
75 | return p; | ||
76 | } | ||
77 | |||
78 | void | ||
79 | #ifdef _MSC_VER | ||
80 | __cdecl | ||
81 | #endif | ||
82 | operator delete[](void *p) throw() | ||
83 | { | ||
84 | // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p); | ||
85 | ::free(p); | ||
86 | } | ||
87 | */ | ||
88 | |||
89 | #endif | ||
90 | |||
91 | #else | ||
92 | |||
93 | #include <stdio.h> | ||
94 | |||
95 | // #pragma init_seg(lib) | ||
96 | const int kDebugSize = 1000000; | ||
97 | static void *a[kDebugSize]; | ||
98 | static int index = 0; | ||
99 | |||
100 | static int numAllocs = 0; | ||
101 | void * __cdecl operator new(size_t size) | ||
102 | { | ||
103 | numAllocs++; | ||
104 | void *p = HeapAlloc(GetProcessHeap(), 0, size); | ||
105 | if (index < kDebugSize) | ||
106 | { | ||
107 | a[index] = p; | ||
108 | index++; | ||
109 | } | ||
110 | if (p == 0) | ||
111 | throw CNewException(); | ||
112 | printf("Alloc %6d, size = %8u\n", numAllocs, (unsigned)size); | ||
113 | return p; | ||
114 | } | ||
115 | |||
116 | class CC | ||
117 | { | ||
118 | public: | ||
119 | CC() | ||
120 | { | ||
121 | for (int i = 0; i < kDebugSize; i++) | ||
122 | a[i] = 0; | ||
123 | } | ||
124 | ~CC() | ||
125 | { | ||
126 | for (int i = 0; i < kDebugSize; i++) | ||
127 | if (a[i] != 0) | ||
128 | return; | ||
129 | } | ||
130 | } g_CC; | ||
131 | |||
132 | |||
133 | void __cdecl operator delete(void *p) | ||
134 | { | ||
135 | if (p == 0) | ||
136 | return; | ||
137 | /* | ||
138 | for (int i = 0; i < index; i++) | ||
139 | if (a[i] == p) | ||
140 | a[i] = 0; | ||
141 | */ | ||
142 | HeapFree(GetProcessHeap(), 0, p); | ||
143 | numAllocs--; | ||
144 | printf("Free %d\n", numAllocs); | ||
145 | } | ||
146 | |||
147 | #endif | ||
148 | |||
149 | /* | ||
150 | int MemErrorVC(size_t) | ||
151 | { | ||
152 | throw CNewException(); | ||
153 | // return 1; | ||
154 | } | ||
155 | CNewHandlerSetter::CNewHandlerSetter() | ||
156 | { | ||
157 | // MemErrorOldVCFunction = _set_new_handler(MemErrorVC); | ||
158 | } | ||
159 | CNewHandlerSetter::~CNewHandlerSetter() | ||
160 | { | ||
161 | // _set_new_handler(MemErrorOldVCFunction); | ||
162 | } | ||
163 | */ | ||
diff --git a/CPP/Common/NewHandler.h b/CPP/Common/NewHandler.h new file mode 100644 index 0000000..aedeca6 --- /dev/null +++ b/CPP/Common/NewHandler.h | |||
@@ -0,0 +1,88 @@ | |||
1 | // Common/NewHandler.h | ||
2 | |||
3 | #ifndef __COMMON_NEW_HANDLER_H | ||
4 | #define __COMMON_NEW_HANDLER_H | ||
5 | |||
6 | /* | ||
7 | NewHandler.h and NewHandler.cpp allows to solve problem with compilers that | ||
8 | don't throw exception in operator new(). | ||
9 | |||
10 | This file must be included before any code that uses operators new() or delete() | ||
11 | and you must compile and link "NewHandler.cpp", if you use some old MSVC compiler. | ||
12 | |||
13 | The operator new() in some MSVC versions doesn't throw exception std::bad_alloc. | ||
14 | MSVC 6.0 (_MSC_VER == 1200) doesn't throw exception. | ||
15 | The code produced by some another MSVC compilers also can be linked | ||
16 | to library that doesn't throw exception. | ||
17 | We suppose that code compiled with VS2015+ (_MSC_VER >= 1900) throws exception std::bad_alloc. | ||
18 | For older _MSC_VER versions we redefine operator new() and operator delete(). | ||
19 | Our version of operator new() throws CNewException() exception on failure. | ||
20 | |||
21 | It's still allowed to use redefined version of operator new() from "NewHandler.cpp" | ||
22 | with any compiler. 7-Zip's code can work with std::bad_alloc and CNewException() exceptions. | ||
23 | But if you use some additional code (outside of 7-Zip's code), you must check | ||
24 | that redefined version of operator new() is not problem for your code. | ||
25 | */ | ||
26 | |||
27 | #include <stddef.h> | ||
28 | |||
29 | #ifdef _WIN32 | ||
30 | // We can compile my_new and my_delete with _fastcall | ||
31 | /* | ||
32 | void * my_new(size_t size); | ||
33 | void my_delete(void *p) throw(); | ||
34 | // void * my_Realloc(void *p, size_t newSize, size_t oldSize); | ||
35 | */ | ||
36 | #endif | ||
37 | |||
38 | |||
39 | #if defined(_MSC_VER) && (_MSC_VER < 1900) | ||
40 | // If you want to use default operator new(), you can disable the following line | ||
41 | #define _7ZIP_REDEFINE_OPERATOR_NEW | ||
42 | #endif | ||
43 | |||
44 | |||
45 | #ifdef _7ZIP_REDEFINE_OPERATOR_NEW | ||
46 | |||
47 | // std::bad_alloc can require additional DLL dependency. | ||
48 | // So we don't define CNewException as std::bad_alloc here. | ||
49 | |||
50 | class CNewException {}; | ||
51 | |||
52 | void * | ||
53 | #ifdef _MSC_VER | ||
54 | __cdecl | ||
55 | #endif | ||
56 | operator new(size_t size); | ||
57 | |||
58 | void | ||
59 | #ifdef _MSC_VER | ||
60 | __cdecl | ||
61 | #endif | ||
62 | operator delete(void *p) throw(); | ||
63 | |||
64 | #else | ||
65 | |||
66 | #include <new> | ||
67 | |||
68 | #define CNewException std::bad_alloc | ||
69 | |||
70 | #endif | ||
71 | |||
72 | /* | ||
73 | #ifdef _WIN32 | ||
74 | void * | ||
75 | #ifdef _MSC_VER | ||
76 | __cdecl | ||
77 | #endif | ||
78 | operator new[](size_t size); | ||
79 | |||
80 | void | ||
81 | #ifdef _MSC_VER | ||
82 | __cdecl | ||
83 | #endif | ||
84 | operator delete[](void *p) throw(); | ||
85 | #endif | ||
86 | */ | ||
87 | |||
88 | #endif | ||
diff --git a/CPP/Common/Random.cpp b/CPP/Common/Random.cpp new file mode 100644 index 0000000..fbdb8c9 --- /dev/null +++ b/CPP/Common/Random.cpp | |||
@@ -0,0 +1,28 @@ | |||
1 | // Common/Random.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | |||
7 | #ifndef _WIN32 | ||
8 | #include <time.h> | ||
9 | #else | ||
10 | #include "MyWindows.h" | ||
11 | #endif | ||
12 | |||
13 | #include "Random.h" | ||
14 | |||
15 | void CRandom::Init(unsigned int seed) { srand(seed); } | ||
16 | |||
17 | void CRandom::Init() | ||
18 | { | ||
19 | Init((unsigned int) | ||
20 | #ifdef _WIN32 | ||
21 | GetTickCount() | ||
22 | #else | ||
23 | time(NULL) | ||
24 | #endif | ||
25 | ); | ||
26 | } | ||
27 | |||
28 | int CRandom::Generate() const { return rand(); } | ||
diff --git a/CPP/Common/Random.h b/CPP/Common/Random.h new file mode 100644 index 0000000..e784e98 --- /dev/null +++ b/CPP/Common/Random.h | |||
@@ -0,0 +1,14 @@ | |||
1 | // Common/Random.h | ||
2 | |||
3 | #ifndef __COMMON_RANDOM_H | ||
4 | #define __COMMON_RANDOM_H | ||
5 | |||
6 | class CRandom | ||
7 | { | ||
8 | public: | ||
9 | void Init(); | ||
10 | void Init(unsigned int seed); | ||
11 | int Generate() const; | ||
12 | }; | ||
13 | |||
14 | #endif | ||
diff --git a/CPP/Common/Sha1Prepare.cpp b/CPP/Common/Sha1Prepare.cpp new file mode 100644 index 0000000..2652f00 --- /dev/null +++ b/CPP/Common/Sha1Prepare.cpp | |||
@@ -0,0 +1,7 @@ | |||
1 | // Sha1Prepare.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/Sha1.h" | ||
6 | |||
7 | static struct CSha1Prepare { CSha1Prepare() { Sha1Prepare(); } } g_Sha1Prepare; | ||
diff --git a/CPP/Common/Sha1Reg.cpp b/CPP/Common/Sha1Reg.cpp new file mode 100644 index 0000000..0cb2baf --- /dev/null +++ b/CPP/Common/Sha1Reg.cpp | |||
@@ -0,0 +1,70 @@ | |||
1 | // Sha1Reg.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/Sha1.h" | ||
6 | |||
7 | #include "../Common/MyBuffer2.h" | ||
8 | #include "../Common/MyCom.h" | ||
9 | |||
10 | #include "../7zip/Common/RegisterCodec.h" | ||
11 | |||
12 | class CSha1Hasher: | ||
13 | public IHasher, | ||
14 | public ICompressSetCoderProperties, | ||
15 | public CMyUnknownImp | ||
16 | { | ||
17 | CAlignedBuffer _buf; | ||
18 | Byte mtDummy[1 << 7]; | ||
19 | |||
20 | CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_buf; } | ||
21 | public: | ||
22 | CSha1Hasher(): | ||
23 | _buf(sizeof(CSha1)) | ||
24 | { | ||
25 | Sha1_SetFunction(Sha(), 0); | ||
26 | Sha1_InitState(Sha()); | ||
27 | } | ||
28 | |||
29 | MY_UNKNOWN_IMP2(IHasher, ICompressSetCoderProperties) | ||
30 | INTERFACE_IHasher(;) | ||
31 | STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); | ||
32 | }; | ||
33 | |||
34 | STDMETHODIMP_(void) CSha1Hasher::Init() throw() | ||
35 | { | ||
36 | Sha1_InitState(Sha()); | ||
37 | } | ||
38 | |||
39 | STDMETHODIMP_(void) CSha1Hasher::Update(const void *data, UInt32 size) throw() | ||
40 | { | ||
41 | Sha1_Update(Sha(), (const Byte *)data, size); | ||
42 | } | ||
43 | |||
44 | STDMETHODIMP_(void) CSha1Hasher::Final(Byte *digest) throw() | ||
45 | { | ||
46 | Sha1_Final(Sha(), digest); | ||
47 | } | ||
48 | |||
49 | |||
50 | STDMETHODIMP CSha1Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) | ||
51 | { | ||
52 | unsigned algo = 0; | ||
53 | for (UInt32 i = 0; i < numProps; i++) | ||
54 | { | ||
55 | const PROPVARIANT &prop = coderProps[i]; | ||
56 | if (propIDs[i] == NCoderPropID::kDefaultProp) | ||
57 | { | ||
58 | if (prop.vt != VT_UI4) | ||
59 | return E_INVALIDARG; | ||
60 | if (prop.ulVal > 2) | ||
61 | return E_NOTIMPL; | ||
62 | algo = (unsigned)prop.ulVal; | ||
63 | } | ||
64 | } | ||
65 | if (!Sha1_SetFunction(Sha(), algo)) | ||
66 | return E_NOTIMPL; | ||
67 | return S_OK; | ||
68 | } | ||
69 | |||
70 | REGISTER_HASHER(CSha1Hasher, 0x201, "SHA1", SHA1_DIGEST_SIZE) | ||
diff --git a/CPP/Common/Sha256Prepare.cpp b/CPP/Common/Sha256Prepare.cpp new file mode 100644 index 0000000..1ec242b --- /dev/null +++ b/CPP/Common/Sha256Prepare.cpp | |||
@@ -0,0 +1,7 @@ | |||
1 | // Sha256Prepare.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/Sha256.h" | ||
6 | |||
7 | static struct CSha256Prepare { CSha256Prepare() { Sha256Prepare(); } } g_Sha256Prepare; | ||
diff --git a/CPP/Common/Sha256Reg.cpp b/CPP/Common/Sha256Reg.cpp new file mode 100644 index 0000000..5f3a35b --- /dev/null +++ b/CPP/Common/Sha256Reg.cpp | |||
@@ -0,0 +1,70 @@ | |||
1 | // Sha256Reg.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/Sha256.h" | ||
6 | |||
7 | #include "../Common/MyBuffer2.h" | ||
8 | #include "../Common/MyCom.h" | ||
9 | |||
10 | #include "../7zip/Common/RegisterCodec.h" | ||
11 | |||
12 | class CSha256Hasher: | ||
13 | public IHasher, | ||
14 | public ICompressSetCoderProperties, | ||
15 | public CMyUnknownImp | ||
16 | { | ||
17 | CAlignedBuffer _buf; | ||
18 | Byte mtDummy[1 << 7]; | ||
19 | |||
20 | CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_buf; } | ||
21 | public: | ||
22 | CSha256Hasher(): | ||
23 | _buf(sizeof(CSha256)) | ||
24 | { | ||
25 | Sha256_SetFunction(Sha(), 0); | ||
26 | Sha256_InitState(Sha()); | ||
27 | } | ||
28 | |||
29 | MY_UNKNOWN_IMP2(IHasher, ICompressSetCoderProperties) | ||
30 | INTERFACE_IHasher(;) | ||
31 | STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps); | ||
32 | }; | ||
33 | |||
34 | STDMETHODIMP_(void) CSha256Hasher::Init() throw() | ||
35 | { | ||
36 | Sha256_InitState(Sha()); | ||
37 | } | ||
38 | |||
39 | STDMETHODIMP_(void) CSha256Hasher::Update(const void *data, UInt32 size) throw() | ||
40 | { | ||
41 | Sha256_Update(Sha(), (const Byte *)data, size); | ||
42 | } | ||
43 | |||
44 | STDMETHODIMP_(void) CSha256Hasher::Final(Byte *digest) throw() | ||
45 | { | ||
46 | Sha256_Final(Sha(), digest); | ||
47 | } | ||
48 | |||
49 | |||
50 | STDMETHODIMP CSha256Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps) | ||
51 | { | ||
52 | unsigned algo = 0; | ||
53 | for (UInt32 i = 0; i < numProps; i++) | ||
54 | { | ||
55 | const PROPVARIANT &prop = coderProps[i]; | ||
56 | if (propIDs[i] == NCoderPropID::kDefaultProp) | ||
57 | { | ||
58 | if (prop.vt != VT_UI4) | ||
59 | return E_INVALIDARG; | ||
60 | if (prop.ulVal > 2) | ||
61 | return E_NOTIMPL; | ||
62 | algo = (unsigned)prop.ulVal; | ||
63 | } | ||
64 | } | ||
65 | if (!Sha256_SetFunction(Sha(), algo)) | ||
66 | return E_NOTIMPL; | ||
67 | return S_OK; | ||
68 | } | ||
69 | |||
70 | REGISTER_HASHER(CSha256Hasher, 0xA, "SHA256", SHA256_DIGEST_SIZE) | ||
diff --git a/CPP/Common/StdAfx.h b/CPP/Common/StdAfx.h new file mode 100644 index 0000000..420f5c3 --- /dev/null +++ b/CPP/Common/StdAfx.h | |||
@@ -0,0 +1,8 @@ | |||
1 | // StdAfx.h | ||
2 | |||
3 | #ifndef __STDAFX_H | ||
4 | #define __STDAFX_H | ||
5 | |||
6 | #include "Common.h" | ||
7 | |||
8 | #endif | ||
diff --git a/CPP/Common/StdInStream.cpp b/CPP/Common/StdInStream.cpp new file mode 100644 index 0000000..abad34b --- /dev/null +++ b/CPP/Common/StdInStream.cpp | |||
@@ -0,0 +1,95 @@ | |||
1 | // Common/StdInStream.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #ifdef _WIN32 | ||
6 | #include <tchar.h> | ||
7 | #endif | ||
8 | |||
9 | #include "StdInStream.h" | ||
10 | #include "StringConvert.h" | ||
11 | #include "UTFConvert.h" | ||
12 | |||
13 | // #define kEOFMessage "Unexpected end of input stream" | ||
14 | // #define kReadErrorMessage "Error reading input stream" | ||
15 | // #define kIllegalCharMessage "Illegal zero character in input stream" | ||
16 | |||
17 | #define kFileOpenMode TEXT("r") | ||
18 | |||
19 | CStdInStream g_StdIn(stdin); | ||
20 | |||
21 | bool CStdInStream::Open(LPCTSTR fileName) throw() | ||
22 | { | ||
23 | Close(); | ||
24 | _stream = | ||
25 | #ifdef _WIN32 | ||
26 | _tfopen | ||
27 | #else | ||
28 | fopen | ||
29 | #endif | ||
30 | (fileName, kFileOpenMode); | ||
31 | _streamIsOpen = (_stream != 0); | ||
32 | return _streamIsOpen; | ||
33 | } | ||
34 | |||
35 | bool CStdInStream::Close() throw() | ||
36 | { | ||
37 | if (!_streamIsOpen) | ||
38 | return true; | ||
39 | _streamIsOpen = (fclose(_stream) != 0); | ||
40 | return !_streamIsOpen; | ||
41 | } | ||
42 | |||
43 | bool CStdInStream::ScanAStringUntilNewLine(AString &s) | ||
44 | { | ||
45 | s.Empty(); | ||
46 | for (;;) | ||
47 | { | ||
48 | int intChar = GetChar(); | ||
49 | if (intChar == EOF) | ||
50 | return true; | ||
51 | char c = (char)intChar; | ||
52 | if (c == 0) | ||
53 | return false; | ||
54 | if (c == '\n') | ||
55 | return true; | ||
56 | s += c; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | bool CStdInStream::ScanUStringUntilNewLine(UString &dest) | ||
61 | { | ||
62 | dest.Empty(); | ||
63 | AString s; | ||
64 | bool res = ScanAStringUntilNewLine(s); | ||
65 | int codePage = CodePage; | ||
66 | if (codePage == -1) | ||
67 | codePage = CP_OEMCP; | ||
68 | if (codePage == CP_UTF8) | ||
69 | ConvertUTF8ToUnicode(s, dest); | ||
70 | else | ||
71 | MultiByteToUnicodeString2(dest, s, (UINT)codePage); | ||
72 | return res; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | bool CStdInStream::ReadToString(AString &resultString) | ||
77 | { | ||
78 | resultString.Empty(); | ||
79 | for (;;) | ||
80 | { | ||
81 | int intChar = GetChar(); | ||
82 | if (intChar == EOF) | ||
83 | return !Error(); | ||
84 | char c = (char)intChar; | ||
85 | if (c == 0) | ||
86 | return false; | ||
87 | resultString += c; | ||
88 | } | ||
89 | } | ||
90 | */ | ||
91 | |||
92 | int CStdInStream::GetChar() | ||
93 | { | ||
94 | return fgetc(_stream); // getc() doesn't work in BeOS? | ||
95 | } | ||
diff --git a/CPP/Common/StdInStream.h b/CPP/Common/StdInStream.h new file mode 100644 index 0000000..71578eb --- /dev/null +++ b/CPP/Common/StdInStream.h | |||
@@ -0,0 +1,44 @@ | |||
1 | // Common/StdInStream.h | ||
2 | |||
3 | #ifndef __COMMON_STD_IN_STREAM_H | ||
4 | #define __COMMON_STD_IN_STREAM_H | ||
5 | |||
6 | #include <stdio.h> | ||
7 | |||
8 | #include "MyString.h" | ||
9 | #include "MyTypes.h" | ||
10 | |||
11 | class CStdInStream | ||
12 | { | ||
13 | FILE *_stream; | ||
14 | bool _streamIsOpen; | ||
15 | public: | ||
16 | int CodePage; | ||
17 | |||
18 | CStdInStream(FILE *stream = NULL): | ||
19 | _stream(stream), | ||
20 | _streamIsOpen(false), | ||
21 | CodePage(-1) | ||
22 | {}; | ||
23 | |||
24 | ~CStdInStream() { Close(); } | ||
25 | |||
26 | bool Open(LPCTSTR fileName) throw(); | ||
27 | bool Close() throw(); | ||
28 | |||
29 | // returns: | ||
30 | // false, if ZERO character in stream | ||
31 | // true, if EOF or '\n' | ||
32 | bool ScanAStringUntilNewLine(AString &s); | ||
33 | bool ScanUStringUntilNewLine(UString &s); | ||
34 | // bool ReadToString(AString &resultString); | ||
35 | |||
36 | bool Eof() const throw() { return (feof(_stream) != 0); } | ||
37 | bool Error() const throw() { return (ferror(_stream) != 0); } | ||
38 | |||
39 | int GetChar(); | ||
40 | }; | ||
41 | |||
42 | extern CStdInStream g_StdIn; | ||
43 | |||
44 | #endif | ||
diff --git a/CPP/Common/StdOutStream.cpp b/CPP/Common/StdOutStream.cpp new file mode 100644 index 0000000..40799e2 --- /dev/null +++ b/CPP/Common/StdOutStream.cpp | |||
@@ -0,0 +1,158 @@ | |||
1 | // Common/StdOutStream.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #ifdef _WIN32 | ||
6 | #include <tchar.h> | ||
7 | #endif | ||
8 | |||
9 | #include "IntToString.h" | ||
10 | #include "StdOutStream.h" | ||
11 | #include "StringConvert.h" | ||
12 | #include "UTFConvert.h" | ||
13 | |||
14 | #define kFileOpenMode "wt" | ||
15 | |||
16 | CStdOutStream g_StdOut(stdout); | ||
17 | CStdOutStream g_StdErr(stderr); | ||
18 | |||
19 | bool CStdOutStream::Open(const char *fileName) throw() | ||
20 | { | ||
21 | Close(); | ||
22 | _stream = fopen(fileName, kFileOpenMode); | ||
23 | _streamIsOpen = (_stream != 0); | ||
24 | return _streamIsOpen; | ||
25 | } | ||
26 | |||
27 | bool CStdOutStream::Close() throw() | ||
28 | { | ||
29 | if (!_streamIsOpen) | ||
30 | return true; | ||
31 | if (fclose(_stream) != 0) | ||
32 | return false; | ||
33 | _stream = 0; | ||
34 | _streamIsOpen = false; | ||
35 | return true; | ||
36 | } | ||
37 | |||
38 | bool CStdOutStream::Flush() throw() | ||
39 | { | ||
40 | return (fflush(_stream) == 0); | ||
41 | } | ||
42 | |||
43 | CStdOutStream & endl(CStdOutStream & outStream) throw() | ||
44 | { | ||
45 | return outStream << '\n'; | ||
46 | } | ||
47 | |||
48 | CStdOutStream & CStdOutStream::operator<<(const wchar_t *s) | ||
49 | { | ||
50 | AString temp; | ||
51 | UString s2(s); | ||
52 | PrintUString(s2, temp); | ||
53 | return *this; | ||
54 | } | ||
55 | |||
56 | void CStdOutStream::PrintUString(const UString &s, AString &temp) | ||
57 | { | ||
58 | Convert_UString_to_AString(s, temp); | ||
59 | *this << (const char *)temp; | ||
60 | } | ||
61 | |||
62 | void CStdOutStream::Convert_UString_to_AString(const UString &src, AString &dest) | ||
63 | { | ||
64 | int codePage = CodePage; | ||
65 | if (codePage == -1) | ||
66 | codePage = CP_OEMCP; | ||
67 | if (codePage == CP_UTF8) | ||
68 | ConvertUnicodeToUTF8(src, dest); | ||
69 | else | ||
70 | UnicodeStringToMultiByte2(dest, src, (UINT)codePage); | ||
71 | } | ||
72 | |||
73 | |||
74 | static const wchar_t kReplaceChar = '_'; | ||
75 | |||
76 | void CStdOutStream::Normalize_UString__LF_Allowed(UString &s) | ||
77 | { | ||
78 | unsigned len = s.Len(); | ||
79 | wchar_t *d = s.GetBuf(); | ||
80 | |||
81 | if (IsTerminalMode) | ||
82 | for (unsigned i = 0; i < len; i++) | ||
83 | { | ||
84 | wchar_t c = d[i]; | ||
85 | if (c <= 13 && c >= 7 && c != '\n') | ||
86 | d[i] = kReplaceChar; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | void CStdOutStream::Normalize_UString(UString &s) | ||
91 | { | ||
92 | unsigned len = s.Len(); | ||
93 | wchar_t *d = s.GetBuf(); | ||
94 | |||
95 | if (IsTerminalMode) | ||
96 | for (unsigned i = 0; i < len; i++) | ||
97 | { | ||
98 | wchar_t c = d[i]; | ||
99 | if (c <= 13 && c >= 7) | ||
100 | d[i] = kReplaceChar; | ||
101 | } | ||
102 | else | ||
103 | for (unsigned i = 0; i < len; i++) | ||
104 | { | ||
105 | wchar_t c = d[i]; | ||
106 | if (c == '\n') | ||
107 | d[i] = kReplaceChar; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | void CStdOutStream::NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA) | ||
112 | { | ||
113 | tempU = s; | ||
114 | Normalize_UString(tempU); | ||
115 | PrintUString(tempU, tempA); | ||
116 | } | ||
117 | |||
118 | void CStdOutStream::NormalizePrint_UString(const UString &s) | ||
119 | { | ||
120 | NormalizePrint_wstr(s); | ||
121 | } | ||
122 | |||
123 | void CStdOutStream::NormalizePrint_wstr(const wchar_t *s) | ||
124 | { | ||
125 | UString tempU = s; | ||
126 | Normalize_UString(tempU); | ||
127 | AString tempA; | ||
128 | PrintUString(tempU, tempA); | ||
129 | } | ||
130 | |||
131 | |||
132 | CStdOutStream & CStdOutStream::operator<<(Int32 number) throw() | ||
133 | { | ||
134 | char s[32]; | ||
135 | ConvertInt64ToString(number, s); | ||
136 | return operator<<(s); | ||
137 | } | ||
138 | |||
139 | CStdOutStream & CStdOutStream::operator<<(Int64 number) throw() | ||
140 | { | ||
141 | char s[32]; | ||
142 | ConvertInt64ToString(number, s); | ||
143 | return operator<<(s); | ||
144 | } | ||
145 | |||
146 | CStdOutStream & CStdOutStream::operator<<(UInt32 number) throw() | ||
147 | { | ||
148 | char s[16]; | ||
149 | ConvertUInt32ToString(number, s); | ||
150 | return operator<<(s); | ||
151 | } | ||
152 | |||
153 | CStdOutStream & CStdOutStream::operator<<(UInt64 number) throw() | ||
154 | { | ||
155 | char s[32]; | ||
156 | ConvertUInt64ToString(number, s); | ||
157 | return operator<<(s); | ||
158 | } | ||
diff --git a/CPP/Common/StdOutStream.h b/CPP/Common/StdOutStream.h new file mode 100644 index 0000000..93f1dfa --- /dev/null +++ b/CPP/Common/StdOutStream.h | |||
@@ -0,0 +1,76 @@ | |||
1 | // Common/StdOutStream.h | ||
2 | |||
3 | #ifndef __COMMON_STD_OUT_STREAM_H | ||
4 | #define __COMMON_STD_OUT_STREAM_H | ||
5 | |||
6 | #include <stdio.h> | ||
7 | |||
8 | #include "MyString.h" | ||
9 | #include "MyTypes.h" | ||
10 | |||
11 | class CStdOutStream | ||
12 | { | ||
13 | FILE *_stream; | ||
14 | bool _streamIsOpen; | ||
15 | public: | ||
16 | bool IsTerminalMode; | ||
17 | int CodePage; | ||
18 | |||
19 | CStdOutStream(FILE *stream = 0): | ||
20 | _stream(stream), | ||
21 | _streamIsOpen(false), | ||
22 | IsTerminalMode(false), | ||
23 | CodePage(-1) | ||
24 | {}; | ||
25 | |||
26 | ~CStdOutStream() { Close(); } | ||
27 | |||
28 | // void AttachStdStream(FILE *stream) { _stream = stream; _streamIsOpen = false; } | ||
29 | // bool IsDefined() const { return _stream != NULL; } | ||
30 | |||
31 | operator FILE *() { return _stream; } | ||
32 | bool Open(const char *fileName) throw(); | ||
33 | bool Close() throw(); | ||
34 | bool Flush() throw(); | ||
35 | |||
36 | CStdOutStream & operator<<(CStdOutStream & (* func)(CStdOutStream &)) | ||
37 | { | ||
38 | (*func)(*this); | ||
39 | return *this; | ||
40 | } | ||
41 | |||
42 | CStdOutStream & operator<<(const char *s) throw() | ||
43 | { | ||
44 | fputs(s, _stream); | ||
45 | return *this; | ||
46 | } | ||
47 | |||
48 | CStdOutStream & operator<<(char c) throw() | ||
49 | { | ||
50 | fputc((unsigned char)c, _stream); | ||
51 | return *this; | ||
52 | } | ||
53 | |||
54 | CStdOutStream & operator<<(Int32 number) throw(); | ||
55 | CStdOutStream & operator<<(Int64 number) throw(); | ||
56 | CStdOutStream & operator<<(UInt32 number) throw(); | ||
57 | CStdOutStream & operator<<(UInt64 number) throw(); | ||
58 | |||
59 | CStdOutStream & operator<<(const wchar_t *s); | ||
60 | void PrintUString(const UString &s, AString &temp); | ||
61 | void Convert_UString_to_AString(const UString &src, AString &dest); | ||
62 | |||
63 | void Normalize_UString__LF_Allowed(UString &s); | ||
64 | void Normalize_UString(UString &s); | ||
65 | |||
66 | void NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA); | ||
67 | void NormalizePrint_UString(const UString &s); | ||
68 | void NormalizePrint_wstr(const wchar_t *s); | ||
69 | }; | ||
70 | |||
71 | CStdOutStream & endl(CStdOutStream & outStream) throw(); | ||
72 | |||
73 | extern CStdOutStream g_StdOut; | ||
74 | extern CStdOutStream g_StdErr; | ||
75 | |||
76 | #endif | ||
diff --git a/CPP/Common/StringConvert.cpp b/CPP/Common/StringConvert.cpp new file mode 100644 index 0000000..c0bde0f --- /dev/null +++ b/CPP/Common/StringConvert.cpp | |||
@@ -0,0 +1,757 @@ | |||
1 | // Common/StringConvert.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "StringConvert.h" | ||
6 | |||
7 | #ifndef _WIN32 | ||
8 | // #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #endif | ||
11 | |||
12 | #if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) | ||
13 | #include "UTFConvert.h" | ||
14 | #endif | ||
15 | |||
16 | #ifdef ENV_HAVE_LOCALE | ||
17 | #include <locale.h> | ||
18 | #endif | ||
19 | |||
20 | static const char k_DefultChar = '_'; | ||
21 | |||
22 | #ifdef _WIN32 | ||
23 | |||
24 | /* | ||
25 | MultiByteToWideChar(CodePage, DWORD dwFlags, | ||
26 | LPCSTR lpMultiByteStr, int cbMultiByte, | ||
27 | LPWSTR lpWideCharStr, int cchWideChar) | ||
28 | |||
29 | if (cbMultiByte == 0) | ||
30 | return: 0. ERR: ERROR_INVALID_PARAMETER | ||
31 | |||
32 | if (cchWideChar == 0) | ||
33 | return: the required buffer size in characters. | ||
34 | |||
35 | if (supplied buffer size was not large enough) | ||
36 | return: 0. ERR: ERROR_INSUFFICIENT_BUFFER | ||
37 | The number of filled characters in lpWideCharStr can be smaller than cchWideChar (if last character is complex) | ||
38 | |||
39 | If there are illegal characters: | ||
40 | if MB_ERR_INVALID_CHARS is set in dwFlags: | ||
41 | - the function stops conversion on illegal character. | ||
42 | - Return: 0. ERR: ERROR_NO_UNICODE_TRANSLATION. | ||
43 | |||
44 | if MB_ERR_INVALID_CHARS is NOT set in dwFlags: | ||
45 | before Vista: illegal character is dropped (skipped). WinXP-64: GetLastError() returns 0. | ||
46 | in Vista+: illegal character is not dropped (MSDN). Undocumented: illegal | ||
47 | character is converted to U+FFFD, which is REPLACEMENT CHARACTER. | ||
48 | */ | ||
49 | |||
50 | |||
51 | void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage) | ||
52 | { | ||
53 | dest.Empty(); | ||
54 | if (src.IsEmpty()) | ||
55 | return; | ||
56 | { | ||
57 | /* | ||
58 | wchar_t *d = dest.GetBuf(src.Len()); | ||
59 | const char *s = (const char *)src; | ||
60 | unsigned i; | ||
61 | |||
62 | for (i = 0;;) | ||
63 | { | ||
64 | Byte c = (Byte)s[i]; | ||
65 | if (c >= 0x80 || c == 0) | ||
66 | break; | ||
67 | d[i++] = (wchar_t)c; | ||
68 | } | ||
69 | |||
70 | if (i != src.Len()) | ||
71 | { | ||
72 | unsigned len = MultiByteToWideChar(codePage, 0, s + i, | ||
73 | src.Len() - i, d + i, | ||
74 | src.Len() + 1 - i); | ||
75 | if (len == 0) | ||
76 | throw 282228; | ||
77 | i += len; | ||
78 | } | ||
79 | |||
80 | d[i] = 0; | ||
81 | dest.ReleaseBuf_SetLen(i); | ||
82 | */ | ||
83 | unsigned len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), NULL, 0); | ||
84 | if (len == 0) | ||
85 | { | ||
86 | if (GetLastError() != 0) | ||
87 | throw 282228; | ||
88 | } | ||
89 | else | ||
90 | { | ||
91 | len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), dest.GetBuf(len), (int)len); | ||
92 | if (len == 0) | ||
93 | throw 282228; | ||
94 | dest.ReleaseBuf_SetEnd(len); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | int WideCharToMultiByte( | ||
101 | UINT CodePage, DWORD dwFlags, | ||
102 | LPCWSTR lpWideCharStr, int cchWideChar, | ||
103 | LPSTR lpMultiByteStr, int cbMultiByte, | ||
104 | LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar); | ||
105 | |||
106 | if (lpDefaultChar == NULL), | ||
107 | - it uses system default value. | ||
108 | |||
109 | if (CodePage == CP_UTF7 || CodePage == CP_UTF8) | ||
110 | if (lpDefaultChar != NULL || lpUsedDefaultChar != NULL) | ||
111 | return: 0. ERR: ERROR_INVALID_PARAMETER. | ||
112 | |||
113 | The function operates most efficiently, if (lpDefaultChar == NULL && lpUsedDefaultChar == NULL) | ||
114 | |||
115 | */ | ||
116 | |||
117 | static void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed) | ||
118 | { | ||
119 | dest.Empty(); | ||
120 | defaultCharWasUsed = false; | ||
121 | if (src.IsEmpty()) | ||
122 | return; | ||
123 | { | ||
124 | /* | ||
125 | unsigned numRequiredBytes = src.Len() * 2; | ||
126 | char *d = dest.GetBuf(numRequiredBytes); | ||
127 | const wchar_t *s = (const wchar_t *)src; | ||
128 | unsigned i; | ||
129 | |||
130 | for (i = 0;;) | ||
131 | { | ||
132 | wchar_t c = s[i]; | ||
133 | if (c >= 0x80 || c == 0) | ||
134 | break; | ||
135 | d[i++] = (char)c; | ||
136 | } | ||
137 | |||
138 | if (i != src.Len()) | ||
139 | { | ||
140 | BOOL defUsed = FALSE; | ||
141 | defaultChar = defaultChar; | ||
142 | |||
143 | bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7); | ||
144 | unsigned len = WideCharToMultiByte(codePage, 0, s + i, src.Len() - i, | ||
145 | d + i, numRequiredBytes + 1 - i, | ||
146 | (isUtf ? NULL : &defaultChar), | ||
147 | (isUtf ? NULL : &defUsed)); | ||
148 | defaultCharWasUsed = (defUsed != FALSE); | ||
149 | if (len == 0) | ||
150 | throw 282229; | ||
151 | i += len; | ||
152 | } | ||
153 | |||
154 | d[i] = 0; | ||
155 | dest.ReleaseBuf_SetLen(i); | ||
156 | */ | ||
157 | |||
158 | /* | ||
159 | if (codePage != CP_UTF7) | ||
160 | { | ||
161 | const wchar_t *s = (const wchar_t *)src; | ||
162 | unsigned i; | ||
163 | for (i = 0;; i++) | ||
164 | { | ||
165 | wchar_t c = s[i]; | ||
166 | if (c >= 0x80 || c == 0) | ||
167 | break; | ||
168 | } | ||
169 | |||
170 | if (s[i] == 0) | ||
171 | { | ||
172 | char *d = dest.GetBuf(src.Len()); | ||
173 | for (i = 0;;) | ||
174 | { | ||
175 | wchar_t c = s[i]; | ||
176 | if (c == 0) | ||
177 | break; | ||
178 | d[i++] = (char)c; | ||
179 | } | ||
180 | d[i] = 0; | ||
181 | dest.ReleaseBuf_SetLen(i); | ||
182 | return; | ||
183 | } | ||
184 | } | ||
185 | */ | ||
186 | |||
187 | unsigned len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(), NULL, 0, NULL, NULL); | ||
188 | if (len == 0) | ||
189 | { | ||
190 | if (GetLastError() != 0) | ||
191 | throw 282228; | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | BOOL defUsed = FALSE; | ||
196 | bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7); | ||
197 | // defaultChar = defaultChar; | ||
198 | len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(), | ||
199 | dest.GetBuf(len), (int)len, | ||
200 | (isUtf ? NULL : &defaultChar), | ||
201 | (isUtf ? NULL : &defUsed) | ||
202 | ); | ||
203 | if (!isUtf) | ||
204 | defaultCharWasUsed = (defUsed != FALSE); | ||
205 | if (len == 0) | ||
206 | throw 282228; | ||
207 | dest.ReleaseBuf_SetEnd(len); | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | #ifndef UNDER_CE | ||
214 | AString SystemStringToOemString(const CSysString &src) | ||
215 | { | ||
216 | AString dest; | ||
217 | const unsigned len = src.Len() * 2; | ||
218 | CharToOem(src, dest.GetBuf(len)); | ||
219 | dest.ReleaseBuf_CalcLen(len); | ||
220 | return dest; | ||
221 | } | ||
222 | #endif | ||
223 | */ | ||
224 | |||
225 | #else // _WIN32 | ||
226 | |||
227 | // #include <stdio.h> | ||
228 | /* | ||
229 | if (wchar_t is 32-bit (#if WCHAR_MAX > 0xffff), | ||
230 | and utf-8 string contains big unicode character > 0xffff), | ||
231 | then we still use 16-bit surrogate pair in UString. | ||
232 | It simplifies another code where utf-16 encoding is used. | ||
233 | So we use surrogate-conversion code only in is file. | ||
234 | */ | ||
235 | |||
236 | /* | ||
237 | mbstowcs() returns error if there is error in utf-8 stream, | ||
238 | mbstowcs() returns error if there is single surrogates point (d800-dfff) in utf-8 stream | ||
239 | */ | ||
240 | |||
241 | /* | ||
242 | static void MultiByteToUnicodeString2_Native(UString &dest, const AString &src) | ||
243 | { | ||
244 | dest.Empty(); | ||
245 | if (src.IsEmpty()) | ||
246 | return; | ||
247 | |||
248 | const size_t limit = ((size_t)src.Len() + 1) * 2; | ||
249 | wchar_t *d = dest.GetBuf((unsigned)limit); | ||
250 | const size_t len = mbstowcs(d, src, limit); | ||
251 | if (len != (size_t)-1) | ||
252 | { | ||
253 | dest.ReleaseBuf_SetEnd((unsigned)len); | ||
254 | return; | ||
255 | } | ||
256 | dest.ReleaseBuf_SetEnd(0); | ||
257 | } | ||
258 | */ | ||
259 | |||
260 | bool g_ForceToUTF8 = true; // false; | ||
261 | |||
262 | void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage) | ||
263 | { | ||
264 | dest.Empty(); | ||
265 | if (src.IsEmpty()) | ||
266 | return; | ||
267 | |||
268 | if (codePage == CP_UTF8 || g_ForceToUTF8) | ||
269 | { | ||
270 | ConvertUTF8ToUnicode(src, dest); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | const size_t limit = ((size_t)src.Len() + 1) * 2; | ||
275 | wchar_t *d = dest.GetBuf((unsigned)limit); | ||
276 | const size_t len = mbstowcs(d, src, limit); | ||
277 | if (len != (size_t)-1) | ||
278 | { | ||
279 | dest.ReleaseBuf_SetEnd((unsigned)len); | ||
280 | |||
281 | #if WCHAR_MAX > 0xffff | ||
282 | d = dest.GetBuf(); | ||
283 | for (size_t i = 0;; i++) | ||
284 | { | ||
285 | // wchar_t c = dest[i]; | ||
286 | wchar_t c = d[i]; | ||
287 | if (c == 0) | ||
288 | break; | ||
289 | if (c >= 0x10000 && c < 0x110000) | ||
290 | { | ||
291 | /* | ||
292 | c -= 0x10000; | ||
293 | unsigned c0 = 0xd800 + ((c >> 10) & 0x3FF); | ||
294 | dest.ReplaceOneCharAtPos(i, c0); | ||
295 | i++; | ||
296 | c = 0xdc00 + (c & 0x3FF); | ||
297 | dest.Insert_wchar_t(i, c); | ||
298 | */ | ||
299 | UString temp = d + i; | ||
300 | |||
301 | for (size_t t = 0;; t++) | ||
302 | { | ||
303 | wchar_t w = temp[t]; | ||
304 | if (w == 0) | ||
305 | break; | ||
306 | if (i == limit) | ||
307 | break; // unexpected error | ||
308 | if (w >= 0x10000 && w < 0x110000) | ||
309 | { | ||
310 | if (i + 1 == limit) | ||
311 | break; // unexpected error | ||
312 | w -= 0x10000; | ||
313 | d[i++] = (unsigned)0xd800 + (((unsigned)w >> 10) & 0x3FF); | ||
314 | w = 0xdc00 + (w & 0x3FF); | ||
315 | } | ||
316 | d[i++] = w; | ||
317 | } | ||
318 | dest.ReleaseBuf_SetEnd((unsigned)i); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | #endif | ||
323 | |||
324 | /* | ||
325 | printf("\nMultiByteToUnicodeString2 (%d) %s\n", (int)src.Len(), src.Ptr()); | ||
326 | printf("char: "); | ||
327 | for (unsigned i = 0; i < src.Len(); i++) | ||
328 | printf (" %02x", (int)(Byte)src[i]); | ||
329 | printf("\n"); | ||
330 | printf("\n-> (%d) %ls\n", (int)dest.Len(), dest.Ptr()); | ||
331 | printf("wchar_t: "); | ||
332 | for (unsigned i = 0; i < dest.Len(); i++) | ||
333 | { | ||
334 | printf (" %02x", (int)dest[i]); | ||
335 | } | ||
336 | printf("\n"); | ||
337 | */ | ||
338 | |||
339 | return; | ||
340 | } | ||
341 | |||
342 | /* if there is mbstowcs() error, we have two ways: | ||
343 | |||
344 | 1) change 0x80+ characters to some character: '_' | ||
345 | in that case we lose data, but we have correct UString() | ||
346 | and that scheme can show errors to user in early stages, | ||
347 | when file converted back to mbs() cannot be found | ||
348 | |||
349 | 2) transfer bad characters in some UTF-16 range. | ||
350 | it can be non-original Unicode character. | ||
351 | but later we still can restore original character. | ||
352 | */ | ||
353 | |||
354 | |||
355 | // printf("\nmbstowcs ERROR !!!!!! s=%s\n", src.Ptr()); | ||
356 | { | ||
357 | unsigned i; | ||
358 | const char *s = (const char *)src; | ||
359 | for (i = 0;;) | ||
360 | { | ||
361 | Byte c = (Byte)s[i]; | ||
362 | if (c == 0) | ||
363 | break; | ||
364 | // we can use ascii compatibilty character '_' | ||
365 | // if (c > 0x7F) c = '_'; // we replace "bad: character | ||
366 | d[i++] = (wchar_t)c; | ||
367 | } | ||
368 | d[i] = 0; | ||
369 | dest.ReleaseBuf_SetLen(i); | ||
370 | } | ||
371 | } | ||
372 | |||
373 | static void UnicodeStringToMultiByte2_Native(AString &dest, const UString &src) | ||
374 | { | ||
375 | dest.Empty(); | ||
376 | if (src.IsEmpty()) | ||
377 | return; | ||
378 | |||
379 | const size_t limit = ((size_t)src.Len() + 1) * 6; | ||
380 | char *d = dest.GetBuf((unsigned)limit); | ||
381 | |||
382 | const size_t len = wcstombs(d, src, limit); | ||
383 | |||
384 | if (len != (size_t)-1) | ||
385 | { | ||
386 | dest.ReleaseBuf_SetEnd((unsigned)len); | ||
387 | return; | ||
388 | } | ||
389 | dest.ReleaseBuf_SetEnd(0); | ||
390 | } | ||
391 | |||
392 | |||
393 | static void UnicodeStringToMultiByte2(AString &dest, const UString &src2, UINT codePage, char defaultChar, bool &defaultCharWasUsed) | ||
394 | { | ||
395 | // if (codePage == 1234567) // for debug purposes | ||
396 | if (codePage == CP_UTF8 || g_ForceToUTF8) | ||
397 | { | ||
398 | defaultCharWasUsed = false; | ||
399 | ConvertUnicodeToUTF8(src2, dest); | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | UString src = src2; | ||
404 | #if WCHAR_MAX > 0xffff | ||
405 | { | ||
406 | src.Empty(); | ||
407 | for (unsigned i = 0; i < src2.Len();) | ||
408 | { | ||
409 | wchar_t c = src2[i]; | ||
410 | if (c >= 0xd800 && c < 0xdc00 && i + 1 != src2.Len()) | ||
411 | { | ||
412 | const wchar_t c2 = src2[i + 1]; | ||
413 | if (c2 >= 0xdc00 && c2 < 0x10000) | ||
414 | { | ||
415 | // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2); | ||
416 | c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); | ||
417 | // printf("%4x\n", (int)c); | ||
418 | i++; | ||
419 | } | ||
420 | } | ||
421 | src += c; | ||
422 | i++; | ||
423 | } | ||
424 | } | ||
425 | #endif | ||
426 | |||
427 | dest.Empty(); | ||
428 | defaultCharWasUsed = false; | ||
429 | if (src.IsEmpty()) | ||
430 | return; | ||
431 | |||
432 | const size_t len = wcstombs(NULL, src, 0); | ||
433 | |||
434 | if (len != (size_t)-1) | ||
435 | { | ||
436 | const unsigned limit = ((unsigned)len); | ||
437 | if (limit == len) | ||
438 | { | ||
439 | char *d = dest.GetBuf(limit); | ||
440 | |||
441 | /* | ||
442 | { | ||
443 | printf("\nwcstombs; len = %d %ls \n", (int)src.Len(), src.Ptr()); | ||
444 | for (unsigned i = 0; i < src.Len(); i++) | ||
445 | printf (" %02x", (int)src[i]); | ||
446 | printf("\n"); | ||
447 | printf("\ndest Limit = %d \n", limit); | ||
448 | } | ||
449 | */ | ||
450 | |||
451 | const size_t len2 = wcstombs(d, src, len + 1); | ||
452 | |||
453 | if (len2 != (size_t)-1 && len2 <= limit) | ||
454 | { | ||
455 | /* | ||
456 | printf("\nOK : destLen = %d : %s\n", (int)len, dest.Ptr()); | ||
457 | for (unsigned i = 0; i < len2; i++) | ||
458 | printf(" %02x", (int)(Byte)dest[i]); | ||
459 | printf("\n"); | ||
460 | */ | ||
461 | dest.ReleaseBuf_SetEnd((unsigned)len2); | ||
462 | return; | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | |||
467 | { | ||
468 | const wchar_t *s = (const wchar_t *)src; | ||
469 | char *d = dest.GetBuf(src.Len()); | ||
470 | |||
471 | unsigned i; | ||
472 | for (i = 0;;) | ||
473 | { | ||
474 | wchar_t c = s[i]; | ||
475 | if (c == 0) | ||
476 | break; | ||
477 | if (c >= | ||
478 | 0x100 | ||
479 | // 0x80 | ||
480 | ) | ||
481 | { | ||
482 | c = defaultChar; | ||
483 | defaultCharWasUsed = true; | ||
484 | } | ||
485 | |||
486 | d[i++] = (char)c; | ||
487 | } | ||
488 | d[i] = 0; | ||
489 | dest.ReleaseBuf_SetLen(i); | ||
490 | /* | ||
491 | printf("\nUnicodeStringToMultiByte2; len = %d \n", (int)src.Len()); | ||
492 | printf("ERROR: %s\n", dest.Ptr()); | ||
493 | */ | ||
494 | } | ||
495 | } | ||
496 | |||
497 | #endif // _WIN32 | ||
498 | |||
499 | |||
500 | UString MultiByteToUnicodeString(const AString &src, UINT codePage) | ||
501 | { | ||
502 | UString dest; | ||
503 | MultiByteToUnicodeString2(dest, src, codePage); | ||
504 | return dest; | ||
505 | } | ||
506 | |||
507 | UString MultiByteToUnicodeString(const char *src, UINT codePage) | ||
508 | { | ||
509 | return MultiByteToUnicodeString(AString(src), codePage); | ||
510 | } | ||
511 | |||
512 | |||
513 | void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage) | ||
514 | { | ||
515 | bool defaultCharWasUsed; | ||
516 | UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed); | ||
517 | } | ||
518 | |||
519 | AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed) | ||
520 | { | ||
521 | AString dest; | ||
522 | UnicodeStringToMultiByte2(dest, src, codePage, defaultChar, defaultCharWasUsed); | ||
523 | return dest; | ||
524 | } | ||
525 | |||
526 | AString UnicodeStringToMultiByte(const UString &src, UINT codePage) | ||
527 | { | ||
528 | AString dest; | ||
529 | bool defaultCharWasUsed; | ||
530 | UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed); | ||
531 | return dest; | ||
532 | } | ||
533 | |||
534 | |||
535 | |||
536 | |||
537 | |||
538 | #ifdef _WIN32 | ||
539 | #define U_to_A(a, b, c) UnicodeStringToMultiByte2 | ||
540 | // #define A_to_U(a, b, c) MultiByteToUnicodeString2 | ||
541 | #else | ||
542 | // void MultiByteToUnicodeString2_Native(UString &dest, const AString &src); | ||
543 | #define U_to_A(a, b, c) UnicodeStringToMultiByte2_Native(a, b) | ||
544 | // #define A_to_U(a, b, c) MultiByteToUnicodeString2_Native(a, b) | ||
545 | #endif | ||
546 | |||
547 | #if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) | ||
548 | |||
549 | bool IsNativeUTF8() | ||
550 | { | ||
551 | UString u; | ||
552 | AString a, a2; | ||
553 | // for (unsigned c = 0x80; c < (UInt32)0x10000; c += (c >> 9) + 1) | ||
554 | for (unsigned c = 0x80; c < (UInt32)0xD000; c += (c >> 2) + 1) | ||
555 | { | ||
556 | u.Empty(); | ||
557 | u += (wchar_t)c; | ||
558 | /* | ||
559 | if (Unicode_Is_There_Utf16SurrogateError(u)) | ||
560 | continue; | ||
561 | #ifndef _WIN32 | ||
562 | if (Unicode_Is_There_BmpEscape(u)) | ||
563 | continue; | ||
564 | #endif | ||
565 | */ | ||
566 | ConvertUnicodeToUTF8(u, a); | ||
567 | U_to_A(a2, u, CP_OEMCP); | ||
568 | if (a != a2) | ||
569 | return false; | ||
570 | } | ||
571 | return true; | ||
572 | } | ||
573 | |||
574 | #endif | ||
575 | |||
576 | |||
577 | #ifdef ENV_HAVE_LOCALE | ||
578 | |||
579 | const char *GetLocale(void) | ||
580 | { | ||
581 | #ifdef ENV_HAVE_LOCALE | ||
582 | // printf("\n\nsetlocale(LC_CTYPE, NULL) : return : "); | ||
583 | const char *s = setlocale(LC_CTYPE, NULL); | ||
584 | if (!s) | ||
585 | { | ||
586 | // printf("[NULL]\n"); | ||
587 | s = "C"; | ||
588 | } | ||
589 | else | ||
590 | { | ||
591 | // ubuntu returns "C" after program start | ||
592 | // printf("\"%s\"\n", s); | ||
593 | } | ||
594 | return s; | ||
595 | #elif defined(LOCALE_IS_UTF8) | ||
596 | return "utf8"; | ||
597 | #else | ||
598 | return "C"; | ||
599 | #endif | ||
600 | } | ||
601 | |||
602 | #ifdef _WIN32 | ||
603 | static void Set_ForceToUTF8(bool) {} | ||
604 | #else | ||
605 | static void Set_ForceToUTF8(bool val) { g_ForceToUTF8 = val; } | ||
606 | #endif | ||
607 | |||
608 | static bool Is_Default_Basic_Locale(const char *locale) | ||
609 | { | ||
610 | const AString a (locale); | ||
611 | if (a.IsEqualTo_Ascii_NoCase("") | ||
612 | || a.IsEqualTo_Ascii_NoCase("C") | ||
613 | || a.IsEqualTo_Ascii_NoCase("POSIX")) | ||
614 | return true; | ||
615 | return false; | ||
616 | } | ||
617 | |||
618 | static bool Is_Default_Basic_Locale() | ||
619 | { | ||
620 | return Is_Default_Basic_Locale(GetLocale()); | ||
621 | } | ||
622 | |||
623 | |||
624 | void MY_SetLocale() | ||
625 | { | ||
626 | #ifdef ENV_HAVE_LOCALE | ||
627 | /* | ||
628 | { | ||
629 | const char *s = GetLocale(); | ||
630 | printf("\nGetLocale() : returned : \"%s\"\n", s); | ||
631 | } | ||
632 | */ | ||
633 | |||
634 | unsigned start = 0; | ||
635 | // unsigned lim = 0; | ||
636 | unsigned lim = 3; | ||
637 | |||
638 | /* | ||
639 | #define MY_SET_LOCALE_FLAGS__FROM_ENV 1 | ||
640 | #define MY_SET_LOCALE_FLAGS__TRY_UTF8 2 | ||
641 | |||
642 | unsigned flags = | ||
643 | MY_SET_LOCALE_FLAGS__FROM_ENV | | ||
644 | MY_SET_LOCALE_FLAGS__TRY_UTF8 | ||
645 | |||
646 | if (flags != 0) | ||
647 | { | ||
648 | if (flags & MY_SET_LOCALE_FLAGS__FROM_ENV) | ||
649 | lim = (flags & MY_SET_LOCALE_FLAGS__TRY_UTF8) ? 3 : 1; | ||
650 | else | ||
651 | { | ||
652 | start = 1; | ||
653 | lim = 2; | ||
654 | } | ||
655 | } | ||
656 | */ | ||
657 | |||
658 | for (unsigned i = start; i < lim; i++) | ||
659 | { | ||
660 | /* | ||
661 | man7: "If locale is an empty string, "", each part of the locale that | ||
662 | should be modified is set according to the environment variables. | ||
663 | for glibc: glibc, first from the user's environment variables: | ||
664 | 1) the environment variable LC_ALL, | ||
665 | 2) environment variable with the same name as the category (see the | ||
666 | 3) the environment variable LANG | ||
667 | The locale "C" or "POSIX" is a portable locale; it exists on all conforming systems. | ||
668 | |||
669 | for WIN32 : MSDN : | ||
670 | Sets the locale to the default, which is the user-default | ||
671 | ANSI code page obtained from the operating system. | ||
672 | The locale name is set to the value returned by GetUserDefaultLocaleName. | ||
673 | The code page is set to the value returned by GetACP | ||
674 | */ | ||
675 | const char *newLocale = ""; | ||
676 | |||
677 | #ifdef __APPLE__ | ||
678 | |||
679 | /* look also CFLocale | ||
680 | there is no C.UTF-8 in macos | ||
681 | macos has UTF-8 locale only with some language like en_US.UTF-8 | ||
682 | what is best way to set UTF-8 locale in macos? */ | ||
683 | if (i == 1) | ||
684 | newLocale = "en_US.UTF-8"; | ||
685 | |||
686 | /* file open with non-utf8 sequencies return | ||
687 | #define EILSEQ 92 // "Illegal byte sequence" | ||
688 | */ | ||
689 | #else | ||
690 | // newLocale = "C"; | ||
691 | if (i == 1) | ||
692 | { | ||
693 | newLocale = "C.UTF-8"; // main UTF-8 locale in ubuntu | ||
694 | // newLocale = ".utf8"; // supported in new Windows 10 build 17134 (April 2018 Update), the Universal C Runtime | ||
695 | // newLocale = "en_US.utf8"; // supported by ubuntu ? | ||
696 | // newLocale = "en_US.UTF-8"; | ||
697 | /* setlocale() in ubuntu allows locales with minor chracter changes in strings | ||
698 | "en_US.UTF-8" / "en_US.utf8" */ | ||
699 | } | ||
700 | |||
701 | #endif | ||
702 | |||
703 | // printf("\nsetlocale(LC_ALL, \"%s\") : returned: ", newLocale); | ||
704 | |||
705 | // const char *s = | ||
706 | setlocale(LC_ALL, newLocale); | ||
707 | |||
708 | /* | ||
709 | if (!s) | ||
710 | printf("NULL: can't set locale"); | ||
711 | else | ||
712 | printf("\"%s\"\n", s); | ||
713 | */ | ||
714 | |||
715 | // request curent locale of program | ||
716 | const char *locale = GetLocale(); | ||
717 | if (locale) | ||
718 | { | ||
719 | AString a (locale); | ||
720 | a.MakeLower_Ascii(); | ||
721 | // if (a.Find("utf") >= 0) | ||
722 | { | ||
723 | if (IsNativeUTF8()) | ||
724 | { | ||
725 | Set_ForceToUTF8(true); | ||
726 | return; | ||
727 | } | ||
728 | } | ||
729 | if (!Is_Default_Basic_Locale(locale)) | ||
730 | { | ||
731 | // if there is some non-default and non-utf locale, we want to use it | ||
732 | break; // comment it for debug | ||
733 | } | ||
734 | } | ||
735 | } | ||
736 | |||
737 | if (IsNativeUTF8()) | ||
738 | { | ||
739 | Set_ForceToUTF8(true); | ||
740 | return; | ||
741 | } | ||
742 | |||
743 | if (Is_Default_Basic_Locale()) | ||
744 | { | ||
745 | Set_ForceToUTF8(true); | ||
746 | return; | ||
747 | } | ||
748 | |||
749 | Set_ForceToUTF8(false); | ||
750 | |||
751 | #elif defined(LOCALE_IS_UTF8) | ||
752 | // assume LC_CTYPE="utf8" | ||
753 | #else | ||
754 | // assume LC_CTYPE="C" | ||
755 | #endif | ||
756 | } | ||
757 | #endif | ||
diff --git a/CPP/Common/StringConvert.h b/CPP/Common/StringConvert.h new file mode 100644 index 0000000..865c025 --- /dev/null +++ b/CPP/Common/StringConvert.h | |||
@@ -0,0 +1,110 @@ | |||
1 | // Common/StringConvert.h | ||
2 | |||
3 | #ifndef __COMMON_STRING_CONVERT_H | ||
4 | #define __COMMON_STRING_CONVERT_H | ||
5 | |||
6 | #include "MyString.h" | ||
7 | #include "MyWindows.h" | ||
8 | |||
9 | UString MultiByteToUnicodeString(const AString &src, UINT codePage = CP_ACP); | ||
10 | UString MultiByteToUnicodeString(const char *src, UINT codePage = CP_ACP); | ||
11 | |||
12 | // optimized versions that work faster for ASCII strings | ||
13 | void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage = CP_ACP); | ||
14 | // void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed); | ||
15 | void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage); | ||
16 | |||
17 | AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed); | ||
18 | AString UnicodeStringToMultiByte(const UString &src, UINT codePage = CP_ACP); | ||
19 | |||
20 | inline const wchar_t* GetUnicodeString(const wchar_t *u) { return u; } | ||
21 | inline const UString& GetUnicodeString(const UString &u) { return u; } | ||
22 | |||
23 | inline UString GetUnicodeString(const AString &a) { return MultiByteToUnicodeString(a); } | ||
24 | inline UString GetUnicodeString(const char *a) { return MultiByteToUnicodeString(a); } | ||
25 | |||
26 | inline UString GetUnicodeString(const AString &a, UINT codePage) | ||
27 | { return MultiByteToUnicodeString(a, codePage); } | ||
28 | inline UString GetUnicodeString(const char *a, UINT codePage) | ||
29 | { return MultiByteToUnicodeString(a, codePage); } | ||
30 | |||
31 | inline const wchar_t* GetUnicodeString(const wchar_t *u, UINT) { return u; } | ||
32 | inline const UString& GetUnicodeString(const UString &u, UINT) { return u; } | ||
33 | |||
34 | inline const char* GetAnsiString(const char *a) { return a; } | ||
35 | inline const AString& GetAnsiString(const AString &a) { return a; } | ||
36 | |||
37 | inline AString GetAnsiString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); } | ||
38 | inline AString GetAnsiString(const UString &u) { return UnicodeStringToMultiByte(u); } | ||
39 | |||
40 | /* | ||
41 | inline const char* GetOemString(const char* oem) | ||
42 | { return oem; } | ||
43 | inline const AString& GetOemString(const AString &oem) | ||
44 | { return oem; } | ||
45 | */ | ||
46 | const char* GetOemString(const char* oem); | ||
47 | const AString& GetOemString(const AString &oem); | ||
48 | inline AString GetOemString(const UString &u) | ||
49 | { return UnicodeStringToMultiByte(u, CP_OEMCP); } | ||
50 | |||
51 | #ifdef _UNICODE | ||
52 | inline const wchar_t* GetSystemString(const wchar_t *u) { return u;} | ||
53 | inline const UString& GetSystemString(const UString &u) { return u;} | ||
54 | inline const wchar_t* GetSystemString(const wchar_t *u, UINT /* codePage */) { return u;} | ||
55 | inline const UString& GetSystemString(const UString &u, UINT /* codePage */) { return u;} | ||
56 | |||
57 | inline UString GetSystemString(const AString &a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); } | ||
58 | inline UString GetSystemString(const char *a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); } | ||
59 | inline UString GetSystemString(const AString &a) { return MultiByteToUnicodeString(a); } | ||
60 | inline UString GetSystemString(const char *a) { return MultiByteToUnicodeString(a); } | ||
61 | #else | ||
62 | inline const char* GetSystemString(const char *a) { return a; } | ||
63 | inline const AString& GetSystemString(const AString &a) { return a; } | ||
64 | inline const char* GetSystemString(const char *a, UINT) { return a; } | ||
65 | inline const AString& GetSystemString(const AString &a, UINT) { return a; } | ||
66 | |||
67 | inline AString GetSystemString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); } | ||
68 | inline AString GetSystemString(const UString &u) { return UnicodeStringToMultiByte(u); } | ||
69 | inline AString GetSystemString(const UString &u, UINT codePage) { return UnicodeStringToMultiByte(u, codePage); } | ||
70 | |||
71 | |||
72 | |||
73 | /* | ||
74 | inline AString GetSystemString(const wchar_t *u) | ||
75 | { | ||
76 | UString s; | ||
77 | s = u; | ||
78 | return UnicodeStringToMultiByte(s); | ||
79 | } | ||
80 | */ | ||
81 | |||
82 | #endif | ||
83 | |||
84 | #ifndef UNDER_CE | ||
85 | AString SystemStringToOemString(const CSysString &src); | ||
86 | #endif | ||
87 | |||
88 | |||
89 | #ifdef _WIN32 | ||
90 | /* we don't need locale functions in Windows | ||
91 | but we can define ENV_HAVE_LOCALE here for debug purposes */ | ||
92 | // #define ENV_HAVE_LOCALE | ||
93 | #else | ||
94 | #define ENV_HAVE_LOCALE | ||
95 | #endif | ||
96 | |||
97 | #ifdef ENV_HAVE_LOCALE | ||
98 | void MY_SetLocale(); | ||
99 | const char *GetLocale(void); | ||
100 | #endif | ||
101 | |||
102 | #if !defined(_WIN32) || defined(ENV_HAVE_LOCALE) | ||
103 | bool IsNativeUTF8(); | ||
104 | #endif | ||
105 | |||
106 | #ifndef _WIN32 | ||
107 | extern bool g_ForceToUTF8; | ||
108 | #endif | ||
109 | |||
110 | #endif | ||
diff --git a/CPP/Common/StringToInt.cpp b/CPP/Common/StringToInt.cpp new file mode 100644 index 0000000..839867a --- /dev/null +++ b/CPP/Common/StringToInt.cpp | |||
@@ -0,0 +1,144 @@ | |||
1 | // Common/StringToInt.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "StringToInt.h" | ||
6 | |||
7 | static const UInt32 k_UInt32_max = 0xFFFFFFFF; | ||
8 | static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF); | ||
9 | // static const UInt64 k_UInt64_max = (UInt64)(Int64)-1; | ||
10 | |||
11 | #define CONVERT_STRING_TO_UINT_FUNC(uintType, charType, charTypeUnsigned) \ | ||
12 | uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \ | ||
13 | if (end) *end = s; \ | ||
14 | uintType res = 0; \ | ||
15 | for (;; s++) { \ | ||
16 | charTypeUnsigned c = (charTypeUnsigned)*s; \ | ||
17 | if (c < '0' || c > '9') { if (end) *end = s; return res; } \ | ||
18 | if (res > (k_ ## uintType ## _max) / 10) return 0; \ | ||
19 | res *= 10; \ | ||
20 | unsigned v = (unsigned)(c - '0'); \ | ||
21 | if (res > (k_ ## uintType ## _max) - v) return 0; \ | ||
22 | res += v; }} | ||
23 | |||
24 | CONVERT_STRING_TO_UINT_FUNC(UInt32, char, Byte) | ||
25 | CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t, wchar_t) | ||
26 | CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte) | ||
27 | CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t) | ||
28 | |||
29 | Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw() | ||
30 | { | ||
31 | if (end) | ||
32 | *end = s; | ||
33 | const wchar_t *s2 = s; | ||
34 | if (*s == '-') | ||
35 | s2++; | ||
36 | if (*s2 == 0) | ||
37 | return 0; | ||
38 | const wchar_t *end2; | ||
39 | UInt32 res = ConvertStringToUInt32(s2, &end2); | ||
40 | if (*s == '-') | ||
41 | { | ||
42 | if (res > ((UInt32)1 << (32 - 1))) | ||
43 | return 0; | ||
44 | } | ||
45 | else if ((res & ((UInt32)1 << (32 - 1))) != 0) | ||
46 | return 0; | ||
47 | if (end) | ||
48 | *end = end2; | ||
49 | if (*s == '-') | ||
50 | return -(Int32)res; | ||
51 | return (Int32)res; | ||
52 | } | ||
53 | |||
54 | UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw() | ||
55 | { | ||
56 | if (end) | ||
57 | *end = s; | ||
58 | UInt32 res = 0; | ||
59 | for (;; s++) | ||
60 | { | ||
61 | unsigned c = (unsigned char)*s; | ||
62 | if (c < '0' || c > '7') | ||
63 | { | ||
64 | if (end) | ||
65 | *end = s; | ||
66 | return res; | ||
67 | } | ||
68 | if ((res & (UInt32)7 << (32 - 3)) != 0) | ||
69 | return 0; | ||
70 | res <<= 3; | ||
71 | res |= (unsigned)(c - '0'); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw() | ||
76 | { | ||
77 | if (end) | ||
78 | *end = s; | ||
79 | UInt64 res = 0; | ||
80 | for (;; s++) | ||
81 | { | ||
82 | unsigned c = (unsigned char)*s; | ||
83 | if (c < '0' || c > '7') | ||
84 | { | ||
85 | if (end) | ||
86 | *end = s; | ||
87 | return res; | ||
88 | } | ||
89 | if ((res & (UInt64)7 << (64 - 3)) != 0) | ||
90 | return 0; | ||
91 | res <<= 3; | ||
92 | res |= (unsigned)(c - '0'); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw() | ||
97 | { | ||
98 | if (end) | ||
99 | *end = s; | ||
100 | UInt32 res = 0; | ||
101 | for (;; s++) | ||
102 | { | ||
103 | unsigned c = (Byte)*s; | ||
104 | unsigned v; | ||
105 | if (c >= '0' && c <= '9') v = (c - '0'); | ||
106 | else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); | ||
107 | else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); | ||
108 | else | ||
109 | { | ||
110 | if (end) | ||
111 | *end = s; | ||
112 | return res; | ||
113 | } | ||
114 | if ((res & (UInt32)0xF << (32 - 4)) != 0) | ||
115 | return 0; | ||
116 | res <<= 4; | ||
117 | res |= v; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw() | ||
122 | { | ||
123 | if (end) | ||
124 | *end = s; | ||
125 | UInt64 res = 0; | ||
126 | for (;; s++) | ||
127 | { | ||
128 | unsigned c = (Byte)*s; | ||
129 | unsigned v; | ||
130 | if (c >= '0' && c <= '9') v = (c - '0'); | ||
131 | else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A'); | ||
132 | else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a'); | ||
133 | else | ||
134 | { | ||
135 | if (end) | ||
136 | *end = s; | ||
137 | return res; | ||
138 | } | ||
139 | if ((res & (UInt64)0xF << (64 - 4)) != 0) | ||
140 | return 0; | ||
141 | res <<= 4; | ||
142 | res |= v; | ||
143 | } | ||
144 | } | ||
diff --git a/CPP/Common/StringToInt.h b/CPP/Common/StringToInt.h new file mode 100644 index 0000000..5c5d7d7 --- /dev/null +++ b/CPP/Common/StringToInt.h | |||
@@ -0,0 +1,21 @@ | |||
1 | // Common/StringToInt.h | ||
2 | |||
3 | #ifndef __COMMON_STRING_TO_INT_H | ||
4 | #define __COMMON_STRING_TO_INT_H | ||
5 | |||
6 | #include "MyTypes.h" | ||
7 | |||
8 | UInt32 ConvertStringToUInt32(const char *s, const char **end) throw(); | ||
9 | UInt64 ConvertStringToUInt64(const char *s, const char **end) throw(); | ||
10 | UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw(); | ||
11 | UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw(); | ||
12 | |||
13 | Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw(); | ||
14 | |||
15 | UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw(); | ||
16 | UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw(); | ||
17 | |||
18 | UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw(); | ||
19 | UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw(); | ||
20 | |||
21 | #endif | ||
diff --git a/CPP/Common/TextConfig.cpp b/CPP/Common/TextConfig.cpp new file mode 100644 index 0000000..1428aab --- /dev/null +++ b/CPP/Common/TextConfig.cpp | |||
@@ -0,0 +1,124 @@ | |||
1 | // Common/TextConfig.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "TextConfig.h" | ||
6 | #include "UTFConvert.h" | ||
7 | |||
8 | static inline bool IsDelimitChar(char c) | ||
9 | { | ||
10 | return (c == ' ' || c == 0x0A || c == 0x0D || c == '\0' || c == '\t'); | ||
11 | } | ||
12 | |||
13 | static AString GetIDString(const char *s, unsigned &finishPos) | ||
14 | { | ||
15 | AString result; | ||
16 | for (finishPos = 0; ; finishPos++) | ||
17 | { | ||
18 | char c = s[finishPos]; | ||
19 | if (IsDelimitChar(c) || c == '=') | ||
20 | break; | ||
21 | result += c; | ||
22 | } | ||
23 | return result; | ||
24 | } | ||
25 | |||
26 | static bool WaitNextLine(const AString &s, unsigned &pos) | ||
27 | { | ||
28 | for (; pos < s.Len(); pos++) | ||
29 | if (s[pos] == 0x0A) | ||
30 | return true; | ||
31 | return false; | ||
32 | } | ||
33 | |||
34 | static bool SkipSpaces(const AString &s, unsigned &pos) | ||
35 | { | ||
36 | for (; pos < s.Len(); pos++) | ||
37 | { | ||
38 | char c = s[pos]; | ||
39 | if (!IsDelimitChar(c)) | ||
40 | { | ||
41 | if (c != ';') | ||
42 | return true; | ||
43 | if (!WaitNextLine(s, pos)) | ||
44 | return false; | ||
45 | } | ||
46 | } | ||
47 | return false; | ||
48 | } | ||
49 | |||
50 | bool GetTextConfig(const AString &s, CObjectVector<CTextConfigPair> &pairs) | ||
51 | { | ||
52 | pairs.Clear(); | ||
53 | unsigned pos = 0; | ||
54 | |||
55 | ///////////////////// | ||
56 | // read strings | ||
57 | |||
58 | for (;;) | ||
59 | { | ||
60 | if (!SkipSpaces(s, pos)) | ||
61 | break; | ||
62 | CTextConfigPair pair; | ||
63 | unsigned finishPos; | ||
64 | const AString temp (GetIDString(((const char *)s) + pos, finishPos)); | ||
65 | if (!ConvertUTF8ToUnicode(temp, pair.ID)) | ||
66 | return false; | ||
67 | if (finishPos == 0) | ||
68 | return false; | ||
69 | pos += finishPos; | ||
70 | if (!SkipSpaces(s, pos)) | ||
71 | return false; | ||
72 | if (s[pos] != '=') | ||
73 | return false; | ||
74 | pos++; | ||
75 | if (!SkipSpaces(s, pos)) | ||
76 | return false; | ||
77 | if (s[pos] != '\"') | ||
78 | return false; | ||
79 | pos++; | ||
80 | AString message; | ||
81 | for (;;) | ||
82 | { | ||
83 | if (pos >= s.Len()) | ||
84 | return false; | ||
85 | char c = s[pos++]; | ||
86 | if (c == '\"') | ||
87 | break; | ||
88 | if (c == '\\') | ||
89 | { | ||
90 | c = s[pos++]; | ||
91 | switch (c) | ||
92 | { | ||
93 | case 'n': message += '\n'; break; | ||
94 | case 't': message += '\t'; break; | ||
95 | case '\\': message += '\\'; break; | ||
96 | case '\"': message += '\"'; break; | ||
97 | default: message += '\\'; message += c; break; | ||
98 | } | ||
99 | } | ||
100 | else | ||
101 | message += c; | ||
102 | } | ||
103 | if (!ConvertUTF8ToUnicode(message, pair.String)) | ||
104 | return false; | ||
105 | pairs.Add(pair); | ||
106 | } | ||
107 | return true; | ||
108 | } | ||
109 | |||
110 | int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw() | ||
111 | { | ||
112 | FOR_VECTOR (i, pairs) | ||
113 | if (pairs[i].ID.IsEqualTo(id)) | ||
114 | return i; | ||
115 | return -1; | ||
116 | } | ||
117 | |||
118 | UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id) | ||
119 | { | ||
120 | int index = FindTextConfigItem(pairs, id); | ||
121 | if (index < 0) | ||
122 | return UString(); | ||
123 | return pairs[index].String; | ||
124 | } | ||
diff --git a/CPP/Common/TextConfig.h b/CPP/Common/TextConfig.h new file mode 100644 index 0000000..cc7ce41 --- /dev/null +++ b/CPP/Common/TextConfig.h | |||
@@ -0,0 +1,19 @@ | |||
1 | // Common/TextConfig.h | ||
2 | |||
3 | #ifndef __COMMON_TEXT_CONFIG_H | ||
4 | #define __COMMON_TEXT_CONFIG_H | ||
5 | |||
6 | #include "MyString.h" | ||
7 | |||
8 | struct CTextConfigPair | ||
9 | { | ||
10 | UString ID; | ||
11 | UString String; | ||
12 | }; | ||
13 | |||
14 | bool GetTextConfig(const AString &text, CObjectVector<CTextConfigPair> &pairs); | ||
15 | |||
16 | int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw(); | ||
17 | UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id); | ||
18 | |||
19 | #endif | ||
diff --git a/CPP/Common/UTFConvert.cpp b/CPP/Common/UTFConvert.cpp new file mode 100644 index 0000000..ac069db --- /dev/null +++ b/CPP/Common/UTFConvert.cpp | |||
@@ -0,0 +1,863 @@ | |||
1 | // UTFConvert.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | // #include <stdio.h> | ||
6 | |||
7 | #include "MyTypes.h" | ||
8 | #include "UTFConvert.h" | ||
9 | |||
10 | |||
11 | #ifndef _WCHART_IS_16BIT | ||
12 | #ifndef __APPLE__ | ||
13 | // we define it if the system supports files with non-utf8 symbols: | ||
14 | #define _UTF8_RAW_NON_UTF8_SUPPORTED | ||
15 | #endif | ||
16 | #endif | ||
17 | |||
18 | /* | ||
19 | _UTF8_START(n) - is a base value for start byte (head), if there are (n) additional bytes after start byte | ||
20 | |||
21 | n : _UTF8_START(n) : Bits of code point | ||
22 | |||
23 | 0 : 0x80 : : unused | ||
24 | 1 : 0xC0 : 11 : | ||
25 | 2 : 0xE0 : 16 : Basic Multilingual Plane | ||
26 | 3 : 0xF0 : 21 : Unicode space | ||
27 | 4 : 0xF8 : 26 : | ||
28 | 5 : 0xFC : 31 : UCS-4 : wcstombs() in ubuntu is limited to that value | ||
29 | 6 : 0xFE : 36 : We can use it, if we want to encode any 32-bit value | ||
30 | 7 : 0xFF : | ||
31 | */ | ||
32 | |||
33 | #define _UTF8_START(n) (0x100 - (1 << (7 - (n)))) | ||
34 | |||
35 | #define _UTF8_HEAD_PARSE2(n) \ | ||
36 | if (c < _UTF8_START((n) + 1)) \ | ||
37 | { numBytes = (n); val -= _UTF8_START(n); } | ||
38 | |||
39 | #ifndef _WCHART_IS_16BIT | ||
40 | |||
41 | /* | ||
42 | if (wchar_t is 32-bit), we can support large points in long UTF-8 sequence, | ||
43 | when we convert wchar_t strings to UTF-8: | ||
44 | (_UTF8_NUM_TAIL_BYTES_MAX == 3) : (21-bits points) - Unicode | ||
45 | (_UTF8_NUM_TAIL_BYTES_MAX == 5) : (31-bits points) - UCS-4 | ||
46 | (_UTF8_NUM_TAIL_BYTES_MAX == 6) : (36-bit hack) | ||
47 | */ | ||
48 | |||
49 | #define _UTF8_NUM_TAIL_BYTES_MAX 5 | ||
50 | #endif | ||
51 | |||
52 | /* | ||
53 | #define _UTF8_HEAD_PARSE \ | ||
54 | UInt32 val = c; \ | ||
55 | _UTF8_HEAD_PARSE2(1) \ | ||
56 | else _UTF8_HEAD_PARSE2(2) \ | ||
57 | else _UTF8_HEAD_PARSE2(3) \ | ||
58 | else _UTF8_HEAD_PARSE2(4) \ | ||
59 | else _UTF8_HEAD_PARSE2(5) \ | ||
60 | #if _UTF8_NUM_TAIL_BYTES_MAX >= 6 | ||
61 | else _UTF8_HEAD_PARSE2(6) | ||
62 | #endif | ||
63 | */ | ||
64 | |||
65 | #define _UTF8_HEAD_PARSE_MAX_3_BYTES \ | ||
66 | UInt32 val = c; \ | ||
67 | _UTF8_HEAD_PARSE2(1) \ | ||
68 | else _UTF8_HEAD_PARSE2(2) \ | ||
69 | else { numBytes = 3; val -= _UTF8_START(3); } | ||
70 | |||
71 | |||
72 | #define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6)) | ||
73 | |||
74 | |||
75 | #define START_POINT_FOR_SURROGATE 0x10000 | ||
76 | |||
77 | |||
78 | /* we use 128 bytes block in 16-bit BMP-PLANE to encode non-UTF-8 Escapes | ||
79 | Also we can use additional HIGH-PLANE (we use 21-bit points above 0x1f0000) | ||
80 | to simplify internal intermediate conversion in Linux: | ||
81 | RAW-UTF-8 <-> internal wchar_t utf-16 strings <-> RAW-UTF-UTF-8 | ||
82 | */ | ||
83 | |||
84 | |||
85 | #if defined(_WCHART_IS_16BIT) | ||
86 | |||
87 | #define UTF_ESCAPE_PLANE 0 | ||
88 | |||
89 | #else | ||
90 | |||
91 | /* | ||
92 | we can place 128 ESCAPE chars to | ||
93 | ef 80 - ee be 80 (3-bytes utf-8) : similar to WSL | ||
94 | ef ff - ee bf bf | ||
95 | |||
96 | 1f ef 80 - f7 be be 80 (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode) | ||
97 | 1f ef ff - f7 be bf bf (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode) | ||
98 | */ | ||
99 | |||
100 | // #define UTF_ESCAPE_PLANE_HIGH (0x1f << 16) | ||
101 | // #define UTF_ESCAPE_PLANE UTF_ESCAPE_PLANE_HIGH | ||
102 | #define UTF_ESCAPE_PLANE 0 | ||
103 | |||
104 | /* | ||
105 | if (UTF_FLAG__FROM_UTF8__USE_ESCAPE is set) | ||
106 | { | ||
107 | if (UTF_ESCAPE_PLANE is UTF_ESCAPE_PLANE_HIGH) | ||
108 | { | ||
109 | we can restore any 8-bit Escape from ESCAPE-PLANE-21 plane. | ||
110 | But ESCAPE-PLANE-21 point cannot be stored to utf-16 (7z archive) | ||
111 | So we still need a way to extract 8-bit Escapes and BMP-Escapes-8 | ||
112 | from same BMP-Escapes-16 stored in 7z. | ||
113 | And if we want to restore any 8-bit from 7z archive, | ||
114 | we still must use UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT for (utf-8 -> utf-16) | ||
115 | Also we need additional Conversions to tranform from utf-16 to utf-16-With-Escapes-21 | ||
116 | } | ||
117 | else (UTF_ESCAPE_PLANE == 0) | ||
118 | { | ||
119 | we must convert original 3-bytes utf-8 BMP-Escape point to sequence | ||
120 | of 3 BMP-Escape-16 points with UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT | ||
121 | so we can extract original RAW-UTF-8 from UTFD-16 later. | ||
122 | } | ||
123 | } | ||
124 | */ | ||
125 | |||
126 | #endif | ||
127 | |||
128 | |||
129 | |||
130 | #define UTF_ESCAPE_BASE 0xef00 | ||
131 | |||
132 | |||
133 | #ifdef UTF_ESCAPE_BASE | ||
134 | #define IS_ESCAPE_POINT(v, plane) (((v) & (UInt32)0xffffff80) == (plane) + UTF_ESCAPE_BASE + 0x80) | ||
135 | #endif | ||
136 | |||
137 | #define IS_SURROGATE_POINT(v) (((v) & (UInt32)0xfffff800) == 0xd800) | ||
138 | #define IS_LOW_SURROGATE_POINT(v) (((v) & (UInt32)0xfffffC00) == 0xdc00) | ||
139 | |||
140 | |||
141 | #define _ERROR_UTF8_CHECK \ | ||
142 | { NonUtf = true; continue; } | ||
143 | |||
144 | void CUtf8Check::Check_Buf(const char *src, size_t size) throw() | ||
145 | { | ||
146 | Clear(); | ||
147 | // Byte maxByte = 0; | ||
148 | |||
149 | for (;;) | ||
150 | { | ||
151 | if (size == 0) | ||
152 | break; | ||
153 | |||
154 | const Byte c = (Byte)(*src++); | ||
155 | size--; | ||
156 | |||
157 | if (c == 0) | ||
158 | { | ||
159 | ZeroChar = true; | ||
160 | continue; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | if (c > maxByte) | ||
165 | maxByte = c; | ||
166 | */ | ||
167 | |||
168 | if (c < 0x80) | ||
169 | continue; | ||
170 | |||
171 | if (c < 0xc0 + 2)// it's limit for 0x140000 unicode codes : win32 compatibility | ||
172 | _ERROR_UTF8_CHECK | ||
173 | |||
174 | unsigned numBytes; | ||
175 | |||
176 | UInt32 val = c; | ||
177 | _UTF8_HEAD_PARSE2(1) | ||
178 | else _UTF8_HEAD_PARSE2(2) | ||
179 | else _UTF8_HEAD_PARSE2(4) | ||
180 | else _UTF8_HEAD_PARSE2(5) | ||
181 | else | ||
182 | { | ||
183 | _ERROR_UTF8_CHECK | ||
184 | } | ||
185 | |||
186 | unsigned pos = 0; | ||
187 | do | ||
188 | { | ||
189 | if (pos == size) | ||
190 | break; | ||
191 | unsigned c2 = (Byte)src[pos]; | ||
192 | c2 -= 0x80; | ||
193 | if (c2 >= 0x40) | ||
194 | break; | ||
195 | val <<= 6; | ||
196 | val |= c2; | ||
197 | if (pos == 0) | ||
198 | if (val < (((unsigned)1 << 7) >> numBytes)) | ||
199 | break; | ||
200 | pos++; | ||
201 | } | ||
202 | while (--numBytes); | ||
203 | |||
204 | if (numBytes != 0) | ||
205 | { | ||
206 | if (pos == size) | ||
207 | Truncated = true; | ||
208 | else | ||
209 | _ERROR_UTF8_CHECK | ||
210 | } | ||
211 | |||
212 | #ifdef UTF_ESCAPE_BASE | ||
213 | if (IS_ESCAPE_POINT(val, 0)) | ||
214 | Escape = true; | ||
215 | #endif | ||
216 | |||
217 | if (MaxHighPoint < val) | ||
218 | MaxHighPoint = val; | ||
219 | |||
220 | if (IS_SURROGATE_POINT(val)) | ||
221 | SingleSurrogate = true; | ||
222 | |||
223 | src += pos; | ||
224 | size -= pos; | ||
225 | } | ||
226 | |||
227 | // MaxByte = maxByte; | ||
228 | } | ||
229 | |||
230 | bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw() | ||
231 | { | ||
232 | CUtf8Check check; | ||
233 | check.Check_Buf(src, size); | ||
234 | return check.IsOK(allowReduced); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | bool CheckUTF8_chars(const char *src, bool allowReduced) throw() | ||
239 | { | ||
240 | CUtf8Check check; | ||
241 | check.CheckBuf(src, strlen(src)); | ||
242 | return check.IsOK(allowReduced); | ||
243 | } | ||
244 | */ | ||
245 | |||
246 | bool CheckUTF8_AString(const AString &s) throw() | ||
247 | { | ||
248 | CUtf8Check check; | ||
249 | check.Check_AString(s); | ||
250 | return check.IsOK(); | ||
251 | } | ||
252 | |||
253 | |||
254 | /* | ||
255 | bool CheckUTF8(const char *src, bool allowReduced) throw() | ||
256 | { | ||
257 | // return Check_UTF8_Buf(src, strlen(src), allowReduced); | ||
258 | |||
259 | for (;;) | ||
260 | { | ||
261 | const Byte c = (Byte)(*src++); | ||
262 | if (c == 0) | ||
263 | return true; | ||
264 | |||
265 | if (c < 0x80) | ||
266 | continue; | ||
267 | if (c < 0xC0 + 2 || c >= 0xf5) | ||
268 | return false; | ||
269 | |||
270 | unsigned numBytes; | ||
271 | _UTF8_HEAD_PARSE | ||
272 | else | ||
273 | return false; | ||
274 | |||
275 | unsigned pos = 0; | ||
276 | |||
277 | do | ||
278 | { | ||
279 | Byte c2 = (Byte)(*src++); | ||
280 | if (c2 < 0x80 || c2 >= 0xC0) | ||
281 | return allowReduced && c2 == 0; | ||
282 | val <<= 6; | ||
283 | val |= (c2 - 0x80); | ||
284 | pos++; | ||
285 | } | ||
286 | while (--numBytes); | ||
287 | |||
288 | if (val < _UTF8_RANGE(pos - 1)) | ||
289 | return false; | ||
290 | |||
291 | if (val >= 0x110000) | ||
292 | return false; | ||
293 | } | ||
294 | } | ||
295 | */ | ||
296 | |||
297 | // in case of UTF-8 error we have two ways: | ||
298 | // 21.01- : old : 0xfffd: REPLACEMENT CHARACTER : old version | ||
299 | // 21.02+ : new : 0xef00 + (c) : similar to WSL scheme for low symbols | ||
300 | |||
301 | #define UTF_REPLACEMENT_CHAR 0xfffd | ||
302 | |||
303 | |||
304 | |||
305 | #define UTF_ESCAPE(c) \ | ||
306 | ((flags & UTF_FLAG__FROM_UTF8__USE_ESCAPE) ? \ | ||
307 | UTF_ESCAPE_PLANE + UTF_ESCAPE_BASE + (c) : UTF_REPLACEMENT_CHAR) | ||
308 | |||
309 | /* | ||
310 | #define _HARD_ERROR_UTF8 | ||
311 | { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \ | ||
312 | destPos++; ok = false; continue; } | ||
313 | */ | ||
314 | |||
315 | // we ignore utf errors, and don't change (ok) variable! | ||
316 | |||
317 | #define _ERROR_UTF8 \ | ||
318 | { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \ | ||
319 | destPos++; continue; } | ||
320 | |||
321 | // we store UTF-16 in wchar_t strings. So we use surrogates for big unicode points: | ||
322 | |||
323 | // for debug puposes only we can store UTF-32 in wchar_t: | ||
324 | // #define START_POINT_FOR_SURROGATE ((UInt32)0 - 1) | ||
325 | |||
326 | |||
327 | /* | ||
328 | WIN32 MultiByteToWideChar(CP_UTF8) emits 0xfffd point, if utf-8 error was found. | ||
329 | Ant it can emit single 0xfffd from 2 src bytes. | ||
330 | It doesn't emit single 0xfffd from 3-4 src bytes. | ||
331 | We can | ||
332 | 1) emit Escape point for each incorrect byte. So we can data recover later | ||
333 | 2) emit 0xfffd for each incorrect byte. | ||
334 | That scheme is similar to Escape scheme, but we emit 0xfffd | ||
335 | instead of each Escape point. | ||
336 | 3) emit single 0xfffd from 1-2 incorrect bytes, as WIN32 MultiByteToWideChar scheme | ||
337 | */ | ||
338 | |||
339 | static bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, const char *srcLim, unsigned flags) throw() | ||
340 | { | ||
341 | size_t destPos = 0; | ||
342 | bool ok = true; | ||
343 | |||
344 | for (;;) | ||
345 | { | ||
346 | if (src == srcLim) | ||
347 | { | ||
348 | *destLen = destPos; | ||
349 | return ok; | ||
350 | } | ||
351 | |||
352 | const Byte c = (Byte)(*src++); | ||
353 | |||
354 | if (c < 0x80) | ||
355 | { | ||
356 | if (dest) | ||
357 | dest[destPos] = (wchar_t)c; | ||
358 | destPos++; | ||
359 | continue; | ||
360 | } | ||
361 | |||
362 | if (c < 0xc0 + 2 | ||
363 | || c >= 0xf5) // it's limit for 0x140000 unicode codes : win32 compatibility | ||
364 | { | ||
365 | _ERROR_UTF8 | ||
366 | } | ||
367 | |||
368 | unsigned numBytes; | ||
369 | |||
370 | _UTF8_HEAD_PARSE_MAX_3_BYTES | ||
371 | |||
372 | unsigned pos = 0; | ||
373 | do | ||
374 | { | ||
375 | if (src + pos == srcLim) | ||
376 | break; | ||
377 | unsigned c2 = (Byte)src[pos]; | ||
378 | c2 -= 0x80; | ||
379 | if (c2 >= 0x40) | ||
380 | break; | ||
381 | val <<= 6; | ||
382 | val |= c2; | ||
383 | pos++; | ||
384 | if (pos == 1) | ||
385 | { | ||
386 | if (val < (((unsigned)1 << 7) >> numBytes)) | ||
387 | break; | ||
388 | if (numBytes == 2) | ||
389 | { | ||
390 | if (flags & UTF_FLAG__FROM_UTF8__SURROGATE_ERROR) | ||
391 | if ((val & (0xF800 >> 6)) == (0xd800 >> 6)) | ||
392 | break; | ||
393 | } | ||
394 | else if (numBytes == 3 && val >= (0x110000 >> 12)) | ||
395 | break; | ||
396 | } | ||
397 | } | ||
398 | while (--numBytes); | ||
399 | |||
400 | if (numBytes != 0) | ||
401 | { | ||
402 | if ((flags & UTF_FLAG__FROM_UTF8__USE_ESCAPE) == 0) | ||
403 | { | ||
404 | // the following code to emit the 0xfffd chars as win32 Utf8 function. | ||
405 | // disable the folling line, if you need 0xfffd for each incorrect byte as in Escape mode | ||
406 | src += pos; | ||
407 | } | ||
408 | _ERROR_UTF8 | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | if (val < _UTF8_RANGE(pos - 1)) | ||
413 | _ERROR_UTF8 | ||
414 | */ | ||
415 | |||
416 | #ifdef UTF_ESCAPE_BASE | ||
417 | |||
418 | if ((flags & UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT) | ||
419 | && IS_ESCAPE_POINT(val, 0)) | ||
420 | { | ||
421 | // We will emit 3 utf16-Escape-16-21 points from one Escape-16 point (3 bytes) | ||
422 | _ERROR_UTF8 | ||
423 | } | ||
424 | |||
425 | #endif | ||
426 | |||
427 | /* | ||
428 | We don't expect virtual Escape-21 points in UTF-8 stream. | ||
429 | And we don't check for Escape-21. | ||
430 | So utf8-Escape-21 will be converted to another 3 utf16-Escape-21 points. | ||
431 | Maybe we could convert virtual utf8-Escape-21 to one utf16-Escape-21 point in some cases? | ||
432 | */ | ||
433 | |||
434 | if (val < START_POINT_FOR_SURROGATE) | ||
435 | { | ||
436 | /* | ||
437 | if ((flags & UTF_FLAG__FROM_UTF8__SURROGATE_ERROR) | ||
438 | && IS_SURROGATE_POINT(val)) | ||
439 | { | ||
440 | // We will emit 3 utf16-Escape-16-21 points from one Surrogate-16 point (3 bytes) | ||
441 | _ERROR_UTF8 | ||
442 | } | ||
443 | */ | ||
444 | if (dest) | ||
445 | dest[destPos] = (wchar_t)val; | ||
446 | destPos++; | ||
447 | } | ||
448 | else | ||
449 | { | ||
450 | /* | ||
451 | if (val >= 0x110000) | ||
452 | { | ||
453 | // We will emit utf16-Escape-16-21 point from each source byte | ||
454 | _ERROR_UTF8 | ||
455 | } | ||
456 | */ | ||
457 | if (dest) | ||
458 | { | ||
459 | dest[destPos + 0] = (wchar_t)(0xd800 - (0x10000 >> 10) + (val >> 10)); | ||
460 | dest[destPos + 1] = (wchar_t)(0xdc00 + (val & 0x3ff)); | ||
461 | } | ||
462 | destPos += 2; | ||
463 | } | ||
464 | src += pos; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | |||
469 | |||
470 | #define _UTF8_HEAD(n, val) ((char)(_UTF8_START(n) + (val >> (6 * (n))))) | ||
471 | #define _UTF8_CHAR(n, val) ((char)(0x80 + (((val) >> (6 * (n))) & 0x3F))) | ||
472 | |||
473 | static size_t Utf16_To_Utf8_Calc(const wchar_t *src, const wchar_t *srcLim, unsigned flags) | ||
474 | { | ||
475 | size_t size = (size_t)(srcLim - src); | ||
476 | for (;;) | ||
477 | { | ||
478 | if (src == srcLim) | ||
479 | return size; | ||
480 | |||
481 | UInt32 val = (UInt32)(*src++); | ||
482 | |||
483 | if (val < 0x80) | ||
484 | continue; | ||
485 | |||
486 | if (val < _UTF8_RANGE(1)) | ||
487 | { | ||
488 | size++; | ||
489 | continue; | ||
490 | } | ||
491 | |||
492 | #ifdef UTF_ESCAPE_BASE | ||
493 | |||
494 | #if UTF_ESCAPE_PLANE != 0 | ||
495 | if (flags & UTF_FLAG__TO_UTF8__PARSE_HIGH_ESCAPE) | ||
496 | if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE)) | ||
497 | continue; | ||
498 | #endif | ||
499 | |||
500 | if (flags & UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE) | ||
501 | if (IS_ESCAPE_POINT(val, 0)) | ||
502 | continue; | ||
503 | |||
504 | #endif | ||
505 | |||
506 | if (IS_SURROGATE_POINT(val)) | ||
507 | { | ||
508 | // it's hack to UTF-8 encoding | ||
509 | |||
510 | if (val < 0xdc00 && src != srcLim) | ||
511 | { | ||
512 | const UInt32 c2 = (UInt32)*src; | ||
513 | if (c2 >= 0xdc00 && c2 < 0xe000) | ||
514 | src++; | ||
515 | } | ||
516 | size += 2; | ||
517 | continue; | ||
518 | } | ||
519 | |||
520 | #ifdef _WCHART_IS_16BIT | ||
521 | |||
522 | size += 2; | ||
523 | |||
524 | #else | ||
525 | |||
526 | if (val < _UTF8_RANGE(2)) size += 2; | ||
527 | else if (val < _UTF8_RANGE(3)) size += 3; | ||
528 | else if (val < _UTF8_RANGE(4)) size += 4; | ||
529 | else if (val < _UTF8_RANGE(5)) size += 5; | ||
530 | else | ||
531 | #if _UTF8_NUM_TAIL_BYTES_MAX >= 6 | ||
532 | size += 6; | ||
533 | #else | ||
534 | size += 3; | ||
535 | #endif | ||
536 | |||
537 | #endif | ||
538 | } | ||
539 | } | ||
540 | |||
541 | |||
542 | static char *Utf16_To_Utf8(char *dest, const wchar_t *src, const wchar_t *srcLim, unsigned flags) | ||
543 | { | ||
544 | for (;;) | ||
545 | { | ||
546 | if (src == srcLim) | ||
547 | return dest; | ||
548 | |||
549 | UInt32 val = (UInt32)*src++; | ||
550 | |||
551 | if (val < 0x80) | ||
552 | { | ||
553 | *dest++ = (char)val; | ||
554 | continue; | ||
555 | } | ||
556 | |||
557 | if (val < _UTF8_RANGE(1)) | ||
558 | { | ||
559 | dest[0] = _UTF8_HEAD(1, val); | ||
560 | dest[1] = _UTF8_CHAR(0, val); | ||
561 | dest += 2; | ||
562 | continue; | ||
563 | } | ||
564 | |||
565 | #ifdef UTF_ESCAPE_BASE | ||
566 | |||
567 | #if UTF_ESCAPE_PLANE != 0 | ||
568 | /* | ||
569 | if (wchar_t is 32-bit) | ||
570 | && (UTF_FLAG__TO_UTF8__PARSE_HIGH_ESCAPE is set) | ||
571 | && (point is virtual escape plane) | ||
572 | we extract 8-bit byte from virtual HIGH-ESCAPE PLANE. | ||
573 | */ | ||
574 | if (flags & UTF_FLAG__TO_UTF8__PARSE_HIGH_ESCAPE) | ||
575 | if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE)) | ||
576 | { | ||
577 | *dest++ = (char)(val); | ||
578 | continue; | ||
579 | } | ||
580 | #endif // UTF_ESCAPE_PLANE != 0 | ||
581 | |||
582 | /* if (UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE is defined) | ||
583 | we extract 8-bit byte from BMP-ESCAPE PLANE. */ | ||
584 | |||
585 | if (flags & UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE) | ||
586 | if (IS_ESCAPE_POINT(val, 0)) | ||
587 | { | ||
588 | *dest++ = (char)(val); | ||
589 | continue; | ||
590 | } | ||
591 | |||
592 | #endif // UTF_ESCAPE_BASE | ||
593 | |||
594 | if (IS_SURROGATE_POINT(val)) | ||
595 | { | ||
596 | // it's hack to UTF-8 encoding | ||
597 | if (val < 0xdc00 && src != srcLim) | ||
598 | { | ||
599 | const UInt32 c2 = (UInt32)*src; | ||
600 | if (IS_LOW_SURROGATE_POINT(c2)) | ||
601 | { | ||
602 | src++; | ||
603 | val = (((val - 0xd800) << 10) | (c2 - 0xdc00)) + 0x10000; | ||
604 | dest[0] = _UTF8_HEAD(3, val); | ||
605 | dest[1] = _UTF8_CHAR(2, val); | ||
606 | dest[2] = _UTF8_CHAR(1, val); | ||
607 | dest[3] = _UTF8_CHAR(0, val); | ||
608 | dest += 4; | ||
609 | continue; | ||
610 | } | ||
611 | } | ||
612 | if (flags & UTF_FLAG__TO_UTF8__SURROGATE_ERROR) | ||
613 | val = UTF_REPLACEMENT_CHAR; // WIN32 function does it | ||
614 | } | ||
615 | |||
616 | #ifndef _WCHART_IS_16BIT | ||
617 | if (val < _UTF8_RANGE(2)) | ||
618 | #endif | ||
619 | { | ||
620 | dest[0] = _UTF8_HEAD(2, val); | ||
621 | dest[1] = _UTF8_CHAR(1, val); | ||
622 | dest[2] = _UTF8_CHAR(0, val); | ||
623 | dest += 3; | ||
624 | continue; | ||
625 | } | ||
626 | |||
627 | #ifndef _WCHART_IS_16BIT | ||
628 | |||
629 | // we don't expect this case. so we can throw exception | ||
630 | // throw 20210407; | ||
631 | |||
632 | char b; | ||
633 | unsigned numBits; | ||
634 | if (val < _UTF8_RANGE(3)) { numBits = 6 * 3; b = _UTF8_HEAD(3, val); } | ||
635 | else if (val < _UTF8_RANGE(4)) { numBits = 6 * 4; b = _UTF8_HEAD(4, val); } | ||
636 | else if (val < _UTF8_RANGE(5)) { numBits = 6 * 5; b = _UTF8_HEAD(5, val); } | ||
637 | #if _UTF8_NUM_TAIL_BYTES_MAX >= 6 | ||
638 | else { numBits = 6 * 6; b = (char)_UTF8_START(6); } | ||
639 | #else | ||
640 | else | ||
641 | { | ||
642 | val = UTF_REPLACEMENT_CHAR; | ||
643 | { numBits = 6 * 3; b = _UTF8_HEAD(3, val); } | ||
644 | } | ||
645 | #endif | ||
646 | |||
647 | *dest++ = b; | ||
648 | |||
649 | do | ||
650 | { | ||
651 | numBits -= 6; | ||
652 | *dest++ = (char)(0x80 + ((val >> numBits) & 0x3F)); | ||
653 | } | ||
654 | while (numBits != 0); | ||
655 | |||
656 | #endif | ||
657 | } | ||
658 | } | ||
659 | |||
660 | bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags) | ||
661 | { | ||
662 | dest.Empty(); | ||
663 | size_t destLen = 0; | ||
664 | Utf8_To_Utf16(NULL, &destLen, src, src + srcSize, flags); | ||
665 | bool res = Utf8_To_Utf16(dest.GetBuf((unsigned)destLen), &destLen, src, src + srcSize, flags); | ||
666 | dest.ReleaseBuf_SetEnd((unsigned)destLen); | ||
667 | return res; | ||
668 | } | ||
669 | |||
670 | bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags) | ||
671 | { | ||
672 | return Convert_UTF8_Buf_To_Unicode(src, src.Len(), dest, flags); | ||
673 | } | ||
674 | |||
675 | |||
676 | static | ||
677 | unsigned g_UTF8_To_Unicode_Flags = | ||
678 | UTF_FLAG__FROM_UTF8__USE_ESCAPE | ||
679 | #ifndef _WCHART_IS_16BIT | ||
680 | | UTF_FLAG__FROM_UTF8__SURROGATE_ERROR | ||
681 | #ifdef _UTF8_RAW_NON_UTF8_SUPPORTED | ||
682 | | UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT | ||
683 | #endif | ||
684 | #endif | ||
685 | ; | ||
686 | |||
687 | |||
688 | /* | ||
689 | bool ConvertUTF8ToUnicode_boolRes(const AString &src, UString &dest) | ||
690 | { | ||
691 | return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags); | ||
692 | } | ||
693 | */ | ||
694 | |||
695 | bool ConvertUTF8ToUnicode(const AString &src, UString &dest) | ||
696 | { | ||
697 | return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags); | ||
698 | } | ||
699 | |||
700 | void Print_UString(const UString &a); | ||
701 | |||
702 | void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags) | ||
703 | { | ||
704 | /* | ||
705 | if (src.Len()== 24) | ||
706 | throw "202104"; | ||
707 | */ | ||
708 | dest.Empty(); | ||
709 | const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags); | ||
710 | char *destStart = dest.GetBuf((unsigned)destLen); | ||
711 | const char *destEnd = Utf16_To_Utf8(destStart, src, src.Ptr(src.Len()), flags); | ||
712 | dest.ReleaseBuf_SetEnd((unsigned)destLen); | ||
713 | // printf("\nlen = %d\n", src.Len()); | ||
714 | if (destLen != (size_t)(destEnd - destStart)) | ||
715 | { | ||
716 | /* | ||
717 | // dest.ReleaseBuf_SetEnd((unsigned)(destEnd - destStart)); | ||
718 | printf("\nlen = %d\n", (unsigned)destLen); | ||
719 | printf("\n(destEnd - destStart) = %d\n", (unsigned)(destEnd - destStart)); | ||
720 | printf("\n"); | ||
721 | // Print_UString(src); | ||
722 | printf("\n"); | ||
723 | // printf("\nlen = %d\n", destLen); | ||
724 | */ | ||
725 | throw 20210406; | ||
726 | } | ||
727 | } | ||
728 | |||
729 | |||
730 | |||
731 | unsigned g_Unicode_To_UTF8_Flags = | ||
732 | // UTF_FLAG__TO_UTF8__PARSE_HIGH_ESCAPE | ||
733 | 0 | ||
734 | #ifndef _WIN32 | ||
735 | #ifdef _UTF8_RAW_NON_UTF8_SUPPORTED | ||
736 | | UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE | ||
737 | #else | ||
738 | | UTF_FLAG__TO_UTF8__SURROGATE_ERROR; | ||
739 | #endif | ||
740 | #endif | ||
741 | ; | ||
742 | |||
743 | void ConvertUnicodeToUTF8(const UString &src, AString &dest) | ||
744 | { | ||
745 | ConvertUnicodeToUTF8_Flags(src, dest, g_Unicode_To_UTF8_Flags); | ||
746 | } | ||
747 | |||
748 | void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest) | ||
749 | { | ||
750 | const unsigned flags = g_Unicode_To_UTF8_Flags; | ||
751 | dest.Free(); | ||
752 | const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags); | ||
753 | dest.Alloc(destLen); | ||
754 | const char *destEnd = Utf16_To_Utf8((char *)(void *)(Byte *)dest, src, src.Ptr(src.Len()), flags); | ||
755 | if (destLen != (size_t)(destEnd - (char *)(void *)(Byte *)dest)) | ||
756 | throw 202104; | ||
757 | } | ||
758 | |||
759 | /* | ||
760 | |||
761 | #ifndef _WIN32 | ||
762 | void Convert_UTF16_To_UTF32(const UString &src, UString &dest) | ||
763 | { | ||
764 | dest.Empty(); | ||
765 | for (size_t i = 0; i < src.Len();) | ||
766 | { | ||
767 | wchar_t c = src[i++]; | ||
768 | if (c >= 0xd800 && c < 0xdc00 && i < src.Len()) | ||
769 | { | ||
770 | const wchar_t c2 = src[i]; | ||
771 | if (c2 >= 0xdc00 && c2 < 0x10000) | ||
772 | { | ||
773 | // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2); | ||
774 | c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); | ||
775 | // printf("%4x\n", (int)c); | ||
776 | i++; | ||
777 | } | ||
778 | } | ||
779 | dest += c; | ||
780 | } | ||
781 | } | ||
782 | |||
783 | void Convert_UTF32_To_UTF16(const UString &src, UString &dest) | ||
784 | { | ||
785 | dest.Empty(); | ||
786 | for (size_t i = 0; i < src.Len();) | ||
787 | { | ||
788 | wchar_t w = src[i++]; | ||
789 | if (w >= 0x10000 && w < 0x110000) | ||
790 | { | ||
791 | w -= 0x10000; | ||
792 | dest += (wchar_t)((unsigned)0xd800 + (((unsigned)w >> 10) & 0x3ff)); | ||
793 | w = 0xdc00 + (w & 0x3ff); | ||
794 | } | ||
795 | dest += w; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | bool UTF32_IsThere_BigPoint(const UString &src) | ||
800 | { | ||
801 | for (size_t i = 0; i < src.Len();) | ||
802 | { | ||
803 | const UInt32 c = (UInt32)src[i++]; | ||
804 | if (c >= 0x110000) | ||
805 | return true; | ||
806 | } | ||
807 | return false; | ||
808 | } | ||
809 | |||
810 | bool Unicode_IsThere_BmpEscape(const UString &src) | ||
811 | { | ||
812 | for (size_t i = 0; i < src.Len();) | ||
813 | { | ||
814 | const UInt32 c = (UInt32)src[i++]; | ||
815 | if (IS_ESCAPE_POINT(c, 0)) | ||
816 | return true; | ||
817 | } | ||
818 | return false; | ||
819 | } | ||
820 | |||
821 | |||
822 | #endif | ||
823 | |||
824 | bool Unicode_IsThere_Utf16SurrogateError(const UString &src) | ||
825 | { | ||
826 | for (size_t i = 0; i < src.Len();) | ||
827 | { | ||
828 | const UInt32 val = (UInt32)src[i++]; | ||
829 | if (IS_SURROGATE_POINT(val)) | ||
830 | { | ||
831 | // it's hack to UTF-8 encoding | ||
832 | if (val >= 0xdc00 || i == src.Len()) | ||
833 | return true; | ||
834 | const UInt32 c2 = (UInt32)*src; | ||
835 | if (!IS_LOW_SURROGATE_POINT(c2)) | ||
836 | return true; | ||
837 | } | ||
838 | } | ||
839 | return false; | ||
840 | } | ||
841 | */ | ||
842 | |||
843 | #ifndef _WCHART_IS_16BIT | ||
844 | |||
845 | void Convert_UnicodeEsc16_To_UnicodeEscHigh | ||
846 | #if UTF_ESCAPE_PLANE == 0 | ||
847 | (UString &) {} | ||
848 | #else | ||
849 | (UString &s) | ||
850 | { | ||
851 | const unsigned len = s.Len(); | ||
852 | for (unsigned i = 0; i < len; i++) | ||
853 | { | ||
854 | wchar_t c = s[i]; | ||
855 | if (IS_ESCAPE_POINT(c, 0)) | ||
856 | { | ||
857 | c += UTF_ESCAPE_PLANE; | ||
858 | s.ReplaceOneCharAtPos(i, c); | ||
859 | } | ||
860 | } | ||
861 | } | ||
862 | #endif | ||
863 | #endif | ||
diff --git a/CPP/Common/UTFConvert.h b/CPP/Common/UTFConvert.h new file mode 100644 index 0000000..37c4975 --- /dev/null +++ b/CPP/Common/UTFConvert.h | |||
@@ -0,0 +1,384 @@ | |||
1 | // Common/UTFConvert.h | ||
2 | |||
3 | #ifndef __COMMON_UTF_CONVERT_H | ||
4 | #define __COMMON_UTF_CONVERT_H | ||
5 | |||
6 | #include "MyBuffer.h" | ||
7 | #include "MyString.h" | ||
8 | |||
9 | struct CUtf8Check | ||
10 | { | ||
11 | // Byte MaxByte; // in original src stream | ||
12 | bool NonUtf; | ||
13 | bool ZeroChar; | ||
14 | bool SingleSurrogate; | ||
15 | bool Escape; | ||
16 | bool Truncated; | ||
17 | UInt32 MaxHighPoint; // only for points >= 0x80 | ||
18 | |||
19 | CUtf8Check() { Clear(); } | ||
20 | |||
21 | void Clear() | ||
22 | { | ||
23 | // MaxByte = 0; | ||
24 | NonUtf = false; | ||
25 | ZeroChar = false; | ||
26 | SingleSurrogate = false; | ||
27 | Escape = false; | ||
28 | Truncated = false; | ||
29 | MaxHighPoint = 0; | ||
30 | } | ||
31 | |||
32 | void Update(const CUtf8Check &c) | ||
33 | { | ||
34 | if (c.NonUtf) NonUtf = true; | ||
35 | if (c.ZeroChar) ZeroChar = true; | ||
36 | if (c.SingleSurrogate) SingleSurrogate = true; | ||
37 | if (c.Escape) Escape = true; | ||
38 | if (c.Truncated) Truncated = true; | ||
39 | if (MaxHighPoint < c.MaxHighPoint) MaxHighPoint = c.MaxHighPoint; | ||
40 | } | ||
41 | |||
42 | void PrintStatus(AString &s) const | ||
43 | { | ||
44 | s.Empty(); | ||
45 | |||
46 | // s.Add_OptSpaced("MaxByte="); | ||
47 | // s.Add_UInt32(MaxByte); | ||
48 | |||
49 | if (NonUtf) s.Add_OptSpaced("non-UTF8"); | ||
50 | if (ZeroChar) s.Add_OptSpaced("ZeroChar"); | ||
51 | if (SingleSurrogate) s.Add_OptSpaced("SingleSurrogate"); | ||
52 | if (Escape) s.Add_OptSpaced("Escape"); | ||
53 | if (Truncated) s.Add_OptSpaced("Truncated"); | ||
54 | |||
55 | if (MaxHighPoint != 0) | ||
56 | { | ||
57 | s.Add_OptSpaced("MaxUnicode="); | ||
58 | s.Add_UInt32(MaxHighPoint); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | |||
63 | bool IsOK(bool allowReduced = false) const | ||
64 | { | ||
65 | if (NonUtf || SingleSurrogate || ZeroChar) | ||
66 | return false; | ||
67 | if (MaxHighPoint >= 0x110000) | ||
68 | return false; | ||
69 | if (Truncated && !allowReduced) | ||
70 | return false; | ||
71 | return true; | ||
72 | } | ||
73 | |||
74 | // it checks full buffer as specified in (size) and it doesn't stop on zero char | ||
75 | void Check_Buf(const char *src, size_t size) throw(); | ||
76 | |||
77 | void Check_AString(const AString &s) throw() | ||
78 | { | ||
79 | Check_Buf(s.Ptr(), s.Len()); | ||
80 | } | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | if (allowReduced == false) - all UTF-8 character sequences must be finished. | ||
85 | if (allowReduced == true) - it allows truncated last character-Utf8-sequence | ||
86 | */ | ||
87 | |||
88 | bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw(); | ||
89 | bool CheckUTF8_AString(const AString &s) throw(); | ||
90 | |||
91 | #define UTF_FLAG__FROM_UTF8__SURROGATE_ERROR (1 << 0) | ||
92 | #define UTF_FLAG__FROM_UTF8__USE_ESCAPE (1 << 1) | ||
93 | #define UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT (1 << 2) | ||
94 | |||
95 | /* | ||
96 | UTF_FLAG__FROM_UTF8__SURROGATE_ERROR | ||
97 | |||
98 | if (flag is NOT set) | ||
99 | { | ||
100 | it processes SINGLE-SURROGATE-8 as valid Unicode point. | ||
101 | it converts SINGLE-SURROGATE-8 to SINGLE-SURROGATE-16 | ||
102 | Note: some sequencies of two SINGLE-SURROGATE-8 points | ||
103 | will generate correct SURROGATE-16-PAIR, and | ||
104 | that SURROGATE-16-PAIR later will be converted to correct | ||
105 | UTF8-SURROGATE-21 point. So we don't restore original | ||
106 | STR-8 sequence in that case. | ||
107 | } | ||
108 | |||
109 | if (flag is set) | ||
110 | { | ||
111 | if (UTF_FLAG__FROM_UTF8__USE_ESCAPE is defined) | ||
112 | it generates ESCAPE for SINGLE-SURROGATE-8, | ||
113 | if (UTF_FLAG__FROM_UTF8__USE_ESCAPE is not defined) | ||
114 | it generates U+fffd for SINGLE-SURROGATE-8, | ||
115 | } | ||
116 | |||
117 | |||
118 | UTF_FLAG__FROM_UTF8__USE_ESCAPE | ||
119 | |||
120 | if (flag is NOT set) | ||
121 | it generates (U+fffd) code for non-UTF-8 (invalid) characters | ||
122 | |||
123 | if (flag is set) | ||
124 | { | ||
125 | It generates (ESCAPE) codes for NON-UTF-8 (invalid) characters. | ||
126 | And later we can restore original UTF-8-RAW characters from (ESCAPE-16-21) codes. | ||
127 | } | ||
128 | |||
129 | UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT | ||
130 | |||
131 | if (flag is NOT set) | ||
132 | { | ||
133 | it process ESCAPE-8 points as another Unicode points. | ||
134 | In Linux: ESCAPE-16 will mean two different ESCAPE-8 seqences, | ||
135 | so we need HIGH-ESCAPE-PLANE-21 to restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW | ||
136 | } | ||
137 | |||
138 | if (flag is set) | ||
139 | { | ||
140 | it generates ESCAPE-16-21 for ESCAPE-8 points | ||
141 | so we can restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW without HIGH-ESCAPE-PLANE-21. | ||
142 | } | ||
143 | |||
144 | |||
145 | Main USE CASES with UTF-8 <-> UTF-16 conversions: | ||
146 | |||
147 | WIN32: UTF-16-RAW -> UTF-8 (Archive) -> UTF-16-RAW | ||
148 | { | ||
149 | set UTF_FLAG__FROM_UTF8__USE_ESCAPE | ||
150 | Do NOT set UTF_FLAG__FROM_UTF8__SURROGATE_ERROR | ||
151 | Do NOT set UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT | ||
152 | |||
153 | So we restore original SINGLE-SURROGATE-16 from single SINGLE-SURROGATE-8. | ||
154 | } | ||
155 | |||
156 | Linux: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW | ||
157 | { | ||
158 | we want restore original UTF-8-RAW sequence later from that ESCAPE-16. | ||
159 | Set the flags: | ||
160 | UTF_FLAG__FROM_UTF8__SURROGATE_ERROR | ||
161 | UTF_FLAG__FROM_UTF8__USE_ESCAPE | ||
162 | UTF_FLAG__FROM_UTF8__BMP_ESCAPE_CONVERT | ||
163 | } | ||
164 | |||
165 | MacOS: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW | ||
166 | { | ||
167 | we want to restore correct UTF-8 without any BMP processing: | ||
168 | Set the flags: | ||
169 | UTF_FLAG__FROM_UTF8__SURROGATE_ERROR | ||
170 | UTF_FLAG__FROM_UTF8__USE_ESCAPE | ||
171 | } | ||
172 | |||
173 | */ | ||
174 | |||
175 | // zero char is not allowed in (src) buf | ||
176 | bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags = 0); | ||
177 | |||
178 | bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags = 0); | ||
179 | bool ConvertUTF8ToUnicode(const AString &src, UString &dest); | ||
180 | |||
181 | #define UTF_FLAG__TO_UTF8__SURROGATE_ERROR (1 << 8) | ||
182 | #define UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE (1 << 9) | ||
183 | // #define UTF_FLAG__TO_UTF8__PARSE_HIGH_ESCAPE (1 << 10) | ||
184 | |||
185 | /* | ||
186 | UTF_FLAG__TO_UTF8__SURROGATE_ERROR | ||
187 | |||
188 | if (flag is NOT set) | ||
189 | { | ||
190 | we extract SINGLE-SURROGATE as normal UTF-8 | ||
191 | |||
192 | In Windows : for UTF-16-RAW <-> UTF-8 (archive) <-> UTF-16-RAW in . | ||
193 | |||
194 | In Linux : | ||
195 | use-case-1: UTF-8 -> UTF-16 -> UTF-8 doesn't generate UTF-16 SINGLE-SURROGATE, | ||
196 | if (UTF_FLAG__FROM_UTF8__SURROGATE_ERROR) is used. | ||
197 | use-case 2: UTF-16-7z (with SINGLE-SURROGATE from Windows) -> UTF-8 (Linux) | ||
198 | will generate SINGLE-SURROGATE-UTF-8 here. | ||
199 | } | ||
200 | |||
201 | if (flag is set) | ||
202 | { | ||
203 | we generate UTF_REPLACEMENT_CHAR (0xfffd) for SINGLE_SURROGATE | ||
204 | it can be used for compatibility mode with WIN32 UTF function | ||
205 | or if we want UTF-8 stream without any errors | ||
206 | } | ||
207 | |||
208 | |||
209 | UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE | ||
210 | |||
211 | if (flag is NOT set) it doesn't extract raw 8-bit symbol from Escape-Plane-16 | ||
212 | if (flag is set) it extracts raw 8-bit symbol from Escape-Plane-16 | ||
213 | |||
214 | in Linux we need some way to extract NON-UTF8 RAW 8-bits from BMP (UTF-16 7z archive): | ||
215 | if (we use High-Escape-Plane), we can transfer BMP escapes to High-Escape-Plane. | ||
216 | if (we don't use High-Escape-Plane), we must use UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE. | ||
217 | |||
218 | |||
219 | UTF_FLAG__TO_UTF8__PARSE_HIGH_ESCAPE | ||
220 | // that flag affects the code only if (wchar_t is 32-bit) | ||
221 | // that mode with high-escape can be disabled now in UTFConvert.cpp | ||
222 | if (flag is NOT set) | ||
223 | it doesn't extract raw 8-bit symbol from High-Escape-Plane | ||
224 | if (flag is set) | ||
225 | it extracts raw 8-bit symbol from High-Escape-Plane | ||
226 | |||
227 | Main use cases: | ||
228 | |||
229 | WIN32 : UTF-16-RAW -> UTF-8 (archive) -> UTF-16-RAW | ||
230 | { | ||
231 | Do NOT set UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE. | ||
232 | Do NOT set UTF_FLAG__TO_UTF8__SURROGATE_ERROR. | ||
233 | So we restore original UTF-16-RAW. | ||
234 | } | ||
235 | |||
236 | Linix : UTF-8 with Escapes -> UTF-16 (7z archive) -> UTF-8 with Escapes | ||
237 | set UTF_FLAG__TO_UTF8__EXTRACT_BMP_ESCAPE to extract non-UTF from 7z archive | ||
238 | set UTF_FLAG__TO_UTF8__PARSE_HIGH_ESCAPE for intermediate UTF-16. | ||
239 | Note: high esacape mode can be ignored now in UTFConvert.cpp | ||
240 | |||
241 | macOS: | ||
242 | the system doesn't support incorrect UTF-8 in file names. | ||
243 | set UTF_FLAG__TO_UTF8__SURROGATE_ERROR | ||
244 | */ | ||
245 | |||
246 | extern unsigned g_Unicode_To_UTF8_Flags; | ||
247 | |||
248 | void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags = 0); | ||
249 | void ConvertUnicodeToUTF8(const UString &src, AString &dest); | ||
250 | |||
251 | void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest); | ||
252 | |||
253 | /* | ||
254 | #ifndef _WIN32 | ||
255 | void Convert_UTF16_To_UTF32(const UString &src, UString &dest); | ||
256 | void Convert_UTF32_To_UTF16(const UString &src, UString &dest); | ||
257 | bool UTF32_IsThere_BigPoint(const UString &src); | ||
258 | bool Unicode_IsThere_BmpEscape(const UString &src); | ||
259 | #endif | ||
260 | |||
261 | bool Unicode_IsThere_Utf16SurrogateError(const UString &src); | ||
262 | */ | ||
263 | |||
264 | #ifdef _WCHART_IS_16BIT | ||
265 | #define Convert_UnicodeEsc16_To_UnicodeEscHigh(s) | ||
266 | #else | ||
267 | void Convert_UnicodeEsc16_To_UnicodeEscHigh(UString &s); | ||
268 | #endif | ||
269 | |||
270 | /* | ||
271 | // #include "../../C/CpuArch.h" | ||
272 | |||
273 | // ---------- Utf16 Little endian functions ---------- | ||
274 | |||
275 | // We store 16-bit surrogates even in 32-bit WCHARs in Linux. | ||
276 | // So now we don't use the following code: | ||
277 | |||
278 | #if WCHAR_MAX > 0xffff | ||
279 | |||
280 | // void *p : pointer to src bytes stream | ||
281 | // size_t len : num Utf16 characters : it can include or not include NULL character | ||
282 | |||
283 | inline size_t Utf16LE__Get_Num_WCHARs(const void *p, size_t len) | ||
284 | { | ||
285 | #if WCHAR_MAX > 0xffff | ||
286 | size_t num_wchars = 0; | ||
287 | for (size_t i = 0; i < len; i++) | ||
288 | { | ||
289 | wchar_t c = GetUi16(p); | ||
290 | p = (const void *)((const Byte *)p + 2); | ||
291 | if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) | ||
292 | { | ||
293 | wchar_t c2 = GetUi16(p); | ||
294 | if (c2 >= 0xdc00 && c2 < 0xe000) | ||
295 | { | ||
296 | c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); | ||
297 | p = (const void *)((const Byte *)p + 2); | ||
298 | i++; | ||
299 | } | ||
300 | } | ||
301 | num_wchars++; | ||
302 | } | ||
303 | return num_wchars; | ||
304 | #else | ||
305 | UNUSED_VAR(p) | ||
306 | return len; | ||
307 | #endif | ||
308 | } | ||
309 | |||
310 | // #include <stdio.h> | ||
311 | |||
312 | inline wchar_t *Utf16LE__To_WCHARs_Sep(const void *p, size_t len, wchar_t *dest) | ||
313 | { | ||
314 | for (size_t i = 0; i < len; i++) | ||
315 | { | ||
316 | wchar_t c = GetUi16(p); | ||
317 | p = (const void *)((const Byte *)p + 2); | ||
318 | |||
319 | #if WCHAR_PATH_SEPARATOR != L'/' | ||
320 | if (c == L'/') | ||
321 | c = WCHAR_PATH_SEPARATOR; | ||
322 | #endif | ||
323 | |||
324 | #if WCHAR_MAX > 0xffff | ||
325 | |||
326 | if (c >= 0xd800 && c < 0xdc00 && i + 1 != len) | ||
327 | { | ||
328 | wchar_t c2 = GetUi16(p); | ||
329 | if (c2 >= 0xdc00 && c2 < 0xe000) | ||
330 | { | ||
331 | // printf("\nSurragate : %4x %4x -> ", (int)c, (int)c2); | ||
332 | c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff); | ||
333 | p = (const void *)((const Byte *)p + 2); | ||
334 | i++; | ||
335 | // printf("%4x\n", (int)c); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | #endif | ||
340 | |||
341 | *dest++ = c; | ||
342 | } | ||
343 | return dest; | ||
344 | } | ||
345 | |||
346 | |||
347 | inline size_t Get_Num_Utf16_chars_from_wchar_string(const wchar_t *p) | ||
348 | { | ||
349 | size_t num = 0; | ||
350 | for (;;) | ||
351 | { | ||
352 | wchar_t c = *p++; | ||
353 | if (c == 0) | ||
354 | return num; | ||
355 | num += ((c >= 0x10000 && c < 0x110000) ? 2 : 1); | ||
356 | } | ||
357 | return num; | ||
358 | } | ||
359 | |||
360 | inline Byte *wchars_to_Utf16LE(const wchar_t *p, Byte *dest) | ||
361 | { | ||
362 | for (;;) | ||
363 | { | ||
364 | wchar_t c = *p++; | ||
365 | if (c == 0) | ||
366 | return dest; | ||
367 | if (c >= 0x10000 && c < 0x110000) | ||
368 | { | ||
369 | SetUi16(dest , (UInt16)(0xd800 + ((c >> 10) & 0x3FF))); | ||
370 | SetUi16(dest + 2, (UInt16)(0xdc00 + ( c & 0x3FF))); | ||
371 | dest += 4; | ||
372 | } | ||
373 | else | ||
374 | { | ||
375 | SetUi16(dest, c); | ||
376 | dest += 2; | ||
377 | } | ||
378 | } | ||
379 | } | ||
380 | |||
381 | #endif | ||
382 | */ | ||
383 | |||
384 | #endif | ||
diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp new file mode 100644 index 0000000..861f3f7 --- /dev/null +++ b/CPP/Common/Wildcard.cpp | |||
@@ -0,0 +1,790 @@ | |||
1 | // Common/Wildcard.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "Wildcard.h" | ||
6 | |||
7 | extern | ||
8 | bool g_CaseSensitive; | ||
9 | bool g_CaseSensitive = | ||
10 | #ifdef _WIN32 | ||
11 | false; | ||
12 | #elif defined (__APPLE__) | ||
13 | #ifdef TARGET_OS_IPHONE | ||
14 | true; | ||
15 | #else | ||
16 | false; | ||
17 | #endif | ||
18 | #else | ||
19 | true; | ||
20 | #endif | ||
21 | |||
22 | |||
23 | bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2) | ||
24 | { | ||
25 | if (g_CaseSensitive) | ||
26 | return IsString1PrefixedByString2(s1, s2); | ||
27 | return IsString1PrefixedByString2_NoCase(s1, s2); | ||
28 | } | ||
29 | |||
30 | // #include <stdio.h> | ||
31 | |||
32 | /* | ||
33 | static int MyStringCompare_PathLinux(const wchar_t *s1, const wchar_t *s2) throw() | ||
34 | { | ||
35 | for (;;) | ||
36 | { | ||
37 | wchar_t c1 = *s1++; | ||
38 | wchar_t c2 = *s2++; | ||
39 | if (c1 != c2) | ||
40 | { | ||
41 | if (c1 == 0) return -1; | ||
42 | if (c2 == 0) return 1; | ||
43 | if (c1 == '/') c1 = 0; | ||
44 | if (c2 == '/') c2 = 0; | ||
45 | if (c1 < c2) return -1; | ||
46 | if (c1 > c2) return 1; | ||
47 | continue; | ||
48 | } | ||
49 | if (c1 == 0) return 0; | ||
50 | } | ||
51 | } | ||
52 | */ | ||
53 | |||
54 | static int MyStringCompare_Path(const wchar_t *s1, const wchar_t *s2) throw() | ||
55 | { | ||
56 | for (;;) | ||
57 | { | ||
58 | wchar_t c1 = *s1++; | ||
59 | wchar_t c2 = *s2++; | ||
60 | if (c1 != c2) | ||
61 | { | ||
62 | if (c1 == 0) return -1; | ||
63 | if (c2 == 0) return 1; | ||
64 | if (IS_PATH_SEPAR(c1)) c1 = 0; | ||
65 | if (IS_PATH_SEPAR(c2)) c2 = 0; | ||
66 | if (c1 < c2) return -1; | ||
67 | if (c1 > c2) return 1; | ||
68 | continue; | ||
69 | } | ||
70 | if (c1 == 0) return 0; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | static int MyStringCompareNoCase_Path(const wchar_t *s1, const wchar_t *s2) throw() | ||
75 | { | ||
76 | for (;;) | ||
77 | { | ||
78 | wchar_t c1 = *s1++; | ||
79 | wchar_t c2 = *s2++; | ||
80 | if (c1 != c2) | ||
81 | { | ||
82 | if (c1 == 0) return -1; | ||
83 | if (c2 == 0) return 1; | ||
84 | if (IS_PATH_SEPAR(c1)) c1 = 0; | ||
85 | if (IS_PATH_SEPAR(c2)) c2 = 0; | ||
86 | c1 = MyCharUpper(c1); | ||
87 | c2 = MyCharUpper(c2); | ||
88 | if (c1 < c2) return -1; | ||
89 | if (c1 > c2) return 1; | ||
90 | continue; | ||
91 | } | ||
92 | if (c1 == 0) return 0; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW | ||
97 | { | ||
98 | /* | ||
99 | printf("\nCompareFileNames"); | ||
100 | printf("\n S1: %ls", s1); | ||
101 | printf("\n S2: %ls", s2); | ||
102 | printf("\n"); | ||
103 | */ | ||
104 | // 21.07 : we parse PATH_SEPARATOR so: 0 < PATH_SEPARATOR < 1 | ||
105 | if (g_CaseSensitive) | ||
106 | return MyStringCompare_Path(s1, s2); | ||
107 | return MyStringCompareNoCase_Path(s1, s2); | ||
108 | } | ||
109 | |||
110 | #ifndef USE_UNICODE_FSTRING | ||
111 | int CompareFileNames(const char *s1, const char *s2) | ||
112 | { | ||
113 | const UString u1 = fs2us(s1); | ||
114 | const UString u2 = fs2us(s2); | ||
115 | return CompareFileNames(u1, u2); | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | // ----------------------------------------- | ||
120 | // this function compares name with mask | ||
121 | // ? - any char | ||
122 | // * - any char or empty | ||
123 | |||
124 | static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name) | ||
125 | { | ||
126 | for (;;) | ||
127 | { | ||
128 | wchar_t m = *mask; | ||
129 | wchar_t c = *name; | ||
130 | if (m == 0) | ||
131 | return (c == 0); | ||
132 | if (m == '*') | ||
133 | { | ||
134 | if (EnhancedMaskTest(mask + 1, name)) | ||
135 | return true; | ||
136 | if (c == 0) | ||
137 | return false; | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | if (m == '?') | ||
142 | { | ||
143 | if (c == 0) | ||
144 | return false; | ||
145 | } | ||
146 | else if (m != c) | ||
147 | if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c)) | ||
148 | return false; | ||
149 | mask++; | ||
150 | } | ||
151 | name++; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // -------------------------------------------------- | ||
156 | // Splits path to strings | ||
157 | |||
158 | void SplitPathToParts(const UString &path, UStringVector &pathParts) | ||
159 | { | ||
160 | pathParts.Clear(); | ||
161 | unsigned len = path.Len(); | ||
162 | if (len == 0) | ||
163 | return; | ||
164 | UString name; | ||
165 | unsigned prev = 0; | ||
166 | for (unsigned i = 0; i < len; i++) | ||
167 | if (IsPathSepar(path[i])) | ||
168 | { | ||
169 | name.SetFrom(path.Ptr(prev), i - prev); | ||
170 | pathParts.Add(name); | ||
171 | prev = i + 1; | ||
172 | } | ||
173 | name.SetFrom(path.Ptr(prev), len - prev); | ||
174 | pathParts.Add(name); | ||
175 | } | ||
176 | |||
177 | void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name) | ||
178 | { | ||
179 | const wchar_t *start = path; | ||
180 | const wchar_t *p = start + path.Len(); | ||
181 | for (; p != start; p--) | ||
182 | if (IsPathSepar(*(p - 1))) | ||
183 | break; | ||
184 | dirPrefix.SetFrom(path, (unsigned)(p - start)); | ||
185 | name = p; | ||
186 | } | ||
187 | |||
188 | void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name) | ||
189 | { | ||
190 | const wchar_t *start = path; | ||
191 | const wchar_t *p = start + path.Len(); | ||
192 | if (p != start) | ||
193 | { | ||
194 | if (IsPathSepar(*(p - 1))) | ||
195 | p--; | ||
196 | for (; p != start; p--) | ||
197 | if (IsPathSepar(*(p - 1))) | ||
198 | break; | ||
199 | } | ||
200 | dirPrefix.SetFrom(path, (unsigned)(p - start)); | ||
201 | name = p; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | UString ExtractDirPrefixFromPath(const UString &path) | ||
206 | { | ||
207 | return path.Left(path.ReverseFind_PathSepar() + 1)); | ||
208 | } | ||
209 | */ | ||
210 | |||
211 | UString ExtractFileNameFromPath(const UString &path) | ||
212 | { | ||
213 | return UString(path.Ptr((unsigned)(path.ReverseFind_PathSepar() + 1))); | ||
214 | } | ||
215 | |||
216 | |||
217 | bool DoesWildcardMatchName(const UString &mask, const UString &name) | ||
218 | { | ||
219 | return EnhancedMaskTest(mask, name); | ||
220 | } | ||
221 | |||
222 | bool DoesNameContainWildcard(const UString &path) | ||
223 | { | ||
224 | for (unsigned i = 0; i < path.Len(); i++) | ||
225 | { | ||
226 | wchar_t c = path[i]; | ||
227 | if (c == '*' || c == '?') | ||
228 | return true; | ||
229 | } | ||
230 | return false; | ||
231 | } | ||
232 | |||
233 | |||
234 | // ----------------------------------------------------------' | ||
235 | // NWildcard | ||
236 | |||
237 | namespace NWildcard { | ||
238 | |||
239 | /* | ||
240 | |||
241 | M = MaskParts.Size(); | ||
242 | N = TestNameParts.Size(); | ||
243 | |||
244 | File Dir | ||
245 | ForFile rec M<=N [N-M, N) - | ||
246 | !ForDir nonrec M=N [0, M) - | ||
247 | |||
248 | ForDir rec M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File | ||
249 | !ForFile nonrec [0, M) same as ForBoth-File | ||
250 | |||
251 | ForFile rec m<=N [0, M) ... [N-M, N) same as ForBoth-File | ||
252 | ForDir nonrec [0, M) same as ForBoth-File | ||
253 | |||
254 | */ | ||
255 | |||
256 | bool CItem::AreAllAllowed() const | ||
257 | { | ||
258 | return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*"; | ||
259 | } | ||
260 | |||
261 | bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const | ||
262 | { | ||
263 | if (!isFile && !ForDir) | ||
264 | return false; | ||
265 | |||
266 | /* | ||
267 | if (PathParts.IsEmpty()) | ||
268 | { | ||
269 | // PathParts.IsEmpty() means all items (universal wildcard) | ||
270 | if (!isFile) | ||
271 | return true; | ||
272 | if (pathParts.Size() <= 1) | ||
273 | return ForFile; | ||
274 | return (ForDir || Recursive && ForFile); | ||
275 | } | ||
276 | */ | ||
277 | |||
278 | int delta = (int)pathParts.Size() - (int)PathParts.Size(); | ||
279 | if (delta < 0) | ||
280 | return false; | ||
281 | int start = 0; | ||
282 | int finish = 0; | ||
283 | |||
284 | if (isFile) | ||
285 | { | ||
286 | if (!ForDir) | ||
287 | { | ||
288 | if (Recursive) | ||
289 | start = delta; | ||
290 | else if (delta !=0) | ||
291 | return false; | ||
292 | } | ||
293 | if (!ForFile && delta == 0) | ||
294 | return false; | ||
295 | } | ||
296 | |||
297 | if (Recursive) | ||
298 | { | ||
299 | finish = delta; | ||
300 | if (isFile && !ForFile) | ||
301 | finish = delta - 1; | ||
302 | } | ||
303 | |||
304 | for (int d = start; d <= finish; d++) | ||
305 | { | ||
306 | unsigned i; | ||
307 | for (i = 0; i < PathParts.Size(); i++) | ||
308 | { | ||
309 | if (WildcardMatching) | ||
310 | { | ||
311 | if (!DoesWildcardMatchName(PathParts[i], pathParts[i + (unsigned)d])) | ||
312 | break; | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | if (CompareFileNames(PathParts[i], pathParts[i + (unsigned)d]) != 0) | ||
317 | break; | ||
318 | } | ||
319 | } | ||
320 | if (i == PathParts.Size()) | ||
321 | return true; | ||
322 | } | ||
323 | return false; | ||
324 | } | ||
325 | |||
326 | bool CCensorNode::AreAllAllowed() const | ||
327 | { | ||
328 | if (!Name.IsEmpty() || | ||
329 | !SubNodes.IsEmpty() || | ||
330 | !ExcludeItems.IsEmpty() || | ||
331 | IncludeItems.Size() != 1) | ||
332 | return false; | ||
333 | return IncludeItems.Front().AreAllAllowed(); | ||
334 | } | ||
335 | |||
336 | int CCensorNode::FindSubNode(const UString &name) const | ||
337 | { | ||
338 | FOR_VECTOR (i, SubNodes) | ||
339 | if (CompareFileNames(SubNodes[i].Name, name) == 0) | ||
340 | return (int)i; | ||
341 | return -1; | ||
342 | } | ||
343 | |||
344 | void CCensorNode::AddItemSimple(bool include, CItem &item) | ||
345 | { | ||
346 | CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems; | ||
347 | items.Add(item); | ||
348 | } | ||
349 | |||
350 | void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex) | ||
351 | { | ||
352 | if (item.PathParts.Size() <= 1) | ||
353 | { | ||
354 | if (item.PathParts.Size() != 0 && item.WildcardMatching) | ||
355 | { | ||
356 | if (!DoesNameContainWildcard(item.PathParts.Front())) | ||
357 | item.WildcardMatching = false; | ||
358 | } | ||
359 | AddItemSimple(include, item); | ||
360 | return; | ||
361 | } | ||
362 | |||
363 | const UString &front = item.PathParts.Front(); | ||
364 | |||
365 | // WIN32 doesn't support wildcards in file names | ||
366 | if (item.WildcardMatching | ||
367 | && ignoreWildcardIndex != 0 | ||
368 | && DoesNameContainWildcard(front)) | ||
369 | { | ||
370 | AddItemSimple(include, item); | ||
371 | return; | ||
372 | } | ||
373 | CCensorNode &subNode = Find_SubNode_Or_Add_New(front); | ||
374 | item.PathParts.Delete(0); | ||
375 | subNode.AddItem(include, item, ignoreWildcardIndex - 1); | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | void CCensorNode::AddItem(bool include, const UString &path, const CCensorPathProps &props) | ||
380 | { | ||
381 | CItem item; | ||
382 | SplitPathToParts(path, item.PathParts); | ||
383 | item.Recursive = props.Recursive; | ||
384 | item.ForFile = props.ForFile; | ||
385 | item.ForDir = props.ForDir; | ||
386 | item.WildcardMatching = props.WildcardMatching; | ||
387 | AddItem(include, item); | ||
388 | } | ||
389 | */ | ||
390 | |||
391 | bool CCensorNode::NeedCheckSubDirs() const | ||
392 | { | ||
393 | FOR_VECTOR (i, IncludeItems) | ||
394 | { | ||
395 | const CItem &item = IncludeItems[i]; | ||
396 | if (item.Recursive || item.PathParts.Size() > 1) | ||
397 | return true; | ||
398 | } | ||
399 | return false; | ||
400 | } | ||
401 | |||
402 | bool CCensorNode::AreThereIncludeItems() const | ||
403 | { | ||
404 | if (IncludeItems.Size() > 0) | ||
405 | return true; | ||
406 | FOR_VECTOR (i, SubNodes) | ||
407 | if (SubNodes[i].AreThereIncludeItems()) | ||
408 | return true; | ||
409 | return false; | ||
410 | } | ||
411 | |||
412 | bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const | ||
413 | { | ||
414 | const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems; | ||
415 | FOR_VECTOR (i, items) | ||
416 | if (items[i].CheckPath(pathParts, isFile)) | ||
417 | return true; | ||
418 | return false; | ||
419 | } | ||
420 | |||
421 | bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const | ||
422 | { | ||
423 | if (CheckPathCurrent(false, pathParts, isFile)) | ||
424 | { | ||
425 | include = false; | ||
426 | return true; | ||
427 | } | ||
428 | if (pathParts.Size() > 1) | ||
429 | { | ||
430 | int index = FindSubNode(pathParts.Front()); | ||
431 | if (index >= 0) | ||
432 | { | ||
433 | UStringVector pathParts2 = pathParts; | ||
434 | pathParts2.Delete(0); | ||
435 | if (SubNodes[(unsigned)index].CheckPathVect(pathParts2, isFile, include)) | ||
436 | return true; | ||
437 | } | ||
438 | } | ||
439 | bool finded = CheckPathCurrent(true, pathParts, isFile); | ||
440 | include = finded; // if (!finded), then (true) is allowed also | ||
441 | return finded; | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const | ||
446 | { | ||
447 | UStringVector pathParts; | ||
448 | SplitPathToParts(path, pathParts); | ||
449 | if (CheckPathVect(pathParts, isFile, include)) | ||
450 | { | ||
451 | if (!include || !isAltStream) | ||
452 | return true; | ||
453 | } | ||
454 | if (isAltStream && !pathParts.IsEmpty()) | ||
455 | { | ||
456 | UString &back = pathParts.Back(); | ||
457 | int pos = back.Find(L':'); | ||
458 | if (pos > 0) | ||
459 | { | ||
460 | back.DeleteFrom(pos); | ||
461 | return CheckPathVect(pathParts, isFile, include); | ||
462 | } | ||
463 | } | ||
464 | return false; | ||
465 | } | ||
466 | |||
467 | bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const | ||
468 | { | ||
469 | bool include; | ||
470 | if (CheckPath2(isAltStream, path, isFile, include)) | ||
471 | return include; | ||
472 | return false; | ||
473 | } | ||
474 | */ | ||
475 | |||
476 | bool CCensorNode::CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const | ||
477 | { | ||
478 | if (CheckPathCurrent(include, pathParts, isFile)) | ||
479 | return true; | ||
480 | if (!Parent) | ||
481 | return false; | ||
482 | pathParts.Insert(0, Name); | ||
483 | return Parent->CheckPathToRoot_Change(include, pathParts, isFile); | ||
484 | } | ||
485 | |||
486 | bool CCensorNode::CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const | ||
487 | { | ||
488 | if (CheckPathCurrent(include, pathParts, isFile)) | ||
489 | return true; | ||
490 | if (!Parent) | ||
491 | return false; | ||
492 | UStringVector pathParts2; | ||
493 | pathParts2.Add(Name); | ||
494 | pathParts2 += pathParts; | ||
495 | return Parent->CheckPathToRoot_Change(include, pathParts2, isFile); | ||
496 | } | ||
497 | |||
498 | /* | ||
499 | bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const | ||
500 | { | ||
501 | UStringVector pathParts; | ||
502 | SplitPathToParts(path, pathParts); | ||
503 | return CheckPathToRoot(include, pathParts, isFile); | ||
504 | } | ||
505 | */ | ||
506 | |||
507 | void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) | ||
508 | { | ||
509 | ExcludeItems += fromNodes.ExcludeItems; | ||
510 | FOR_VECTOR (i, fromNodes.SubNodes) | ||
511 | { | ||
512 | const CCensorNode &node = fromNodes.SubNodes[i]; | ||
513 | Find_SubNode_Or_Add_New(node.Name).ExtendExclude(node); | ||
514 | } | ||
515 | } | ||
516 | |||
517 | int CCensor::FindPairForPrefix(const UString &prefix) const | ||
518 | { | ||
519 | FOR_VECTOR (i, Pairs) | ||
520 | if (CompareFileNames(Pairs[i].Prefix, prefix) == 0) | ||
521 | return (int)i; | ||
522 | return -1; | ||
523 | } | ||
524 | |||
525 | #ifdef _WIN32 | ||
526 | |||
527 | bool IsDriveColonName(const wchar_t *s) | ||
528 | { | ||
529 | wchar_t c = s[0]; | ||
530 | return c != 0 | ||
531 | && s[1] == ':' | ||
532 | && s[2] == 0 | ||
533 | && ((c >= 'a' && c <= 'z') | ||
534 | || (c >= 'A' && c <= 'Z')); | ||
535 | } | ||
536 | |||
537 | unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts) | ||
538 | { | ||
539 | if (pathParts.IsEmpty()) | ||
540 | return 0; | ||
541 | |||
542 | unsigned testIndex = 0; | ||
543 | if (pathParts[0].IsEmpty()) | ||
544 | { | ||
545 | if (pathParts.Size() < 4 | ||
546 | || !pathParts[1].IsEmpty() | ||
547 | || pathParts[2] != L"?") | ||
548 | return 0; | ||
549 | testIndex = 3; | ||
550 | } | ||
551 | if (NWildcard::IsDriveColonName(pathParts[testIndex])) | ||
552 | return testIndex + 1; | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | #endif | ||
557 | |||
558 | static unsigned GetNumPrefixParts(const UStringVector &pathParts) | ||
559 | { | ||
560 | if (pathParts.IsEmpty()) | ||
561 | return 0; | ||
562 | |||
563 | /* empty last part could be removed already from (pathParts), | ||
564 | if there was tail path separator (slash) in original full path string. */ | ||
565 | |||
566 | #ifdef _WIN32 | ||
567 | |||
568 | if (IsDriveColonName(pathParts[0])) | ||
569 | return 1; | ||
570 | if (!pathParts[0].IsEmpty()) | ||
571 | return 0; | ||
572 | |||
573 | if (pathParts.Size() == 1) | ||
574 | return 1; | ||
575 | if (!pathParts[1].IsEmpty()) | ||
576 | return 1; | ||
577 | if (pathParts.Size() == 2) | ||
578 | return 2; | ||
579 | if (pathParts[2] == L".") | ||
580 | return 3; | ||
581 | |||
582 | unsigned networkParts = 2; | ||
583 | if (pathParts[2] == L"?") | ||
584 | { | ||
585 | if (pathParts.Size() == 3) | ||
586 | return 3; | ||
587 | if (IsDriveColonName(pathParts[3])) | ||
588 | return 4; | ||
589 | if (!pathParts[3].IsEqualTo_Ascii_NoCase("UNC")) | ||
590 | return 3; | ||
591 | networkParts = 4; | ||
592 | } | ||
593 | |||
594 | networkParts += | ||
595 | // 2; // server/share | ||
596 | 1; // server | ||
597 | if (pathParts.Size() <= networkParts) | ||
598 | return pathParts.Size(); | ||
599 | return networkParts; | ||
600 | |||
601 | #else | ||
602 | |||
603 | return pathParts[0].IsEmpty() ? 1 : 0; | ||
604 | |||
605 | #endif | ||
606 | } | ||
607 | |||
608 | void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, | ||
609 | const CCensorPathProps &props) | ||
610 | { | ||
611 | if (path.IsEmpty()) | ||
612 | throw "Empty file path"; | ||
613 | |||
614 | UStringVector pathParts; | ||
615 | SplitPathToParts(path, pathParts); | ||
616 | |||
617 | CCensorPathProps props2 = props; | ||
618 | |||
619 | bool forFile = true; | ||
620 | bool forDir = true; | ||
621 | const UString &back = pathParts.Back(); | ||
622 | if (back.IsEmpty()) | ||
623 | { | ||
624 | // we have tail path separator. So it's directory. | ||
625 | // we delete tail path separator here even for "\" and "c:\" | ||
626 | forFile = false; | ||
627 | pathParts.DeleteBack(); | ||
628 | } | ||
629 | else | ||
630 | { | ||
631 | if (props.MarkMode == kMark_StrictFile | ||
632 | || (props.MarkMode == kMark_StrictFile_IfWildcard | ||
633 | && DoesNameContainWildcard(back))) | ||
634 | forDir = false; | ||
635 | } | ||
636 | |||
637 | |||
638 | UString prefix; | ||
639 | |||
640 | int ignoreWildcardIndex = -1; | ||
641 | |||
642 | // #ifdef _WIN32 | ||
643 | // we ignore "?" wildcard in "\\?\" prefix. | ||
644 | if (pathParts.Size() >= 3 | ||
645 | && pathParts[0].IsEmpty() | ||
646 | && pathParts[1].IsEmpty() | ||
647 | && pathParts[2] == L"?") | ||
648 | ignoreWildcardIndex = 2; | ||
649 | // #endif | ||
650 | |||
651 | if (pathMode != k_AbsPath) | ||
652 | { | ||
653 | // detection of the number of Skip Parts for prefix | ||
654 | ignoreWildcardIndex = -1; | ||
655 | |||
656 | const unsigned numPrefixParts = GetNumPrefixParts(pathParts); | ||
657 | unsigned numSkipParts = numPrefixParts; | ||
658 | |||
659 | if (pathMode != k_FullPath) | ||
660 | { | ||
661 | // if absolute path, then all parts before last part will be in prefix | ||
662 | if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts) | ||
663 | numSkipParts = pathParts.Size() - 1; | ||
664 | } | ||
665 | { | ||
666 | int dotsIndex = -1; | ||
667 | for (unsigned i = numPrefixParts; i < pathParts.Size(); i++) | ||
668 | { | ||
669 | const UString &part = pathParts[i]; | ||
670 | if (part == L".." || part == L".") | ||
671 | dotsIndex = (int)i; | ||
672 | } | ||
673 | |||
674 | if (dotsIndex >= 0) | ||
675 | { | ||
676 | if (dotsIndex == (int)pathParts.Size() - 1) | ||
677 | numSkipParts = pathParts.Size(); | ||
678 | else | ||
679 | numSkipParts = pathParts.Size() - 1; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | // we split (pathParts) to (prefix) and (pathParts). | ||
684 | for (unsigned i = 0; i < numSkipParts; i++) | ||
685 | { | ||
686 | { | ||
687 | const UString &front = pathParts.Front(); | ||
688 | // WIN32 doesn't support wildcards in file names | ||
689 | if (props.WildcardMatching) | ||
690 | if (i >= numPrefixParts && DoesNameContainWildcard(front)) | ||
691 | break; | ||
692 | prefix += front; | ||
693 | prefix.Add_PathSepar(); | ||
694 | } | ||
695 | pathParts.Delete(0); | ||
696 | } | ||
697 | } | ||
698 | |||
699 | int index = FindPairForPrefix(prefix); | ||
700 | if (index < 0) | ||
701 | { | ||
702 | index = (int)Pairs.Size(); | ||
703 | Pairs.AddNew().Prefix = prefix; | ||
704 | } | ||
705 | |||
706 | if (pathMode != k_AbsPath) | ||
707 | { | ||
708 | if (pathParts.IsEmpty() || (pathParts.Size() == 1 && pathParts[0].IsEmpty())) | ||
709 | { | ||
710 | // we create universal item, if we skip all parts as prefix (like \ or L:\ ) | ||
711 | pathParts.Clear(); | ||
712 | pathParts.Add(UString("*")); | ||
713 | forFile = true; | ||
714 | forDir = true; | ||
715 | props2.WildcardMatching = true; | ||
716 | props2.Recursive = false; | ||
717 | } | ||
718 | } | ||
719 | |||
720 | /* | ||
721 | // not possible now | ||
722 | if (!forDir && !forFile) | ||
723 | { | ||
724 | UString s ("file path was blocked for files and directories: "); | ||
725 | s += path; | ||
726 | throw s; | ||
727 | // return; // for debug : ignore item (don't create Item) | ||
728 | } | ||
729 | */ | ||
730 | |||
731 | CItem item; | ||
732 | item.PathParts = pathParts; | ||
733 | item.ForDir = forDir; | ||
734 | item.ForFile = forFile; | ||
735 | item.Recursive = props2.Recursive; | ||
736 | item.WildcardMatching = props2.WildcardMatching; | ||
737 | Pairs[(unsigned)index].Head.AddItem(include, item, ignoreWildcardIndex); | ||
738 | } | ||
739 | |||
740 | /* | ||
741 | bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const | ||
742 | { | ||
743 | bool finded = false; | ||
744 | FOR_VECTOR (i, Pairs) | ||
745 | { | ||
746 | bool include; | ||
747 | if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include)) | ||
748 | { | ||
749 | if (!include) | ||
750 | return false; | ||
751 | finded = true; | ||
752 | } | ||
753 | } | ||
754 | return finded; | ||
755 | } | ||
756 | */ | ||
757 | |||
758 | void CCensor::ExtendExclude() | ||
759 | { | ||
760 | unsigned i; | ||
761 | for (i = 0; i < Pairs.Size(); i++) | ||
762 | if (Pairs[i].Prefix.IsEmpty()) | ||
763 | break; | ||
764 | if (i == Pairs.Size()) | ||
765 | return; | ||
766 | unsigned index = i; | ||
767 | for (i = 0; i < Pairs.Size(); i++) | ||
768 | if (index != i) | ||
769 | Pairs[i].Head.ExtendExclude(Pairs[index].Head); | ||
770 | } | ||
771 | |||
772 | void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode) | ||
773 | { | ||
774 | FOR_VECTOR(i, CensorPaths) | ||
775 | { | ||
776 | const CCensorPath &cp = CensorPaths[i]; | ||
777 | AddItem(censorPathMode, cp.Include, cp.Path, cp.Props); | ||
778 | } | ||
779 | CensorPaths.Clear(); | ||
780 | } | ||
781 | |||
782 | void CCensor::AddPreItem(bool include, const UString &path, const CCensorPathProps &props) | ||
783 | { | ||
784 | CCensorPath &cp = CensorPaths.AddNew(); | ||
785 | cp.Path = path; | ||
786 | cp.Include = include; | ||
787 | cp.Props = props; | ||
788 | } | ||
789 | |||
790 | } | ||
diff --git a/CPP/Common/Wildcard.h b/CPP/Common/Wildcard.h new file mode 100644 index 0000000..0fa4887 --- /dev/null +++ b/CPP/Common/Wildcard.h | |||
@@ -0,0 +1,231 @@ | |||
1 | // Common/Wildcard.h | ||
2 | |||
3 | #ifndef __COMMON_WILDCARD_H | ||
4 | #define __COMMON_WILDCARD_H | ||
5 | |||
6 | #include "MyString.h" | ||
7 | |||
8 | int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW; | ||
9 | #ifndef USE_UNICODE_FSTRING | ||
10 | int CompareFileNames(const char *s1, const char *s2); | ||
11 | #endif | ||
12 | |||
13 | bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2); | ||
14 | |||
15 | void SplitPathToParts(const UString &path, UStringVector &pathParts); | ||
16 | void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name); | ||
17 | void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name); // ignores dir delimiter at the end of (path) | ||
18 | |||
19 | UString ExtractDirPrefixFromPath(const UString &path); | ||
20 | UString ExtractFileNameFromPath(const UString &path); | ||
21 | |||
22 | bool DoesNameContainWildcard(const UString &path); | ||
23 | bool DoesWildcardMatchName(const UString &mask, const UString &name); | ||
24 | |||
25 | namespace NWildcard { | ||
26 | |||
27 | #ifdef _WIN32 | ||
28 | // returns true, if name is like "a:", "c:", ... | ||
29 | bool IsDriveColonName(const wchar_t *s); | ||
30 | unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts); | ||
31 | #endif | ||
32 | |||
33 | struct CItem | ||
34 | { | ||
35 | UStringVector PathParts; | ||
36 | bool Recursive; | ||
37 | bool ForFile; | ||
38 | bool ForDir; | ||
39 | bool WildcardMatching; | ||
40 | |||
41 | #ifdef _WIN32 | ||
42 | bool IsDriveItem() const | ||
43 | { | ||
44 | return PathParts.Size() == 1 && !ForFile && ForDir && IsDriveColonName(PathParts[0]); | ||
45 | } | ||
46 | #endif | ||
47 | |||
48 | // CItem(): WildcardMatching(true) {} | ||
49 | |||
50 | bool AreAllAllowed() const; | ||
51 | bool CheckPath(const UStringVector &pathParts, bool isFile) const; | ||
52 | }; | ||
53 | |||
54 | |||
55 | |||
56 | const Byte kMark_FileOrDir = 0; | ||
57 | const Byte kMark_StrictFile = 1; | ||
58 | const Byte kMark_StrictFile_IfWildcard = 2; | ||
59 | |||
60 | struct CCensorPathProps | ||
61 | { | ||
62 | bool Recursive; | ||
63 | bool WildcardMatching; | ||
64 | Byte MarkMode; | ||
65 | |||
66 | CCensorPathProps(): | ||
67 | Recursive(false), | ||
68 | WildcardMatching(true), | ||
69 | MarkMode(kMark_FileOrDir) | ||
70 | {} | ||
71 | }; | ||
72 | |||
73 | |||
74 | class CCensorNode MY_UNCOPYABLE | ||
75 | { | ||
76 | CCensorNode *Parent; | ||
77 | |||
78 | bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const; | ||
79 | void AddItemSimple(bool include, CItem &item); | ||
80 | public: | ||
81 | // bool ExcludeDirItems; | ||
82 | |||
83 | CCensorNode(): | ||
84 | Parent(NULL) | ||
85 | // , ExcludeDirItems(false) | ||
86 | {}; | ||
87 | |||
88 | CCensorNode(const UString &name, CCensorNode *parent): | ||
89 | Parent(parent) | ||
90 | // , ExcludeDirItems(false) | ||
91 | , Name(name) | ||
92 | {} | ||
93 | |||
94 | UString Name; // WIN32 doesn't support wildcards in file names | ||
95 | CObjectVector<CCensorNode> SubNodes; | ||
96 | CObjectVector<CItem> IncludeItems; | ||
97 | CObjectVector<CItem> ExcludeItems; | ||
98 | |||
99 | CCensorNode &Find_SubNode_Or_Add_New(const UString &name) | ||
100 | { | ||
101 | int i = FindSubNode(name); | ||
102 | if (i >= 0) | ||
103 | return SubNodes[(unsigned)i]; | ||
104 | // return SubNodes.Add(CCensorNode(name, this)); | ||
105 | CCensorNode &node = SubNodes.AddNew(); | ||
106 | node.Parent = this; | ||
107 | node.Name = name; | ||
108 | return node; | ||
109 | } | ||
110 | |||
111 | bool AreAllAllowed() const; | ||
112 | |||
113 | int FindSubNode(const UString &path) const; | ||
114 | |||
115 | void AddItem(bool include, CItem &item, int ignoreWildcardIndex = -1); | ||
116 | // void AddItem(bool include, const UString &path, const CCensorPathProps &props); | ||
117 | void Add_Wildcard() | ||
118 | { | ||
119 | CItem item; | ||
120 | item.PathParts.Add(L"*"); | ||
121 | item.Recursive = false; | ||
122 | item.ForFile = true; | ||
123 | item.ForDir = true; | ||
124 | item.WildcardMatching = true; | ||
125 | AddItem( | ||
126 | true // include | ||
127 | , item); | ||
128 | } | ||
129 | |||
130 | // NeedCheckSubDirs() returns true, if there are IncludeItems rules that affect items in subdirs | ||
131 | bool NeedCheckSubDirs() const; | ||
132 | bool AreThereIncludeItems() const; | ||
133 | |||
134 | /* | ||
135 | CheckPathVect() doesn't check path in Parent CCensorNode | ||
136 | so use CheckPathVect() for root CCensorNode | ||
137 | OUT: | ||
138 | returns (true) && (include = false) - file in exlude list | ||
139 | returns (true) && (include = true) - file in include list and is not in exlude list | ||
140 | returns (false) - file is not in (include/exlude) list | ||
141 | */ | ||
142 | bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const; | ||
143 | |||
144 | // bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const; | ||
145 | // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; | ||
146 | |||
147 | // CheckPathToRoot_Change() changes pathParts !!! | ||
148 | bool CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const; | ||
149 | bool CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const; | ||
150 | |||
151 | // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const; | ||
152 | void ExtendExclude(const CCensorNode &fromNodes); | ||
153 | }; | ||
154 | |||
155 | |||
156 | struct CPair MY_UNCOPYABLE | ||
157 | { | ||
158 | UString Prefix; | ||
159 | CCensorNode Head; | ||
160 | |||
161 | // CPair(const UString &prefix): Prefix(prefix) { }; | ||
162 | }; | ||
163 | |||
164 | |||
165 | enum ECensorPathMode | ||
166 | { | ||
167 | k_RelatPath, // absolute prefix as Prefix, remain path in Tree | ||
168 | k_FullPath, // drive prefix as Prefix, remain path in Tree | ||
169 | k_AbsPath // full path in Tree | ||
170 | }; | ||
171 | |||
172 | |||
173 | struct CCensorPath | ||
174 | { | ||
175 | UString Path; | ||
176 | bool Include; | ||
177 | CCensorPathProps Props; | ||
178 | |||
179 | CCensorPath(): | ||
180 | Include(true) | ||
181 | {} | ||
182 | }; | ||
183 | |||
184 | |||
185 | class CCensor MY_UNCOPYABLE | ||
186 | { | ||
187 | int FindPairForPrefix(const UString &prefix) const; | ||
188 | public: | ||
189 | CObjectVector<CPair> Pairs; | ||
190 | |||
191 | bool ExcludeDirItems; | ||
192 | bool ExcludeFileItems; | ||
193 | |||
194 | CCensor(): | ||
195 | ExcludeDirItems(false), | ||
196 | ExcludeFileItems(false) | ||
197 | {} | ||
198 | |||
199 | CObjectVector<NWildcard::CCensorPath> CensorPaths; | ||
200 | |||
201 | bool AllAreRelative() const | ||
202 | { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); } | ||
203 | |||
204 | void AddItem(ECensorPathMode pathMode, bool include, const UString &path, const CCensorPathProps &props); | ||
205 | // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const; | ||
206 | void ExtendExclude(); | ||
207 | |||
208 | void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode); | ||
209 | void AddPreItem(bool include, const UString &path, const CCensorPathProps &props); | ||
210 | |||
211 | void AddPreItem_NoWildcard(const UString &path) | ||
212 | { | ||
213 | CCensorPathProps props; | ||
214 | props.WildcardMatching = false; | ||
215 | AddPreItem( | ||
216 | true, // include | ||
217 | path, props); | ||
218 | } | ||
219 | void AddPreItem_Wildcard() | ||
220 | { | ||
221 | CCensorPathProps props; | ||
222 | // props.WildcardMatching = true; | ||
223 | AddPreItem( | ||
224 | true, // include | ||
225 | UString("*"), props); | ||
226 | } | ||
227 | }; | ||
228 | |||
229 | } | ||
230 | |||
231 | #endif | ||
diff --git a/CPP/Common/XzCrc64Init.cpp b/CPP/Common/XzCrc64Init.cpp new file mode 100644 index 0000000..5cb8e67 --- /dev/null +++ b/CPP/Common/XzCrc64Init.cpp | |||
@@ -0,0 +1,7 @@ | |||
1 | // XzCrc64Init.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/XzCrc64.h" | ||
6 | |||
7 | static struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit; | ||
diff --git a/CPP/Common/XzCrc64Reg.cpp b/CPP/Common/XzCrc64Reg.cpp new file mode 100644 index 0000000..33b5249 --- /dev/null +++ b/CPP/Common/XzCrc64Reg.cpp | |||
@@ -0,0 +1,42 @@ | |||
1 | // XzCrc64Reg.cpp | ||
2 | |||
3 | #include "StdAfx.h" | ||
4 | |||
5 | #include "../../C/CpuArch.h" | ||
6 | #include "../../C/XzCrc64.h" | ||
7 | |||
8 | #include "../Common/MyCom.h" | ||
9 | |||
10 | #include "../7zip/Common/RegisterCodec.h" | ||
11 | |||
12 | class CXzCrc64Hasher: | ||
13 | public IHasher, | ||
14 | public CMyUnknownImp | ||
15 | { | ||
16 | UInt64 _crc; | ||
17 | Byte mtDummy[1 << 7]; | ||
18 | |||
19 | public: | ||
20 | CXzCrc64Hasher(): _crc(CRC64_INIT_VAL) {} | ||
21 | |||
22 | MY_UNKNOWN_IMP1(IHasher) | ||
23 | INTERFACE_IHasher(;) | ||
24 | }; | ||
25 | |||
26 | STDMETHODIMP_(void) CXzCrc64Hasher::Init() throw() | ||
27 | { | ||
28 | _crc = CRC64_INIT_VAL; | ||
29 | } | ||
30 | |||
31 | STDMETHODIMP_(void) CXzCrc64Hasher::Update(const void *data, UInt32 size) throw() | ||
32 | { | ||
33 | _crc = Crc64Update(_crc, data, size); | ||
34 | } | ||
35 | |||
36 | STDMETHODIMP_(void) CXzCrc64Hasher::Final(Byte *digest) throw() | ||
37 | { | ||
38 | UInt64 val = CRC64_GET_DIGEST(_crc); | ||
39 | SetUi64(digest, val); | ||
40 | } | ||
41 | |||
42 | REGISTER_HASHER(CXzCrc64Hasher, 0x4, "CRC64", 8) | ||