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-21.07.tar.gz 7zip-21.07.tar.bz2 7zip-21.07.zip | |
'21.07'21.07
Diffstat (limited to '')
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) | ||
