GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/util/string.cc
Date: 2025-03-09 02:34:28
Exec Total Coverage
Lines: 288 301 95.7%
Branches: 267 387 69.0%

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 // NOLINTNEXTLINE
9 #define __STDC_FORMAT_MACROS
10 #endif
11
12 #include "string.h"
13
14
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <inttypes.h>
18 #include <stdint.h>
19 #include <unistd.h>
20
21 #include <cstdio>
22 #include <cstdlib>
23 #include <cstring>
24 #include <ctime>
25 #include <string>
26
27 using namespace std; // NOLINT
28
29 #ifdef CVMFS_NAMESPACE_GUARD
30 namespace CVMFS_NAMESPACE_GUARD {
31 #endif
32
33 const char b64_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
34 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
35 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
36 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
37 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
38 '3', '4', '5', '6', '7', '8', '9', '+', '/'};
39
40 /**
41 * Decode Base64 and Base64Url
42 */
43 const int8_t db64_table[] = {
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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
46 -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60,
47 61, -1, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
48 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1,
49 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
50 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
51
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, -1, -1, -1, -1, -1,
58 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
59 };
60
61 namespace {
62
63 /**
64 * Used for cas insensitive HasSuffix
65 */
66 struct IgnoreCaseComperator {
67 1009 IgnoreCaseComperator() {}
68 21 bool operator()(const std::string::value_type a,
69 const std::string::value_type b) const {
70 21 return std::tolower(a) == std::tolower(b);
71 }
72 };
73
74 } // anonymous namespace
75
76
3/4
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 98 times.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
102 string StringifyBool(const bool value) { return value ? "yes" : "no"; }
77
78 1237219 string StringifyInt(const int64_t value) {
79 char buffer[48];
80 1237219 snprintf(buffer, sizeof(buffer), "%" PRId64, value);
81
1/2
✓ Branch 2 taken 1239818 times.
✗ Branch 3 not taken.
1237219 return string(buffer);
82 }
83
84 366627 std::string StringifyUint(const uint64_t value) {
85 char buffer[48];
86 366627 snprintf(buffer, sizeof(buffer), "%" PRIu64, value);
87
1/2
✓ Branch 2 taken 366627 times.
✗ Branch 3 not taken.
366627 return string(buffer);
88 }
89
90 4 string StringifyByteAsHex(const unsigned char value) {
91 char buffer[3];
92 4 snprintf(buffer, sizeof(buffer), "%02x", value);
93
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 return string(buffer);
94 }
95
96 8 string StringifyDouble(const double value) {
97 char buffer[64];
98 8 snprintf(buffer, sizeof(buffer), "%.03f", value);
99
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 return string(buffer);
100 }
101
102 /**
103 * Converts seconds since UTC 0 into something readable
104 */
105 75 string StringifyTime(const time_t seconds, const bool utc) {
106 struct tm timestamp;
107
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 33 times.
75 if (utc) {
108 42 localtime_r(&seconds, &timestamp);
109 } else {
110 33 gmtime_r(&seconds, &timestamp);
111 }
112
113 75 const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
114 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
115 char buffer[21];
116 75 snprintf(buffer, sizeof(buffer), "%d %s %d %02d:%02d:%02d", timestamp.tm_mday,
117 75 months[timestamp.tm_mon], timestamp.tm_year + 1900,
118 timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec);
119
120
1/2
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
75 return string(buffer);
121 }
122
123 /**
124 * Converts seconds since UTC 0 into something like 12 Sep 14:59:37 CDT
125 */
126 21 string StringifyLocalTime(const time_t seconds) {
127 struct tm timestamp;
128 21 localtime_r(&seconds, &timestamp);
129
130 21 const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
131 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
132 char buffer[26];
133 (void)/* cast to void ignores return and placates clang-tidy */
134 21 snprintf(buffer, sizeof(buffer), "%d %s %d %02d:%02d:%02d %s", timestamp.tm_mday,
135 21 months[timestamp.tm_mon], timestamp.tm_year + 1900,
136 timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec, timestamp.tm_zone);
137
138
1/2
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
21 return string(buffer);
139 }
140
141
142 /**
143 * Current time in format Wed, 01 Mar 2006 12:00:00 GMT
144 */
145 1399 std::string RfcTimestamp() {
146 1399 const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
147 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
148 1399 const char *day_of_week[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
149
150 struct tm timestamp;
151 1399 time_t now = time(NULL);
152 1399 gmtime_r(&now, &timestamp);
153
154 char buffer[30];
155 1399 snprintf(buffer, sizeof(buffer), "%s, %02d %s %d %02d:%02d:%02d %s",
156 1399 day_of_week[timestamp.tm_wday], timestamp.tm_mday,
157 1399 months[timestamp.tm_mon], timestamp.tm_year + 1900,
158 timestamp.tm_hour, timestamp.tm_min, timestamp.tm_sec,
159 timestamp.tm_zone);
160
1/2
✓ Branch 2 taken 1399 times.
✗ Branch 3 not taken.
1399 return string(buffer);
161 }
162
163
164 /**
165 * Current time in format YYYYMMDDTHHMMSSZ. Used in AWS4 requests.
166 */
167 1 std::string IsoTimestamp() {
168 struct tm timestamp;
169 1 time_t now = time(NULL);
170 1 gmtime_r(&now, &timestamp);
171
172 char buffer[17];
173 1 snprintf(buffer, sizeof(buffer), "%04d%02d%02dT%02d%02d%02dZ",
174 1 timestamp.tm_year + 1900,
175 1 timestamp.tm_mon + 1,
176 timestamp.tm_mday,
177 timestamp.tm_hour,
178 timestamp.tm_min,
179 timestamp.tm_sec);
180
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return string(buffer);
181 }
182
183
184 /**
185 * UTC time in format YYYYMMDDHHMMSS. Used in cvmfs whitelists.
186 */
187 7 std::string WhitelistTimestamp(time_t when) {
188 struct tm timestamp;
189 7 gmtime_r(&when, &timestamp);
190
191 char buffer[15];
192 7 snprintf(buffer, sizeof(buffer), "%04d%02d%02d%02d%02d%02d",
193 7 timestamp.tm_year + 1900,
194 7 timestamp.tm_mon + 1,
195 timestamp.tm_mday,
196 timestamp.tm_hour,
197 timestamp.tm_min,
198 timestamp.tm_sec);
199
1/2
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 return string(buffer);
200 }
201
202
203 372632 string StringifyTimeval(const timeval value) {
204 char buffer[64];
205 372632 int64_t msec = value.tv_sec * 1000;
206 372632 msec += value.tv_usec / 1000;
207 372632 snprintf(buffer, sizeof(buffer), "%" PRId64 ".%03d", msec,
208 372632 static_cast<int>(value.tv_usec % 1000));
209
1/2
✓ Branch 2 taken 372632 times.
✗ Branch 3 not taken.
372632 return string(buffer);
210 }
211
212 /**
213 * Parses a timestamp of the form YYYY-MM-DDTHH:MM:SSZ
214 * Return 0 on error
215 */
216 108 time_t IsoTimestamp2UtcTime(const std::string &iso8601) {
217 108 time_t utc_time = 0;
218 108 unsigned length = iso8601.length();
219
220
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 106 times.
108 if (length != 20) return utc_time;
221
2/4
✓ Branch 2 taken 106 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 106 times.
✗ Branch 6 not taken.
212 if ((iso8601[4] != '-') || (iso8601[7] != '-') || (iso8601[10] != 'T') ||
222
5/10
✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 106 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 106 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 106 times.
212 (iso8601[13] != ':') || (iso8601[16] != ':') || (iso8601[19] != 'Z')) {
223 return utc_time;
224 }
225
226 struct tm tm_wl;
227 106 memset(&tm_wl, 0, sizeof(struct tm));
228
2/4
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
106 tm_wl.tm_year = static_cast<int>(String2Int64(iso8601.substr(0, 4))) - 1900;
229
2/4
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
106 tm_wl.tm_mon = static_cast<int>(String2Int64(iso8601.substr(5, 2))) - 1;
230
2/4
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
106 tm_wl.tm_mday = static_cast<int>(String2Int64(iso8601.substr(8, 2)));
231
2/4
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
106 tm_wl.tm_hour = static_cast<int>(String2Int64(iso8601.substr(11, 2)));
232
2/4
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
106 tm_wl.tm_min = static_cast<int>(String2Int64(iso8601.substr(14, 2)));
233
2/4
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
106 tm_wl.tm_sec = static_cast<int>(String2Int64(iso8601.substr(17, 2)));
234 106 utc_time = timegm(&tm_wl);
235
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 105 times.
106 if (utc_time < 0) return 0;
236
237 105 return utc_time;
238 }
239
240 1442 int64_t String2Int64(const string &value) {
241 int64_t result;
242 1442 sscanf(value.c_str(), "%" PRId64, &result);
243 1442 return result;
244 }
245
246 10358 uint64_t String2Uint64(const string &value) {
247 uint64_t result;
248
2/2
✓ Branch 1 taken 10354 times.
✓ Branch 2 taken 4 times.
10358 if (sscanf(value.c_str(), "%" PRIu64, &result) == 1) {
249 10354 return result;
250 }
251 4 return 0;
252 }
253
254 /**
255 * Parse a string into a a uint64_t.
256 *
257 * Unlike String2Uint64, this:
258 * - Checks to make sure the full string is parsed
259 * - Can indicate an error occurred.
260 *
261 * If an error occurs, this returns false and sets errno appropriately.
262 */
263 304 bool String2Uint64Parse(const std::string &value, uint64_t *result) {
264 304 char *endptr = NULL;
265 304 errno = 0;
266 304 long long myval = strtoll(value.c_str(), &endptr, 10); // NOLINT
267
8/8
✓ Branch 1 taken 299 times.
✓ Branch 2 taken 5 times.
✓ Branch 5 taken 260 times.
✓ Branch 6 taken 39 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 259 times.
✓ Branch 9 taken 45 times.
✓ Branch 10 taken 259 times.
304 if ((value.size() == 0) || (endptr != (value.c_str() + value.size())) ||
268 (myval < 0)) {
269 45 errno = EINVAL;
270 45 return false;
271 }
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 259 times.
259 if (errno) {
273 return false;
274 }
275
2/2
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 1 times.
259 if (result) {
276 258 *result = myval;
277 }
278 259 return true;
279 }
280
281 4 void String2Uint64Pair(const string &value, uint64_t *a, uint64_t *b) {
282 4 sscanf(value.c_str(), "%" PRIu64 " %" PRIu64, a, b);
283 4 }
284
285 8353 bool HasPrefix(const string &str, const string &prefix,
286 const bool ignore_case) {
287
2/2
✓ Branch 2 taken 1686 times.
✓ Branch 3 taken 6667 times.
8353 if (prefix.length() > str.length()) return false;
288
289
2/2
✓ Branch 1 taken 24331 times.
✓ Branch 2 taken 2143 times.
26474 for (unsigned i = 0, l = prefix.length(); i < l; ++i) {
290
2/2
✓ Branch 0 taken 4117 times.
✓ Branch 1 taken 20214 times.
24331 if (ignore_case) {
291
2/2
✓ Branch 2 taken 2167 times.
✓ Branch 3 taken 1950 times.
4117 if (toupper(str[i]) != toupper(prefix[i])) return false;
292 } else {
293
2/2
✓ Branch 2 taken 2357 times.
✓ Branch 3 taken 17857 times.
20214 if (str[i] != prefix[i]) return false;
294 }
295 }
296 2143 return true;
297 }
298
299 1019 bool HasSuffix(const std::string &str, const std::string &suffix,
300 const bool ignore_case) {
301
2/2
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 1009 times.
1019 if (suffix.size() > str.size()) return false;
302 1009 const IgnoreCaseComperator icmp;
303 return (ignore_case)
304
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 996 times.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
1009 ? std::equal(suffix.rbegin(), suffix.rend(), str.rbegin(), icmp)
305
1/2
✓ Branch 4 taken 996 times.
✗ Branch 5 not taken.
1009 : std::equal(suffix.rbegin(), suffix.rend(), str.rbegin());
306 }
307
308 1948 vector<string> SplitString(const string &str, char delim) {
309 1948 return SplitStringBounded(0, str, delim);
310 }
311
312 1954 vector<string> SplitStringBounded(
313 unsigned max_chunks, const string &str, char delim)
314 {
315 1954 vector<string> result;
316
317 // edge case... one chunk is always the whole string
318
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1953 times.
1954 if (1 == max_chunks) {
319
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 result.push_back(str);
320 1 return result;
321 }
322
323 // split the string
324 1953 const unsigned size = str.size();
325 1953 unsigned marker = 0;
326 1953 unsigned chunks = 1;
327 unsigned i;
328
2/2
✓ Branch 0 taken 45678 times.
✓ Branch 1 taken 1951 times.
47629 for (i = 0; i < size; ++i) {
329
2/2
✓ Branch 1 taken 3117 times.
✓ Branch 2 taken 42561 times.
45678 if (str[i] == delim) {
330
2/4
✓ Branch 1 taken 3117 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3117 times.
✗ Branch 5 not taken.
3117 result.push_back(str.substr(marker, i - marker));
331 3117 marker = i + 1;
332
333 // we got what we want... good bye
334
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3115 times.
3117 if (++chunks == max_chunks) break;
335 }
336 }
337
338 // push the remainings of the string and return
339
2/4
✓ Branch 1 taken 1953 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1953 times.
✗ Branch 5 not taken.
1953 result.push_back(str.substr(marker));
340 1953 return result;
341 }
342
343 320 string JoinStrings(const vector<string> &strings, const string &joint) {
344
1/2
✓ Branch 2 taken 320 times.
✗ Branch 3 not taken.
320 string result = "";
345 320 const unsigned size = strings.size();
346
347
2/2
✓ Branch 0 taken 239 times.
✓ Branch 1 taken 81 times.
320 if (size > 0) {
348
1/2
✓ Branch 2 taken 239 times.
✗ Branch 3 not taken.
239 result = strings[0];
349
4/7
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 32 times.
✓ Branch 9 taken 239 times.
271 for (unsigned i = 1; i < size; ++i) result += joint + strings[i];
350 }
351
352 320 return result;
353 }
354
355 113 void ParseKeyvalMem(const unsigned char *buffer, const unsigned buffer_size,
356 map<char, string> *content) {
357 113 string line;
358 113 unsigned pos = 0;
359
2/2
✓ Branch 0 taken 9588 times.
✓ Branch 1 taken 2 times.
9590 while (pos < buffer_size) {
360
2/2
✓ Branch 0 taken 750 times.
✓ Branch 1 taken 8838 times.
9588 if (static_cast<char>(buffer[pos]) == '\n') {
361
2/2
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 639 times.
750 if (line == "--") return;
362
363
1/2
✓ Branch 1 taken 639 times.
✗ Branch 2 not taken.
639 if (line != "") {
364
3/11
✗ Branch 1 not taken.
✓ Branch 2 taken 639 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 639 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 639 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
639 const string tail = (line.length() == 1) ? "" : line.substr(1);
365 // Special handling of 'Z' key because it can exist multiple times
366
3/4
✓ Branch 1 taken 639 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 635 times.
✓ Branch 4 taken 4 times.
639 if (line[0] != 'Z') {
367
3/6
✓ Branch 1 taken 635 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 635 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 635 times.
✗ Branch 8 not taken.
635 (*content)[line[0]] = tail;
368 } else {
369
4/7
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
4 if (content->find(line[0]) == content->end()) {
370
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
2 (*content)[line[0]] = tail;
371 } else {
372
6/12
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
2 (*content)[line[0]] = (*content)[line[0]] + "|" + tail;
373 }
374 }
375 639 }
376
1/2
✓ Branch 1 taken 639 times.
✗ Branch 2 not taken.
639 line = "";
377 } else {
378
1/2
✓ Branch 1 taken 8838 times.
✗ Branch 2 not taken.
8838 line += static_cast<char>(buffer[pos]);
379 }
380 9477 pos++;
381 }
382
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 111 times.
113 }
383
384 12 bool ParseKeyvalPath(const string &filename, map<char, string> *content) {
385
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 int fd = open(filename.c_str(), O_RDONLY);
386
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (fd < 0) return false;
387
388 unsigned char buffer[4096];
389
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 ssize_t num_bytes = read(fd, buffer, sizeof(buffer));
390
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 close(fd);
391
392
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
11 if ((num_bytes <= 0) || (unsigned(num_bytes) >= sizeof(buffer))) return false;
393
394
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 ParseKeyvalMem(buffer, unsigned(num_bytes), content);
395 10 return true;
396 }
397
398 6648 string GetLineMem(const char *text, const int text_size) {
399 6648 int pos = 0;
400
4/4
✓ Branch 0 taken 278400 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 271773 times.
✓ Branch 3 taken 6627 times.
278421 while ((pos < text_size) && (text[pos] != '\n')) pos++;
401
1/2
✓ Branch 2 taken 6648 times.
✗ Branch 3 not taken.
6648 return string(text, pos);
402 }
403
404 373843 bool GetLineFile(FILE *f, std::string *line) {
405 int retval;
406 373843 line->clear();
407 while (true) {
408 26645569 retval = fgetc(f);
409
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 26645569 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 26645569 times.
26645569 if (ferror(f) && (errno == EINTR)) {
410 clearerr(f);
411 continue;
412
2/2
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 26645354 times.
26645569 } else if (retval == EOF) {
413 215 break;
414 }
415 26645354 char c = static_cast<char>(retval);
416
2/2
✓ Branch 0 taken 373628 times.
✓ Branch 1 taken 26271726 times.
26645354 if (c == '\n') break;
417 26271726 line->push_back(c);
418 26271726 }
419
4/4
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 373628 times.
✓ Branch 3 taken 37 times.
✓ Branch 4 taken 178 times.
373843 return (retval != EOF) || !line->empty();
420 }
421
422 199 bool GetLineFd(const int fd, std::string *line) {
423 ssize_t retval;
424 char c;
425 199 line->clear();
426 while (true) {
427
1/2
✓ Branch 1 taken 9092 times.
✗ Branch 2 not taken.
9092 retval = read(fd, &c, 1);
428
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9089 times.
9092 if (retval == 0) {
429 3 break;
430 }
431
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9089 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9089 if ((retval == -1) && (errno == EINTR)) {
432 continue;
433 }
434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9089 times.
9089 if (retval == -1) {
435 break;
436 }
437
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 8893 times.
9089 if (c == '\n') break;
438
1/2
✓ Branch 1 taken 8893 times.
✗ Branch 2 not taken.
8893 line->push_back(c);
439 }
440
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 196 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
199 return (retval == 1) || !line->empty();
441 }
442
443 /**
444 * Removes leading and trailing whitespaces.
445 */
446 975 string Trim(const string &raw, bool trim_newline) {
447
3/4
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 892 times.
✓ Branch 5 taken 83 times.
✗ Branch 6 not taken.
975 if (raw.empty()) return "";
448
449 892 unsigned start_pos = 0;
450
4/4
✓ Branch 1 taken 961 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 81 times.
✓ Branch 4 taken 892 times.
1865 for (; (start_pos < raw.length()) &&
451
5/6
✓ Branch 1 taken 905 times.
✓ Branch 2 taken 56 times.
✓ Branch 4 taken 905 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 106 times.
✓ Branch 7 taken 799 times.
961 (raw[start_pos] == ' ' || raw[start_pos] == '\t' ||
452
4/4
✓ Branch 1 taken 94 times.
✓ Branch 2 taken 12 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 81 times.
106 (trim_newline && (raw[start_pos] == '\n' || raw[start_pos] == '\r')));
453 ++start_pos)
454 {
455 }
456 892 unsigned end_pos = raw.length() - 1; // at least one character in raw
457 1096 for (;
458
4/4
✓ Branch 0 taken 1084 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 204 times.
✓ Branch 3 taken 892 times.
2180 (end_pos >= start_pos) &&
459
5/6
✓ Branch 1 taken 1029 times.
✓ Branch 2 taken 55 times.
✓ Branch 4 taken 1029 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 230 times.
✓ Branch 7 taken 799 times.
1084 (raw[end_pos] == ' ' || raw[end_pos] == '\t' ||
460
4/4
✓ Branch 1 taken 145 times.
✓ Branch 2 taken 85 times.
✓ Branch 4 taken 64 times.
✓ Branch 5 taken 81 times.
230 (trim_newline && (raw[end_pos] == '\n' || raw[end_pos] == '\r')));
461 --end_pos)
462 {
463 }
464
465 892 return raw.substr(start_pos, end_pos - start_pos + 1);
466 }
467
468 4 std::string TrimString(
469 const std::string& path,
470 const std::string& toTrim,
471 const int trimMode)
472 {
473 4 std::string trimmed = path;
474
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if (trimmed != toTrim) {
475
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
4 while ((trimMode & kTrimLeading) &&
476
8/10
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
✓ Branch 10 taken 4 times.
16 HasPrefix(trimmed, toTrim, true) &&
477 6 (trimmed.size() > toTrim.size()))
478 {
479
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 trimmed = trimmed.substr(toTrim.size());
480 }
481
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
4 while ((trimMode & kTrimTrailing) &&
482
8/10
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 4 times.
12 HasSuffix(trimmed, toTrim, true) &&
483 4 (trimmed.size() > toTrim.size()))
484 {
485
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 trimmed = trimmed.substr(0, trimmed.size() - toTrim.size());
486 }
487 }
488 4 return trimmed;
489 }
490
491 /**
492 * Converts all characters to upper case
493 */
494 95 string ToUpper(const string &mixed_case) {
495 95 string result(mixed_case);
496
2/2
✓ Branch 1 taken 240 times.
✓ Branch 2 taken 95 times.
335 for (unsigned i = 0, l = result.length(); i < l; ++i) {
497
2/4
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 240 times.
✗ Branch 5 not taken.
240 result[i] = static_cast<char>(toupper(result[i]));
498 }
499 95 return result;
500 }
501
502 101 string ReplaceAll(const string &haystack, const string &needle,
503 const string &replace_by) {
504 101 string result(haystack);
505 101 size_t pos = 0;
506 101 const unsigned needle_size = needle.size();
507
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 100 times.
101 if (needle == "") return result;
508
509
2/2
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 100 times.
168 while ((pos = result.find(needle, pos)) != string::npos)
510
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 result.replace(pos, needle_size, replace_by);
511 100 return result;
512 }
513
514 16052 static inline void Base64Block(const unsigned char input[3], const char *table,
515 char output[4]) {
516 16052 output[0] = table[(input[0] & 0xFD) >> 2];
517 16052 output[1] = table[((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4)];
518 16052 output[2] = table[((input[1] & 0x0F) << 2) | ((input[2] & 0xD0) >> 6)];
519 16052 output[3] = table[input[2] & 0x3F];
520 16052 }
521
522 1878 string Base64(const string &data) {
523 1878 string result;
524
1/2
✓ Branch 2 taken 1878 times.
✗ Branch 3 not taken.
1878 result.reserve((data.length() + 3) * 4 / 3);
525 1878 unsigned pos = 0;
526 const unsigned char *data_ptr =
527 1878 reinterpret_cast<const unsigned char *>(data.data());
528 1878 const unsigned length = data.length();
529
2/2
✓ Branch 0 taken 14191 times.
✓ Branch 1 taken 1878 times.
16069 while (pos + 2 < length) {
530 char encoded_block[4];
531 14191 Base64Block(data_ptr + pos, b64_table, encoded_block);
532
1/2
✓ Branch 1 taken 14191 times.
✗ Branch 2 not taken.
14191 result.append(encoded_block, 4);
533 14191 pos += 3;
534 }
535
2/2
✓ Branch 0 taken 1861 times.
✓ Branch 1 taken 17 times.
1878 if (length % 3 != 0) {
536 unsigned char input[3];
537 1861 input[0] = data_ptr[pos];
538
2/2
✓ Branch 0 taken 1243 times.
✓ Branch 1 taken 618 times.
1861 input[1] = ((length % 3) == 2) ? data_ptr[pos + 1] : 0;
539 1861 input[2] = 0;
540 char encoded_block[4];
541 1861 Base64Block(input, b64_table, encoded_block);
542
1/2
✓ Branch 1 taken 1861 times.
✗ Branch 2 not taken.
1861 result.append(encoded_block, 2);
543
3/4
✓ Branch 0 taken 1243 times.
✓ Branch 1 taken 618 times.
✓ Branch 3 taken 1861 times.
✗ Branch 4 not taken.
1861 result.push_back(((length % 3) == 2) ? encoded_block[2] : '=');
544
1/2
✓ Branch 1 taken 1861 times.
✗ Branch 2 not taken.
1861 result.push_back('=');
545 }
546
547 1878 return result;
548 }
549
550 /**
551 * Safe encoding for URIs and path names: replace + by - and / by _
552 */
553 5 string Base64Url(const string &data) {
554 5 string base64 = Base64(data);
555
2/2
✓ Branch 1 taken 420 times.
✓ Branch 2 taken 5 times.
425 for (unsigned i = 0, l = base64.length(); i < l; ++i) {
556
3/4
✓ Branch 1 taken 420 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 414 times.
420 if (base64[i] == '+') {
557
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 base64[i] = '-';
558
3/4
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 410 times.
414 } else if (base64[i] == '/') {
559
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 base64[i] = '_';
560 }
561 }
562 5 return base64;
563 }
564
565 29434 static bool Debase64Block(const unsigned char input[4], unsigned char output[3])
566 {
567 int32_t dec[4];
568
2/2
✓ Branch 0 taken 117733 times.
✓ Branch 1 taken 29433 times.
147166 for (int i = 0; i < 4; ++i) {
569 117733 dec[i] = db64_table[input[i]];
570
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 117732 times.
117733 if (dec[i] < 0) return false;
571 }
572
573 29433 output[0] = (dec[0] << 2) | (dec[1] >> 4);
574 29433 output[1] = ((dec[1] & 0x0F) << 4) | (dec[2] >> 2);
575 29433 output[2] = ((dec[2] & 0x03) << 6) | dec[3];
576 29433 return true;
577 }
578
579 /**
580 * Can decode both base64 and base64url
581 */
582 143 bool Debase64(const string &data, string *decoded) {
583 143 decoded->clear();
584 143 decoded->reserve((data.length() + 4) * 3 / 4);
585 143 unsigned pos = 0;
586 const unsigned char *data_ptr =
587 143 reinterpret_cast<const unsigned char *>(data.data());
588 143 const unsigned length = data.length();
589
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 142 times.
143 if (length == 0) return true;
590
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 140 times.
142 if ((length % 4) != 0) return false;
591
592
2/2
✓ Branch 0 taken 29434 times.
✓ Branch 1 taken 139 times.
29573 while (pos < length) {
593 unsigned char decoded_block[3];
594 29434 bool retval = Debase64Block(data_ptr + pos, decoded_block);
595
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 29433 times.
29434 if (!retval) return false;
596
1/2
✓ Branch 1 taken 29433 times.
✗ Branch 2 not taken.
29433 decoded->append(reinterpret_cast<char *>(decoded_block), 3);
597 29433 pos += 4;
598 }
599
600
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 139 times.
417 for (int i = 0; i < 2; ++i) {
601 278 pos--;
602
2/2
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 228 times.
278 if (data[pos] == '=') decoded->erase(decoded->length() - 1);
603 }
604 139 return true;
605 }
606
607 /**
608 * Assumes that source is terminated by a newline
609 */
610 7 string Tail(const string &source, unsigned num_lines) {
611
7/8
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 4 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
7 if (source.empty() || (num_lines == 0)) return "";
612
613 4 int l = static_cast<int>(source.length());
614 4 int i = l - 1;
615
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 3 times.
19 for (; i >= 0; --i) {
616 16 char c = source.data()[i];
617
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 11 times.
16 if (c == '\n') {
618
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (num_lines == 0) {
619 1 return source.substr(i + 1);
620 }
621 4 num_lines--;
622 }
623 }
624 3 return source;
625 }
626
627 /**
628 * Get UTC Time.
629 *
630 * @param format format if timestamp (YYYY-MM-DD HH:MM:SS by default)
631 * @return a timestamp string on success, empty string on failure
632 */
633 std::string GetGMTimestamp(const std::string &format) {
634 struct tm time_ptr;
635 char date_and_time[100];
636 time_t t = time(NULL);
637 gmtime_r(&t, &time_ptr); // take UTC
638 // return empty string if formatting fails
639 if (!strftime(date_and_time, 100, format.c_str(), &time_ptr)) {
640 return "";
641 }
642 std::string timestamp(date_and_time);
643 return timestamp;
644 }
645
646 #ifdef CVMFS_NAMESPACE_GUARD
647 } // namespace CVMFS_NAMESPACE_GUARD
648 #endif
649