GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/** |
||
2 |
* This file is part of the CernVM File System. |
||
3 |
* |
||
4 |
* Some common functions. |
||
5 |
*/ |
||
6 |
|||
7 |
#ifndef __STDC_FORMAT_MACROS |
||
8 |
#define __STDC_FORMAT_MACROS |
||
9 |
#endif |
||
10 |
|||
11 |
#include "string.h" |
||
12 |
#include "cvmfs_config.h" |
||
13 |
|||
14 |
#include <errno.h> |
||
15 |
#include <fcntl.h> |
||
16 |
#include <inttypes.h> |
||
17 |
#include <stdint.h> |
||
18 |
#include <unistd.h> |
||
19 |
|||
20 |
#include <cstdio> |
||
21 |
#include <cstdlib> |
||
22 |
#include <cstring> |
||
23 |
#include <ctime> |
||
24 |
#include <string> |
||
25 |
|||
26 |
using namespace std; // NOLINT |
||
27 |
|||
28 |
#ifdef CVMFS_NAMESPACE_GUARD |
||
29 |
namespace CVMFS_NAMESPACE_GUARD { |
||
30 |
#endif |
||
31 |
|||
32 |
const char b64_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', |
||
33 |
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', |
||
34 |
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', |
||
35 |
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', |
||
36 |
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', |
||
37 |
'3', '4', '5', '6', '7', '8', '9', '+', '/'}; |
||
38 |
|||
39 |
/** |
||
40 |
* Decode Base64 and Base64Url |
||
41 |
*/ |
||
42 |
const signed char db64_table[] = { |
||
43 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
44 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
45 |
-1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, |
||
46 |
61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, |
||
47 |
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, |
||
48 |
63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, |
||
49 |
43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, |
||
50 |
|||
51 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
52 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
53 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
54 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
55 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
56 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
57 |
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
||
58 |
}; |
||
59 |
|||
60 |
namespace { |
||
61 |
|||
62 |
/** |
||
63 |
* Used for cas insensitive HasSuffix |
||
64 |
*/ |
||
65 |
struct IgnoreCaseComperator { |
||
66 |
165 |
IgnoreCaseComperator() {} |
|
67 |
4 |
bool operator()(const std::string::value_type a, |
|
68 |
const std::string::value_type b) const { |
||
69 |
4 |
return std::tolower(a) == std::tolower(b); |
|
70 |
} |
||
71 |
}; |
||
72 |
|||
73 |
} // anonymous namespace |
||
74 |
|||
75 |
✓✓ | 88 |
string StringifyBool(const bool value) { return value ? "yes" : "no"; } |
76 |
|||
77 |
9668917 |
string StringifyInt(const int64_t value) { |
|
78 |
char buffer[48]; |
||
79 |
9668917 |
snprintf(buffer, sizeof(buffer), "%" PRId64, value); |
|
80 |
9668917 |
return string(buffer); |
|
81 |
} |
||
82 |
|||
83 |
7 |
std::string StringifyUint(const uint64_t value) { |
|
84 |
char buffer[48]; |
||
85 |
7 |
snprintf(buffer, sizeof(buffer), "%" PRIu64, value); |
|
86 |
7 |
return string(buffer); |
|
87 |
} |
||
88 |
|||
89 |
4 |
string StringifyByteAsHex(const unsigned char value) { |
|
90 |
char buffer[3]; |
||
91 |
4 |
snprintf(buffer, sizeof(buffer), "%02x", value); |
|
92 |
4 |
return string(buffer); |
|
93 |
} |
||
94 |
|||
95 |
8 |
string StringifyDouble(const double value) { |
|
96 |
char buffer[64]; |
||
97 |
8 |
snprintf(buffer, sizeof(buffer), "%.03f", value); |
|
98 |
8 |
return string(buffer); |
|
99 |
} |
||
100 |
|||
101 |
/** |
||
102 |
* Converts seconds since UTC 0 into something readable |
||
103 |
*/ |
||
104 |
82 |
string StringifyTime(const time_t seconds, const bool utc) { |
|
105 |
struct tm timestamp; |
||
106 |
✓✓ | 82 |
if (utc) { |
107 |
44 |
localtime_r(&seconds, ×tamp); |
|
108 |
} else { |
||
109 |
38 |
gmtime_r(&seconds, ×tamp); |
|
110 |
} |
||
111 |
|||
112 |
const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
||
113 |
82 |
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; |
|
114 |
char buffer[21]; |
||
115 |
snprintf(buffer, sizeof(buffer), "%d %s %d %02d:%02d:%02d", timestamp.tm_mday, |
||
116 |
months[timestamp.tm_mon], timestamp.tm_year + 1900, |
||
117 |
82 |
timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec); |
|
118 |
|||
119 |
82 |
return string(buffer); |
|
120 |
} |
||
121 |
|||
122 |
|||
123 |
/** |
||
124 |
* Current time in format Wed, 01 Mar 2006 12:00:00 GMT |
||
125 |
*/ |
||
126 |
6120 |
std::string RfcTimestamp() { |
|
127 |
const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
||
128 |
6120 |
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; |
|
129 |
6120 |
const char *day_of_week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; |
|
130 |
|||
131 |
struct tm timestamp; |
||
132 |
6120 |
time_t now = time(NULL); |
|
133 |
6120 |
gmtime_r(&now, ×tamp); |
|
134 |
|||
135 |
char buffer[30]; |
||
136 |
snprintf(buffer, sizeof(buffer), "%s, %02d %s %d %02d:%02d:%02d %s", |
||
137 |
day_of_week[timestamp.tm_wday], timestamp.tm_mday, |
||
138 |
months[timestamp.tm_mon], timestamp.tm_year + 1900, |
||
139 |
timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec, |
||
140 |
6120 |
timestamp.tm_zone); |
|
141 |
6120 |
return string(buffer); |
|
142 |
} |
||
143 |
|||
144 |
|||
145 |
/** |
||
146 |
* Current time in format YYYYMMDDTHHMMSSZ. Used in AWS4 requests. |
||
147 |
*/ |
||
148 |
1 |
std::string IsoTimestamp() { |
|
149 |
struct tm timestamp; |
||
150 |
1 |
time_t now = time(NULL); |
|
151 |
1 |
gmtime_r(&now, ×tamp); |
|
152 |
|||
153 |
char buffer[17]; |
||
154 |
snprintf(buffer, sizeof(buffer), "%04d%02d%02dT%02d%02d%02dZ", |
||
155 |
timestamp.tm_year + 1900, |
||
156 |
timestamp.tm_mon + 1, |
||
157 |
timestamp.tm_mday, |
||
158 |
timestamp.tm_hour, |
||
159 |
timestamp.tm_min, |
||
160 |
1 |
timestamp.tm_sec); |
|
161 |
1 |
return string(buffer); |
|
162 |
} |
||
163 |
|||
164 |
|||
165 |
5589438 |
string StringifyTimeval(const timeval value) { |
|
166 |
char buffer[64]; |
||
167 |
5589438 |
int64_t msec = value.tv_sec * 1000; |
|
168 |
5589438 |
msec += value.tv_usec / 1000; |
|
169 |
snprintf(buffer, sizeof(buffer), "%" PRId64 ".%03d", msec, |
||
170 |
5589438 |
static_cast<int>(value.tv_usec % 1000)); |
|
171 |
5589438 |
return string(buffer); |
|
172 |
} |
||
173 |
|||
174 |
/** |
||
175 |
* Parses a timstamp of the form YYYY-MM-DDTHH:MM:SSZ |
||
176 |
* Return 0 on error |
||
177 |
*/ |
||
178 |
90 |
time_t IsoTimestamp2UtcTime(const std::string &iso8601) { |
|
179 |
90 |
time_t utc_time = 0; |
|
180 |
90 |
unsigned length = iso8601.length(); |
|
181 |
|||
182 |
✓✓ | 90 |
if (length != 20) return utc_time; |
183 |
✓✗✓✗ ✓✗✓✗ ✓✗✗✓ ✗✓ |
88 |
if ((iso8601[4] != '-') || (iso8601[7] != '-') || (iso8601[10] != 'T') || |
184 |
(iso8601[13] != ':') || (iso8601[16] != ':') || (iso8601[19] != 'Z')) { |
||
185 |
return utc_time; |
||
186 |
} |
||
187 |
|||
188 |
struct tm tm_wl; |
||
189 |
88 |
memset(&tm_wl, 0, sizeof(struct tm)); |
|
190 |
88 |
tm_wl.tm_year = String2Int64(iso8601.substr(0, 4)) - 1900; |
|
191 |
176 |
tm_wl.tm_mon = String2Int64(iso8601.substr(5, 2)) - 1; |
|
192 |
176 |
tm_wl.tm_mday = String2Int64(iso8601.substr(8, 2)); |
|
193 |
176 |
tm_wl.tm_hour = String2Int64(iso8601.substr(11, 2)); |
|
194 |
176 |
tm_wl.tm_min = String2Int64(iso8601.substr(14, 2)); |
|
195 |
176 |
tm_wl.tm_sec = String2Int64(iso8601.substr(17, 2)); |
|
196 |
88 |
utc_time = timegm(&tm_wl); |
|
197 |
✓✓ | 89 |
if (utc_time < 0) return 0; |
198 |
|||
199 |
87 |
return utc_time; |
|
200 |
} |
||
201 |
|||
202 |
3795 |
int64_t String2Int64(const string &value) { |
|
203 |
int64_t result; |
||
204 |
3795 |
sscanf(value.c_str(), "%" PRId64, &result); |
|
205 |
3795 |
return result; |
|
206 |
} |
||
207 |
|||
208 |
9168 |
uint64_t String2Uint64(const string &value) { |
|
209 |
uint64_t result; |
||
210 |
9168 |
sscanf(value.c_str(), "%" PRIu64, &result); |
|
211 |
9168 |
return result; |
|
212 |
} |
||
213 |
|||
214 |
/** |
||
215 |
* Parse a string into a a uint64_t. |
||
216 |
* |
||
217 |
* Unlike String2Uint64, this: |
||
218 |
* - Checks to make sure the full string is parsed |
||
219 |
* - Can indicate an error occurred. |
||
220 |
* |
||
221 |
* If an error occurs, this returns false and sets errno appropriately. |
||
222 |
*/ |
||
223 |
11 |
bool String2Uint64Parse(const std::string &value, uint64_t *result) { |
|
224 |
11 |
char *endptr = NULL; |
|
225 |
11 |
errno = 0; |
|
226 |
11 |
long long myval = strtoll(value.c_str(), &endptr, 10); // NOLINT |
|
227 |
✓✓✓✓ ✓✓✓✓ |
11 |
if ((value.size() == 0) || (endptr != (value.c_str() + value.size())) || |
228 |
(myval < 0)) { |
||
229 |
4 |
errno = EINVAL; |
|
230 |
4 |
return false; |
|
231 |
} |
||
232 |
✗✓ | 7 |
if (errno) { |
233 |
return false; |
||
234 |
} |
||
235 |
✓✓ | 7 |
if (result) { |
236 |
6 |
*result = myval; |
|
237 |
} |
||
238 |
7 |
return true; |
|
239 |
} |
||
240 |
|||
241 |
4 |
void String2Uint64Pair(const string &value, uint64_t *a, uint64_t *b) { |
|
242 |
4 |
sscanf(value.c_str(), "%" PRIu64 " %" PRIu64, a, b); |
|
243 |
4 |
} |
|
244 |
|||
245 |
17935 |
bool HasPrefix(const string &str, const string &prefix, |
|
246 |
const bool ignore_case) { |
||
247 |
✓✓ | 17935 |
if (prefix.length() > str.length()) return false; |
248 |
|||
249 |
✓✓ | 73825 |
for (unsigned i = 0, l = prefix.length(); i < l; ++i) { |
250 |
✓✓ | 66335 |
if (ignore_case) { |
251 |
✓✓ | 3337 |
if (toupper(str[i]) != toupper(prefix[i])) return false; |
252 |
} else { |
||
253 |
✓✓ | 62998 |
if (str[i] != prefix[i]) return false; |
254 |
} |
||
255 |
} |
||
256 |
7490 |
return true; |
|
257 |
} |
||
258 |
|||
259 |
166 |
bool HasSuffix(const std::string &str, const std::string &suffix, |
|
260 |
const bool ignore_case) { |
||
261 |
✓✓ | 166 |
if (suffix.size() > str.size()) return false; |
262 |
165 |
const IgnoreCaseComperator icmp; |
|
263 |
return (ignore_case) |
||
264 |
? std::equal(suffix.rbegin(), suffix.rend(), str.rbegin(), icmp) |
||
265 |
✓✓ | 165 |
: std::equal(suffix.rbegin(), suffix.rend(), str.rbegin()); |
266 |
} |
||
267 |
|||
268 |
6809 |
vector<string> SplitString(const string &str, const char delim, |
|
269 |
const unsigned max_chunks) { |
||
270 |
6809 |
vector<string> result; |
|
271 |
|||
272 |
// edge case... one chunk is always the whole string |
||
273 |
✓✓ | 6809 |
if (1 == max_chunks) { |
274 |
1 |
result.push_back(str); |
|
275 |
1 |
return result; |
|
276 |
} |
||
277 |
|||
278 |
// split the string |
||
279 |
6808 |
const unsigned size = str.size(); |
|
280 |
6808 |
unsigned marker = 0; |
|
281 |
6808 |
unsigned chunks = 1; |
|
282 |
unsigned i; |
||
283 |
✓✓ | 1457728 |
for (i = 0; i < size; ++i) { |
284 |
✓✓ | 1450922 |
if (str[i] == delim) { |
285 |
47376 |
result.push_back(str.substr(marker, i - marker)); |
|
286 |
47376 |
marker = i + 1; |
|
287 |
|||
288 |
// we got what we want... good bye |
||
289 |
✓✓ | 47376 |
if (++chunks == max_chunks) break; |
290 |
} |
||
291 |
} |
||
292 |
|||
293 |
// push the remainings of the string and return |
||
294 |
6808 |
result.push_back(str.substr(marker)); |
|
295 |
6808 |
return result; |
|
296 |
} |
||
297 |
|||
298 |
114 |
string JoinStrings(const vector<string> &strings, const string &joint) { |
|
299 |
114 |
string result = ""; |
|
300 |
114 |
const unsigned size = strings.size(); |
|
301 |
|||
302 |
✓✓ | 114 |
if (size > 0) { |
303 |
105 |
result = strings[0]; |
|
304 |
✗✓✓ | 105 |
for (unsigned i = 1; i < size; ++i) result += joint + strings[i]; |
305 |
} |
||
306 |
|||
307 |
114 |
return result; |
|
308 |
} |
||
309 |
|||
310 |
120 |
void ParseKeyvalMem(const unsigned char *buffer, const unsigned buffer_size, |
|
311 |
map<char, string> *content) { |
||
312 |
120 |
string line; |
|
313 |
120 |
unsigned pos = 0; |
|
314 |
✓✓ | 11258 |
while (pos < buffer_size) { |
315 |
✓✓ | 11137 |
if (static_cast<char>(buffer[pos]) == '\n') { |
316 |
✓✓ | 835 |
if (line == "--") return; |
317 |
|||
318 |
✓✗ | 716 |
if (line != "") { |
319 |
✗✓✗✗ ✗✓ |
716 |
const string tail = (line.length() == 1) ? "" : line.substr(1); |
320 |
// Special handling of 'Z' key because it can exist multiple times |
||
321 |
✓✓ | 716 |
if (line[0] != 'Z') { |
322 |
712 |
(*content)[line[0]] = tail; |
|
323 |
} else { |
||
324 |
✓✓ | 4 |
if (content->find(line[0]) == content->end()) { |
325 |
2 |
(*content)[line[0]] = tail; |
|
326 |
} else { |
||
327 |
2 |
(*content)[line[0]] = (*content)[line[0]] + "|" + tail; |
|
328 |
} |
||
329 |
} |
||
330 |
} |
||
331 |
716 |
line = ""; |
|
332 |
} else { |
||
333 |
10302 |
line += static_cast<char>(buffer[pos]); |
|
334 |
} |
||
335 |
11018 |
pos++; |
|
336 |
} |
||
337 |
} |
||
338 |
|||
339 |
11 |
bool ParseKeyvalPath(const string &filename, map<char, string> *content) { |
|
340 |
11 |
int fd = open(filename.c_str(), O_RDONLY); |
|
341 |
✓✓ | 11 |
if (fd < 0) return false; |
342 |
|||
343 |
unsigned char buffer[4096]; |
||
344 |
10 |
int num_bytes = read(fd, buffer, sizeof(buffer)); |
|
345 |
10 |
close(fd); |
|
346 |
|||
347 |
✓✓✗✓ |
10 |
if ((num_bytes <= 0) || (unsigned(num_bytes) >= sizeof(buffer))) return false; |
348 |
|||
349 |
9 |
ParseKeyvalMem(buffer, unsigned(num_bytes), content); |
|
350 |
9 |
return true; |
|
351 |
} |
||
352 |
|||
353 |
7151 |
string GetLineMem(const char *text, const int text_size) { |
|
354 |
7151 |
int pos = 0; |
|
355 |
✓✓✓✓ ✓✓ |
7151 |
while ((pos < text_size) && (text[pos] != '\n')) pos++; |
356 |
7151 |
return string(text, pos); |
|
357 |
} |
||
358 |
|||
359 |
5593257 |
bool GetLineFile(FILE *f, std::string *line) { |
|
360 |
int retval; |
||
361 |
5593257 |
line->clear(); |
|
362 |
393531876 |
while (true) { |
|
363 |
399125133 |
retval = fgetc(f); |
|
364 |
✗✓✗✗ ✗✓ |
399125133 |
if (ferror(f) && (errno == EINTR)) { |
365 |
clearerr(f); |
||
366 |
continue; |
||
367 |
✓✓ | 399125133 |
} else if (retval == EOF) { |
368 |
682 |
break; |
|
369 |
} |
||
370 |
399124451 |
char c = retval; |
|
371 |
✓✓ | 399124451 |
if (c == '\n') break; |
372 |
393531876 |
line->push_back(c); |
|
373 |
} |
||
374 |
✓✓✓✓ |
5593257 |
return (retval != EOF) || !line->empty(); |
375 |
} |
||
376 |
|||
377 |
985 |
bool GetLineFd(const int fd, std::string *line) { |
|
378 |
int retval; |
||
379 |
char c; |
||
380 |
985 |
line->clear(); |
|
381 |
66547 |
while (true) { |
|
382 |
67532 |
retval = read(fd, &c, 1); |
|
383 |
✓✓ | 67532 |
if (retval == 0) { |
384 |
6 |
break; |
|
385 |
} |
||
386 |
✗✓✗✗ |
67526 |
if ((retval == -1) && (errno == EINTR)) { |
387 |
continue; |
||
388 |
} |
||
389 |
✗✓ | 67526 |
if (retval == -1) { |
390 |
break; |
||
391 |
} |
||
392 |
✓✓ | 67526 |
if (c == '\n') break; |
393 |
66547 |
line->push_back(c); |
|
394 |
} |
||
395 |
✓✓✓✓ |
985 |
return (retval == 1) || !line->empty(); |
396 |
} |
||
397 |
|||
398 |
/** |
||
399 |
* Removes leading and trailing whitespaces. |
||
400 |
*/ |
||
401 |
2694 |
string Trim(const string &raw) { |
|
402 |
✓✓ | 2694 |
if (raw.empty()) return ""; |
403 |
|||
404 |
2548 |
unsigned start_pos = 0; |
|
405 |
✓✗✓✓ ✗✓✓✓ |
2548 |
for (; (start_pos < raw.length()) && |
406 |
(raw[start_pos] == ' ' || raw[start_pos] == '\t'); |
||
407 |
++start_pos) { |
||
408 |
} |
||
409 |
2548 |
unsigned end_pos = raw.length() - 1; // at least one character in raw |
|
410 |
✓✗✓✓ ✗✓✓✓ |
2548 |
for (; |
411 |
(end_pos >= start_pos) && (raw[end_pos] == ' ' || raw[end_pos] == '\t'); |
||
412 |
--end_pos) { |
||
413 |
} |
||
414 |
|||
415 |
2548 |
return raw.substr(start_pos, end_pos - start_pos + 1); |
|
416 |
} |
||
417 |
|||
418 |
/** |
||
419 |
* Converts all characters to upper case |
||
420 |
*/ |
||
421 |
189 |
string ToUpper(const string &mixed_case) { |
|
422 |
189 |
string result(mixed_case); |
|
423 |
✓✓ | 670 |
for (unsigned i = 0, l = result.length(); i < l; ++i) { |
424 |
481 |
result[i] = toupper(result[i]); |
|
425 |
} |
||
426 |
189 |
return result; |
|
427 |
} |
||
428 |
|||
429 |
250 |
string ReplaceAll(const string &haystack, const string &needle, |
|
430 |
const string &replace_by) { |
||
431 |
250 |
string result(haystack); |
|
432 |
250 |
size_t pos = 0; |
|
433 |
250 |
const unsigned needle_size = needle.size(); |
|
434 |
✓✓ | 250 |
if (needle == "") return result; |
435 |
|||
436 |
✓✓ | 627 |
while ((pos = result.find(needle, pos)) != string::npos) |
437 |
129 |
result.replace(pos, needle_size, replace_by); |
|
438 |
249 |
return result; |
|
439 |
} |
||
440 |
|||
441 |
102244 |
static inline void Base64Block(const unsigned char input[3], const char *table, |
|
442 |
char output[4]) { |
||
443 |
102244 |
output[0] = table[(input[0] & 0xFD) >> 2]; |
|
444 |
102244 |
output[1] = table[((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4)]; |
|
445 |
102244 |
output[2] = table[((input[1] & 0x0F) << 2) | ((input[2] & 0xD0) >> 6)]; |
|
446 |
102244 |
output[3] = table[input[2] & 0x3F]; |
|
447 |
102244 |
} |
|
448 |
|||
449 |
9105 |
string Base64(const string &data) { |
|
450 |
9105 |
string result; |
|
451 |
9105 |
result.reserve((data.length() + 3) * 4 / 3); |
|
452 |
9105 |
unsigned pos = 0; |
|
453 |
const unsigned char *data_ptr = |
||
454 |
9105 |
reinterpret_cast<const unsigned char *>(data.data()); |
|
455 |
9105 |
const unsigned length = data.length(); |
|
456 |
✓✓ | 111392 |
while (pos + 2 < length) { |
457 |
char encoded_block[4]; |
||
458 |
93182 |
Base64Block(data_ptr + pos, b64_table, encoded_block); |
|
459 |
93182 |
result.append(encoded_block, 4); |
|
460 |
93182 |
pos += 3; |
|
461 |
} |
||
462 |
✓✓ | 9105 |
if (length % 3 != 0) { |
463 |
unsigned char input[3]; |
||
464 |
9062 |
input[0] = data_ptr[pos]; |
|
465 |
✓✓ | 9062 |
input[1] = ((length % 3) == 2) ? data_ptr[pos + 1] : 0; |
466 |
9062 |
input[2] = 0; |
|
467 |
char encoded_block[4]; |
||
468 |
9062 |
Base64Block(input, b64_table, encoded_block); |
|
469 |
9062 |
result.append(encoded_block, 2); |
|
470 |
✓✓ | 9062 |
result.push_back(((length % 3) == 2) ? encoded_block[2] : '='); |
471 |
9062 |
result.push_back('='); |
|
472 |
} |
||
473 |
|||
474 |
9105 |
return result; |
|
475 |
} |
||
476 |
|||
477 |
/** |
||
478 |
* Safe encoding for URIs and path names: replace + by - and / by _ |
||
479 |
*/ |
||
480 |
5 |
string Base64Url(const string &data) { |
|
481 |
5 |
string base64 = Base64(data); |
|
482 |
✓✓ | 425 |
for (unsigned i = 0, l = base64.length(); i < l; ++i) { |
483 |
✓✓ | 420 |
if (base64[i] == '+') |
484 |
6 |
base64[i] = '-'; |
|
485 |
✓✓ | 414 |
else if (base64[i] == '/') |
486 |
4 |
base64[i] = '_'; |
|
487 |
} |
||
488 |
5 |
return base64; |
|
489 |
} |
||
490 |
|||
491 |
64482 |
static bool Debase64Block(const unsigned char input[4], |
|
492 |
const signed char *d_table, unsigned char output[3]) { |
||
493 |
int32_t dec[4]; |
||
494 |
✓✓ | 322406 |
for (int i = 0; i < 4; ++i) { |
495 |
257925 |
dec[i] = db64_table[input[i]]; |
|
496 |
✓✓ | 257925 |
if (dec[i] < 0) return false; |
497 |
} |
||
498 |
|||
499 |
64481 |
output[0] = (dec[0] << 2) | (dec[1] >> 4); |
|
500 |
64481 |
output[1] = ((dec[1] & 0x0F) << 4) | (dec[2] >> 2); |
|
501 |
64481 |
output[2] = ((dec[2] & 0x03) << 6) | dec[3]; |
|
502 |
64481 |
return true; |
|
503 |
} |
||
504 |
|||
505 |
/** |
||
506 |
* Can decode both base64 and base64url |
||
507 |
*/ |
||
508 |
167 |
bool Debase64(const string &data, string *decoded) { |
|
509 |
167 |
decoded->clear(); |
|
510 |
167 |
decoded->reserve((data.length() + 4) * 3 / 4); |
|
511 |
167 |
unsigned pos = 0; |
|
512 |
const unsigned char *data_ptr = |
||
513 |
167 |
reinterpret_cast<const unsigned char *>(data.data()); |
|
514 |
167 |
const unsigned length = data.length(); |
|
515 |
✓✓ | 167 |
if (length == 0) return true; |
516 |
✓✓ | 166 |
if ((length % 4) != 0) return false; |
517 |
|||
518 |
✓✓ | 64809 |
while (pos < length) { |
519 |
unsigned char decoded_block[3]; |
||
520 |
64482 |
bool retval = Debase64Block(data_ptr + pos, db64_table, decoded_block); |
|
521 |
✓✓ | 64482 |
if (!retval) return false; |
522 |
64481 |
decoded->append(reinterpret_cast<char *>(decoded_block), 3); |
|
523 |
64481 |
pos += 4; |
|
524 |
} |
||
525 |
|||
526 |
✓✓ | 489 |
for (int i = 0; i < 2; ++i) { |
527 |
326 |
pos--; |
|
528 |
✓✓ | 326 |
if (data[pos] == '=') decoded->erase(decoded->length() - 1); |
529 |
} |
||
530 |
163 |
return true; |
|
531 |
} |
||
532 |
|||
533 |
/** |
||
534 |
* Assumes that source is terminated by a newline |
||
535 |
*/ |
||
536 |
7 |
string Tail(const string &source, unsigned num_lines) { |
|
537 |
✓✓✓✓ ✓✓ |
7 |
if (source.empty() || (num_lines == 0)) return ""; |
538 |
|||
539 |
4 |
unsigned l = source.length(); |
|
540 |
4 |
int i = l - 1; |
|
541 |
✓✓ | 19 |
for (; i >= 0; --i) { |
542 |
16 |
char c = source.data()[i]; |
|
543 |
✓✓ | 16 |
if (c == '\n') { |
544 |
✓✓ | 5 |
if (num_lines == 0) { |
545 |
1 |
return source.substr(i + 1); |
|
546 |
} |
||
547 |
4 |
num_lines--; |
|
548 |
} |
||
549 |
} |
||
550 |
3 |
return source; |
|
551 |
} |
||
552 |
|||
553 |
/** |
||
554 |
* Get UTC Time. |
||
555 |
* |
||
556 |
* @return a timestamp in "YYYY-MM-DD HH:MM:SS" format |
||
557 |
*/ |
||
558 |
std::string GetGMTimestamp() { |
||
559 |
struct tm time_ptr; |
||
560 |
char date_and_time[50]; |
||
561 |
time_t t = time(NULL); |
||
562 |
gmtime_r(&t, &time_ptr); // take UTC |
||
563 |
// timestamp format |
||
564 |
strftime(date_and_time, 50, "%Y-%m-%d %H:%M:%S", &time_ptr); |
||
565 |
std::string timestamp(date_and_time); |
||
566 |
return timestamp; |
||
567 |
} |
||
568 |
|||
569 |
#ifdef CVMFS_NAMESPACE_GUARD |
||
570 |
} // namespace CVMFS_NAMESPACE_GUARD |
||
571 |
#endif |
Generated by: GCOVR (Version 4.1) |