1 /*
2  *  This file is part of nzbget. See <http://nzbget.net>.
3  *
4  *  Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 #ifndef UTIL_H
22 #define UTIL_H
23 
24 #include "NString.h"
25 
26 #ifdef WIN32
27 extern int optind, opterr;
28 extern char *optarg;
29 int getopt(int argc, char *argv[], char *optstring);
30 #endif
31 
32 class Util
33 {
34 public:
35 	static bool MatchFileExt(const char* filename, const char* extensionList, const char* listSeparator);
36 
37 	/*
38 	* Split command line into arguments.
39 	* Uses spaces and single quotation marks as separators.
40 	* May return empty list if bad escaping was detected.
41 	*/
42 	static std::vector<CString> SplitCommandLine(const char* commandLine);
43 
44 	static int64 JoinInt64(uint32 Hi, uint32 Lo);
45 	static void SplitInt64(int64 Int64, uint32* Hi, uint32* Lo);
46 
47 	static void TrimRight(char* str);
48 	static char* Trim(char* str);
EmptyStr(const char * str)49 	static bool EmptyStr(const char* str) { return !str || !*str; }
50 	static std::vector<CString> SplitStr(const char* str, const char* separators);
51 	static bool EndsWith(const char* str, const char* suffix, bool caseSensitive);
52 	static bool AlphaNum(const char* str);
53 
54 	/* replace all occurences of szFrom to szTo in string szStr with a limitation that szTo must be shorter than szFrom */
55 	static char* ReduceStr(char* str, const char* from, const char* to);
56 
57 	/* Calculate Hash using Bob Jenkins (1996) algorithm */
58 	static uint32 HashBJ96(const char* buffer, int bufSize, uint32 initValue);
59 
60 #ifdef WIN32
61 	static bool RegReadStr(HKEY keyRoot, const char* keyName, const char* valueName, char* buffer, int* bufLen);
62 #endif
63 
64 	static void SetStandByMode(bool standBy);
65 
66 	static time_t CurrentTime();
67 	static int64 CurrentTicks();
68 	static void Sleep(int milliseconds);
69 
70 	/* cross platform version of GNU timegm, which is similar to mktime but takes an UTC time as parameter */
71 	static time_t Timegm(tm const *t);
72 
73 	static void FormatTime(time_t timeSec, char* buffer, int bufsize);
74 	static CString FormatTime(time_t timeSec);
75 
76 	static CString FormatSpeed(int bytesPerSecond);
77 	static CString FormatSize(int64 fileSize);
78 	static CString FormatBuffer(const char* buf, int len);
79 
80 	/*
81 	* Returns program version and revision number as string formatted like "0.7.0-r295".
82 	* If revision number is not available only version is returned ("0.7.0").
83 	*/
VersionRevision()84 	static const char* VersionRevision() { return VersionRevisionBuf; };
85 
86 	static char VersionRevisionBuf[100];
87 
88 	static void Init();
89 
90 	/*
91 	* Returns number of available CPU cores or -1 if it could not be determined
92 	*/
93 	static int NumberOfCpuCores();
94 };
95 
96 class WebUtil
97 {
98 public:
99 	static uint32 DecodeBase64(char* inputBuffer, int inputBufferLength, char* outputBuffer);
100 
101 	/*
102 	* Encodes string to be used as content of xml-tag.
103 	*/
104 	static CString XmlEncode(const char* raw);
105 
106 	/*
107 	* Decodes string from xml.
108 	* The string is decoded on the place overwriting the content of raw-data.
109 	*/
110 	static void XmlDecode(char* raw);
111 
112 	/*
113 	* Returns pointer to tag-content and length of content in iValueLength
114 	* The returned pointer points to the part of source-string, no additional strings are allocated.
115 	*/
116 	static const char* XmlFindTag(const char* xml, const char* tag, int* valueLength);
117 
118 	/*
119 	* Parses tag-content into szValueBuf.
120 	*/
121 	static bool XmlParseTagValue(const char* xml, const char* tag, char* valueBuf, int valueBufSize, const char** tagEnd);
122 
123 	/*
124 	* Replaces all tags with spaces effectively providing the text content only.
125 	* The string is transformed in-place overwriting the previous content.
126 	*/
127 	static void XmlStripTags(char* xml);
128 
129 	/*
130 	* Replaces all entities with spaces.
131 	* The string is transformed in-place overwriting the previous content.
132 	*/
133 	static void XmlRemoveEntities(char* raw);
134 
135 	/*
136 	* Creates JSON-string by replace the certain characters with escape-sequences.
137 	*/
138 	static CString JsonEncode(const char* raw);
139 
140 	/*
141 	* Decodes JSON-string.
142 	* The string is decoded on the place overwriting the content of raw-data.
143 	*/
144 	static void JsonDecode(char* raw);
145 
146 	/*
147 	* Returns pointer to field-content and length of content in iValueLength
148 	* The returned pointer points to the part of source-string, no additional strings are allocated.
149 	*/
150 	static const char* JsonFindField(const char* jsonText, const char* fieldName, int* valueLength);
151 
152 	/*
153 	* Returns pointer to field-content and length of content in iValueLength
154 	* The returned pointer points to the part of source-string, no additional strings are allocated.
155 	*/
156 	static const char* JsonNextValue(const char* jsonText, int* valueLength);
157 
158 	/*
159 	* Unquote http quoted string.
160 	* The string is decoded on the place overwriting the content of raw-data.
161 	*/
162 	static void HttpUnquote(char* raw);
163 
164 	/*
165 	* Decodes URL-string.
166 	* The string is decoded on the place overwriting the content of raw-data.
167 	*/
168 	static void UrlDecode(char* raw);
169 
170 	/*
171 	* Makes valid URL by replacing of spaces with "%20".
172 	*/
173 	static CString UrlEncode(const char* raw);
174 
175 	/*
176 	* Converts ISO-8859-1 (aka Latin-1) into UTF-8.
177 	*/
178 	static CString Latin1ToUtf8(const char* str);
179 
180 	static time_t ParseRfc822DateTime(const char* dateTimeStr);
181 };
182 
183 class URL
184 {
185 public:
186 	URL(const char* address);
IsValid()187 	bool IsValid() { return m_valid; }
GetAddress()188 	const char* GetAddress() { return m_address; }
GetProtocol()189 	const char* GetProtocol() { return m_protocol; }
GetUser()190 	const char* GetUser() { return m_user; }
GetPassword()191 	const char* GetPassword() { return m_password; }
GetHost()192 	const char* GetHost() { return m_host; }
GetResource()193 	const char* GetResource() { return m_resource; }
GetPort()194 	int GetPort() { return m_port; }
GetTls()195 	bool GetTls() { return m_tls; }
196 
197 private:
198 	CString m_address;
199 	CString m_protocol;
200 	CString m_user;
201 	CString m_password;
202 	CString m_host;
203 	CString m_resource;
204 	int m_port = 0;
205 	bool m_tls = false;
206 	bool m_valid = false;
207 
208 	void ParseUrl();
209 };
210 
211 class RegEx
212 {
213 public:
214 	RegEx(const char *pattern, int matchBufSize = 100);
215 	~RegEx();
IsValid()216 	bool IsValid() { return m_valid; }
217 	bool Match(const char* str);
218 	int GetMatchCount();
219 	int GetMatchStart(int index);
220 	int GetMatchLen(int index);
221 
222 private:
223 #ifdef HAVE_REGEX_H
224 	regex_t m_context;
225 	std::unique_ptr<regmatch_t[]> m_matches;
226 #endif
227 	bool m_valid;
228 	int m_matchBufSize;
229 };
230 
231 class WildMask
232 {
233 public:
234 	WildMask(const char* pattern, bool wantsPositions = false):
m_pattern(pattern)235 		m_pattern(pattern), m_wantsPositions(wantsPositions) {}
236 	bool Match(const char* text);
GetMatchCount()237 	int GetMatchCount() { return m_wildCount; }
GetMatchStart(int index)238 	int GetMatchStart(int index) { return m_wildStart[index]; }
GetMatchLen(int index)239 	int GetMatchLen(int index) { return m_wildLen[index]; }
240 
241 private:
242 	typedef std::vector<int> IntList;
243 
244 	CString m_pattern;
245 	bool m_wantsPositions;
246 	int m_wildCount;
247 	IntList m_wildStart;
248 	IntList m_wildLen;
249 
250 	void ExpandArray();
251 };
252 
253 #ifndef DISABLE_GZIP
254 class ZLib
255 {
256 public:
257 	/*
258 	* calculates the size required for output buffer
259 	*/
260 	static uint32 GZipLen(int inputBufferLength);
261 
262 	/*
263 	* compresses inputBuffer and returns the size of bytes written to
264 	* outputBuffer or 0 if the buffer is too small or an error occured.
265 	*/
266 	static uint32 GZip(const void* inputBuffer, int inputBufferLength, void* outputBuffer, int outputBufferLength);
267 };
268 
269 class GUnzipStream
270 {
271 public:
272 	enum EStatus
273 	{
274 		zlError,
275 		zlFinished,
276 		zlOK
277 	};
278 
279 	GUnzipStream(int BufferSize);
280 	~GUnzipStream();
281 
282 	/*
283 	* set next memory block for uncompression
284 	*/
285 	void Write(const void *inputBuffer, int inputBufferLength);
286 
287 	/*
288 	* get next uncompressed memory block.
289 	* iOutputBufferLength - the size of uncompressed block. if it is "0" the next compressed block must be provided via "Write".
290 	*/
291 	EStatus Read(const void **outputBuffer, int *outputBufferLength);
292 
293 private:
294 	z_stream m_zStream = {0};
295 	std::unique_ptr<Bytef[]> m_outputBuffer;
296 	int m_bufferSize;
297 	bool m_active = false;
298 };
299 #endif
300 
301 class Tokenizer
302 {
303 public:
304 	Tokenizer(const char* dataString, const char* separators);
305 	Tokenizer(char* dataString, const char* separators, bool inplaceBuf);
306 	char* Next();
307 
308 private:
309 	BString<1024> m_shortString;
310 	CString m_longString;
311 	char* m_dataString;
312 	const char* m_separators;
313 	char* m_savePtr = nullptr;
314 	bool m_working = false;
315 };
316 
317 class Crc32
318 {
319 public:
Crc32()320 	Crc32() { Reset(); }
321 	void Reset();
322 	void Append(uchar* block, uint32 length);
323 	uint32 Finish();
324 	static uint32 Combine(uint32 crc1, uint32 crc2, uint32 len2);
325 
326 private:
327 #if defined(WIN32) && !defined(_WIN64)
328 	// VC++ in 32 bit mode can not "alignas(16)" dynamically allocated objects
329 	alignas(8) uint32_t m_state[4 * 5 + 8]; // = YEncode::crc_state
State()330 	void* State() { void* p = &m_state; size_t s = sizeof(m_state); return std::align(16, 4 * 5, p, s); }
331 #else
332 	alignas(16) uint32_t m_state[4 * 5]; // = YEncode::crc_state
333 	void* State() { return &m_state; }
334 #endif
335 };
336 
337 #endif
338