-
Notifications
You must be signed in to change notification settings - Fork 13
/
tools.h
329 lines (296 loc) · 12 KB
/
tools.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#ifndef VDR_LIVE_TOOLS_H
#define VDR_LIVE_TOOLS_H
// uncomment to debug lock sequence
// #define DEBUG_LOCK
// STL headers need to be before VDR tools.h (included by <vdr/channels.h>)
#include <istream>
#include <sstream>
#include <stdexcept>
#include <vector>
#if TNTVERSION >= 30000
#include <cxxtools/log.h> // must be loaded before any VDR include because of duplicate macros (LOG_ERROR, LOG_DEBUG, LOG_INFO)
#include "cxxtools/serializationinfo.h"
#endif
#ifndef DISABLE_TEMPLATES_COLLIDING_WITH_STL
// To get rid of the swap definition in vdr/tools.h
#define DISABLE_TEMPLATES_COLLIDING_WITH_STL
#endif
#include "stringhelpers.h"
#include "xxhash.h"
#include <vdr/channels.h>
// ================ XXH128_hash_t ============================================
inline cToSvHex<32>& operator<<(cToSvHex<32> &h, const XXH128_hash_t &value) {
stringhelpers_internal::addCharsHex(h.m_buffer, 16, value.high64);
stringhelpers_internal::addCharsHex(h.m_buffer+16, 16, value.low64);
return h;
}
template <size_t N>
inline cToSvConcat<N>& operator<<(cToSvConcat<N>& s, const XXH128_hash_t &value) {
s.appendHex(value.high64);
s.appendHex(value.low64);
return s;
}
// ================ Channels ============================================
template <size_t N>
inline cToSvConcat<N> &stringAppendChannel(cToSvConcat<N> &target, const tChannelID &channelID, char point = '.', char minus = '-') {
const int st_Mask = 0xFF000000;
const int st_Pos = 0x0000FFFF;
target.concat((char) ((channelID.Source() & st_Mask) >> 24));
if (int16_t n = channelID.Source() & st_Pos) {
char ew = 'E';
if (n < 0) {
ew = 'W';
n = -n;
}
uint16_t q = (uint16_t)n / 10;
target.concat(q, point, (char)((uint16_t)n - 10*q + '0'), ew);
}
target.concat(minus, channelID.Nid(), minus, channelID.Tid(), minus, channelID.Sid());
if (channelID.Rid() ) target.concat(minus, channelID.Rid() );
return target;
}
template <size_t N>
inline cToSvConcat<N>& operator<<(cToSvConcat<N>& s, const tChannelID &channelID) {
return stringAppendChannel(s, channelID);
}
inline void stringAppend(std::string &str, const tChannelID &channelID) {
str.append(cToSvConcat(channelID));
}
inline std::ostream& operator<<( std::ostream& os, tChannelID const& id ) {
return os << cToSvConcat(id);
}
std::istream& operator>>( std::istream& is, tChannelID& ret );
namespace vdrlive {
extern const std::locale g_locale;
extern const std::collate<char>& g_collate_char;
template <size_t N>
inline cToSvConcat<N>& AppendHtmlEscapedAndCorrectNonUTF8(cToSvConcat<N>& target, cSv text, bool tooltip = false) {
size_t i = 0; // number of not yet appended chars
const char* notAppended = text.data(); // position of the first character which is not yet appended
for (size_t pos = 0; pos < text.length(); ++pos) {
if ((unsigned char)text[pos] <= '\'') {
switch(text[pos]) {
case '\t': target.append(notAppended, i); target.append("&tab;"); notAppended += i + 1; i = 0; break;
case '\n':
case '\r':
// target.append(notAppended, i); target.append("<br/>"); notAppended += i + 1; i = 0; break;
target.append(notAppended, i); target.append("<br/>"); notAppended += i + 1; i = 0; break;
case '&': target.append(notAppended, i); target.append("&"); notAppended += i + 1; i = 0; break;
case '\"': target.append(notAppended, i); target.append("""); notAppended += i + 1; i = 0; break;
case '\'': target.append(notAppended, i); target.append("'"); notAppended += i + 1; i = 0; break;
case ' ':
case '!':
case '#':
case '$':
case '%':
++i; break; // just append these characters, no encoding
default: // replace control characters with ?
target.append(notAppended, i); target.append("?"); notAppended += i + 1; i = 0; break;
}
continue;
}
if ((unsigned char)text[pos] <= '~') {
switch(text[pos]) {
case '\\': target.append(notAppended, i); target.append("\"); notAppended += i + 1; i = 0; break;
case '<': target.append(notAppended, i); target.append("<"); notAppended += i + 1; i = 0; break;
case '>': target.append(notAppended, i); target.append(">"); notAppended += i + 1; i = 0; break;
default:
++i; break; // just append these characters, no encoding
}
continue;
}
if (text[pos] == 127) { // replace control characters with ?
target.append(notAppended, i); target.append("?"); notAppended += i + 1; i = 0;
continue;
}
int l = text.utf8CodepointIsValid(pos);
if (l == 0) {
// invalid UTF8, replace with ?
target.append(notAppended, i); target.append("?"); notAppended += i + 1; i = 0;
continue;
}
if (l == 3 && text[pos] == '\xEE' && text[pos+1] == '\x80') {
target.append(notAppended, i);
switch (text[pos+2]) {
// mapping of VDR private-use symbols onto well-known UTF symbols
case '\x80':
// reversion symbol (counter-clockwise arrow)
target.append("\u21BA");
break;
case '\x82':
// U+E002: folder symbol
target.append("\U0001F4C1");
break;
case '\x83':
// U+E003: non-breaking space
target.append("\u00A0");
break;
case '\x8B':
// U+E00B: recording symbol
target.append("\u00AE");
break;
case '\x8C':
// U+E00C: timer symbol (full coverage)
target.append("\u23F2");
break;
case '\x91':
// U+E011: continuation symbol (clockwise arrow)
target.append("\u21BB");
break;
case '\x92':
// U+E012: running symbol
target.append("\u25B6");
break;
case '\x93':
// U+E013: VPS symbol
target.append("\U0001F185");
break;
case '\x94':
// U+E014: partial timer symbol
target.append("\u26AC");
break;
case '\x95':
// U+E015: inactive timer symbol
target.append("\u29B8");
break;
default:
target.append(text.substr(pos, 3));
break;
}
notAppended += i + 3; i = 0;
pos += 2;
continue;
}
i += l;
pos += l-1;
}
target.append(notAppended, i);
return target;
}
template <size_t N>
inline cToSvConcat<N>& AppendQuoteEscapedAndCorrectNonUTF8(cToSvConcat<N>& target, cSv text) {
size_t i = 0; // number of not yet appended chars
const char* notAppended = text.data(); // position of the first character which is not yet appended
for (size_t pos = 0; pos < text.length(); ++pos) {
if ((unsigned char)text[pos] <= '\"') {
switch(text[pos]) {
case '\t': target.append(notAppended, i); target.append("\\t"); notAppended += i + 1; i = 0; break;
case '\n': target.append(notAppended, i); target.append("\\n"); notAppended += i + 1; i = 0; break;
case '\r': target.append(notAppended, i); target.append("\\r"); notAppended += i + 1; i = 0; break;
case '\"': target.append(notAppended, i); target.append("\\"); notAppended += i; i = 1; break;
case ' ':
case '!':
++i; break; // just append these characters, no encoding
default: // replace control characters with ?
target.append(notAppended, i); target.append("?"); notAppended += i + 1; i = 0; break;
}
continue;
}
if ((unsigned char)text[pos] <= '~') {
if (text[pos] == '\\') {
target.append(notAppended, i); target.append("\\"); notAppended += i; i = 1; // this results in appending two backslashs
} else {
++i; // just append these characters, no encoding
}
continue;
}
if (text[pos] == 127) { // replace control characters with ?
target.append(notAppended, i); target.append("?"); notAppended += i + 1; i = 0;
continue;
}
int l = text.utf8CodepointIsValid(pos);
if (l == 0) {
// invalid UTF8, replace with ?
target.append(notAppended, i); target.append("?"); notAppended += i + 1; i = 0;
} else {
i += l;
pos += l-1;
}
}
target.append(notAppended, i);
return target;
}
cSv StringWordTruncate(cSv text, size_t maxLen, bool& truncated);
inline cSv StringWordTruncate(cSv text, size_t maxLen) { bool dummy; return StringWordTruncate(text, maxLen, dummy); }
template <size_t N>
inline cToSvConcat<N>& AppendTextTruncateOnWord(cToSvConcat<N>& target, cSv text, int max_len, bool tooltip = false) {
// append text to target, but only up to max_len characters. If such truncation is required, truncate at ' ' \n, ... and similar
// escape HTML characters, and correct invalid UTF8
bool truncated;
AppendHtmlEscapedAndCorrectNonUTF8(target, StringWordTruncate(text, max_len, truncated), tooltip);
if (truncated) target.append(" ...");
return target;
}
template<size_t N>
inline cToSvConcat<N>& AppendDuration(cToSvConcat<N>& target, char const* format, int duration) {
int minutes = (duration + 30) / 60;
int hours = minutes / 60;
minutes %= 60;
target.appendFormated(format, hours, minutes);
return target;
}
std::string FormatDuration( char const* format, int duration );
std::vector<std::string> StringSplit(cSv text, char delimiter );
cSv StringTrim(cSv str);
std::string MD5Hash(std::string const& str);
class cToSvXxHash32: public cToSvHex<8> {
public:
cToSvXxHash32(XXH32_hash_t value): cToSvHex<8>::cToSvHex(value) {}
cToSvXxHash32(cSv str): cToSvHex<8>::cToSvHex(XXH32(str.data(), str.length(), 20)) {}
};
XXH64_hash_t parse_hex_64(cSv str);
class cToSvXxHash64: public cToSvHex<16> {
public:
cToSvXxHash64(XXH64_hash_t value): cToSvHex<16>::cToSvHex(value) {}
cToSvXxHash64(cSv str): cToSvHex<16>::cToSvHex(XXH3_64bits(str.data(), str.length() )) {}
};
XXH128_hash_t parse_hex_128(cSv str);
class cToSvXxHash128: public cToSvHex<32> {
public:
cToSvXxHash128(XXH128_hash_t value): cToSvHex<32>::cToSvHex(value) { }
cToSvXxHash128(cSv str): cToSvHex<32>::cToSvHex(XXH3_128bits(str.data(), str.length() )) {}
};
time_t GetTimeT(cSv timestring); // timestring in HH:MM
std::string ExpandTimeString(std::string timestring);
time_t GetDateFromDatePicker(cSv datestring, cSv format);
std::string DatePickerToC(time_t date, cSv format);
std::string intToTimeString(int tm);
int timeStringToInt(const char *t);
int timeStringToInt(const std::string &t);
void EncodeDomId(char *toEncode_s, char *toEncode_e, char const * from = ".-:", char const * to = "pmc");
inline void DecodeDomId(char *toDecode_s, char *toDecode_e, char const * from = "pmc", char const * to = ".-:") {
EncodeDomId(toDecode_s, toDecode_e, from, to);
}
std::string EncodeDomId(cSv toEncode, char const * from = ".-:", char const * to = "pmc");
inline std::string DecodeDomId(cSv toDecode, char const * from = "pmc", char const * to = ".-:") {
return EncodeDomId(toDecode, from, to);
}
std::string FileSystemExchangeChars(cSv s, bool ToFileSystem);
bool MoveDirectory(cSv sourceDir, cSv targetDir, bool copy = false);
struct bad_lexical_cast: std::runtime_error
{
bad_lexical_cast(): std::runtime_error( "bad lexical cast" ) {}
};
template<typename To, typename From>
To lexical_cast( From const& from )
{
std::stringstream parser;
parser << from;
To result;
parser >> result;
if ( !parser )
throw bad_lexical_cast();
return result;
}
// methods for scraper **************************************
// tool for images returned by Tvscraper or scraper2vdr:
// convert path (valid in local file system) to path which can be used by live (in browser) to access the image
// Note: final browser path is: "/tvscraper/" + ScraperImagePath2Live(...)
cSv ScraperImagePath2Live(cSv path);
// call the service Id
// return false if there is no scraper plugin, or if the service does not exist
// otherwise, return true
// can be called with Data == Null to check is the service exits
bool ScraperCallService(const char *Id, void *Data);
} // namespace vdrlive
#endif // VDR_LIVE_TOOLS_H