libutil++  1.9.3
 All Classes Functions Variables
String.cpp
1 /*
2 ** libutil++
3 ** $Id: String.cpp 1911 2017-09-02 17:37:35Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: String.cpp 1911 2017-09-02 17:37:35Z sella $";
10 
11 #include "String.h"
12 #include "Crypt.h"
13 #include "Time.h"
14 #include "../variant/Variant.h"
15 
16 #include <lz4.h>
17 #include <zlib.h>
18 #include <math.h>
19 #include <string.h>
20 #include <sstream>
21 
22 #include <endian.h>
23 
24 #include <cctype>
25 #include <algorithm>
26 
27 #include <boost/algorithm/string/replace.hpp>
28 
29 #define BUFFER_SIZE (1024 * 32)
30 #define CHUNK 65536
31 
32 using namespace sella::util;
33 
34 union magic {
35  uint16_t u16;
36  uint32_t u32;
37 };
38 
39 struct lz4 { /* Non-streaming header */
40  uint32_t magic;
41  uint32_t size;
42  char data[];
43 } __attribute__((packed));
44 
45 static const unsigned char gzip_header[] = {
46  0x1f, 0x8b, Z_DEFLATED, 0,
47  0, 0, 0, 0, /* mtime */
48  0, 0x03 /* Unix OS_CODE */
49 };
50 
51 std::string String::sprintf(const char* format, ...) throw () {
52  va_list args;
53 
54  va_start(args, format);
55  std::string buffer = vsprintf(format, args);
56  va_end(args);
57 
58  return buffer;
59 }
60 
61 std::string String::sprintf(const std::string &format, ...) throw () {
62  va_list args;
63 
64  va_start(args, format);
65  std::string buffer = vsprintf(format.c_str(), args);
66  va_end(args);
67 
68  return buffer;
69 }
70 
71 std::string String::vsprintf(const char* format, va_list args) throw () {
72  char buffer[BUFFER_SIZE];
73 
74  vsnprintf(buffer, sizeof(buffer), format, args);
75 
76  return buffer;
77 }
78 
79 std::string String::vsprintf(const std::string &format, va_list args) throw () {
80  char buffer[BUFFER_SIZE];
81 
82  vsnprintf(buffer, sizeof(buffer), format.c_str(), args);
83 
84  return std::string(buffer);
85 }
86 
87 int String::strcmp(const std::string &a, const std::string &b) throw () {
88  size_t len = std::min(a.size(), b.size());
89 
90  for (size_t i = 0; i < len; i++) {
91  if (a[i] != b[i]) {
92  return (a[i] - b[i]);
93  }
94  }
95 
96  if (a.size() != b.size()) {
97  return (a.size() - b.size());
98  }
99 
100  return 0;
101 }
102 
103 int String::strcasecmp(const std::string &a, const std::string &b) throw () {
104  size_t len = std::min(a.size(), b.size());
105 
106  for (size_t i = 0; i < len; i++) {
107  if (std::tolower(a[i]) != std::tolower(b[i])) {
108  return (a[i] - b[i]);
109  }
110  }
111 
112  if (a.size() != b.size()) {
113  return (a.size() - b.size());
114  }
115 
116  return 0;
117 }
118 
119 int String::strncmp(const std::string &a, const std::string &b, size_t len) throw () {
120  size_t size = std::min(std::min(a.size(), b.size()), len);
121 
122  for (size_t i = 0; i < size; i++) {
123  if (a[i] != b[i]) {
124  return (a[i] - b[i]);
125  }
126  }
127 
128  if (len != size && a.size() != b.size()) {
129  return (a.size() - b.size());
130  }
131 
132  return 0;
133 }
134 
135 int String::strncasecmp(const std::string &a, const std::string &b, size_t len) throw () {
136  size_t size = std::min(std::min(a.size(), b.size()), len);
137 
138  for (size_t i = 0; i < size; i++) {
139  if (std::tolower(a[i]) != std::tolower(b[i])) {
140  return (a[i] - b[i]);
141  }
142  }
143 
144  if (len != size && a.size() != b.size()) {
145  return (a.size() - b.size());
146  }
147 
148  return 0;
149 }
150 
151 bool String::str_imatch(const std::string &a, const std::string &b) throw () {
152  if (a.size() != b.size()) {
153  return false;
154  }
155 
156  size_t len = std::min(a.size(), b.size());
157 
158  for (size_t i = 0; i < len; i++) {
159  if (std::tolower(a[i]) != std::tolower(b[i])) {
160  return false;
161  }
162  }
163 
164  return true;
165 }
166 
167 std::string String::substr_replace(const std::string &src, const std::string &search, const std::string &replace, bool global) throw () {
168  size_t i = 0, inc = (replace.length()) ? replace.length() : 1;
169  std::string dst = src;
170 
171  if (!search.empty()) {
172  while (true) {
173  if ((i = dst.find(search, i)) == std::string::npos) {
174  break;
175  }
176 
177  dst.replace(i, search.length(), replace);
178 
179  if (!global) break;
180 
181  i += inc;
182  }
183  }
184 
185  return dst;
186 }
187 
188 std::string& String::substr_replace(std::string &src, const std::string &search, const std::string &replace, bool global) throw () {
189  size_t i = 0, inc = (replace.length()) ? replace.length() : 1;
190 
191  if (!search.empty()) {
192  while (true) {
193  if ((i = src.find(search, i)) == std::string::npos) {
194  break;
195  }
196 
197  src.replace(i, search.length(), replace);
198 
199  if (!global) break;
200 
201  i += inc;
202  }
203  }
204 
205  return src;
206 }
207 
208 std::string String::substr_ireplace(const std::string &src, const std::string &search, const std::string &replace, bool global) throw () {
209  if (global) {
210  return boost::algorithm::ireplace_all_copy(src, search, replace);
211  } else {
212  return boost::algorithm::ireplace_first_copy(src, search, replace);
213  }
214 }
215 
216 std::string& String::substr_ireplace(std::string &src, const std::string &search, const std::string &replace, bool global) throw () {
217  if (global) {
218  boost::algorithm::ireplace_all(src, search, replace);
219  } else {
220  boost::algorithm::ireplace_first(src, search, replace);
221  }
222 
223  return src;
224 }
225 
226 std::string String::escape_percent(const std::string &src) throw () {
227  return substr_replace(src, "%", "%%");
228 }
229 
230 std::string String::escape(const std::string &src, const std::string &chars, const std::string &escape) throw () {
231  std::string result;
232  bool found;
233 
234  for (auto s = src.begin(), end = src.end(); s != end; ++s) {
235  found = false;
236 
237  for (auto c = chars.begin(), end = chars.end(); c != end; ++c) {
238  if (*c == *s) {
239  result += escape + *s;
240  found = true;
241 
242  break;
243  }
244  }
245 
246  if (!found) {
247  result += *s;
248  }
249  }
250  return result;
251 }
252 
253 std::string String::regex_replace(const std::string &src, const boost::regex &regex, const std::string &replace, MatchFlag mFlags) throw (RegexException) {
254  try {
255  return boost::regex_replace(src, regex, replace, mFlags);
256  } catch (boost::bad_expression &e) {
257  RETHROW_CODE(RegexException, 0, e);
258  } catch (std::exception &e) {
259  RETHROW_CODE(RegexException, 0, e);
260  }
261 }
262 
263 std::string String::regex_replace(const std::string &src, const std::string &regex, const std::string &replace, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
264  try {
265  const boost::regex rx(regex, reFlags);
266 
267  return boost::regex_replace(src, rx, replace, mFlags);
268  } catch (boost::bad_expression &e) {
269  RETHROW_CODE(RegexException, 0, e);
270  } catch (std::exception &e) {
271  RETHROW_CODE(RegexException, 0, e);
272  }
273 }
274 
275 std::string& String::regex_replace(std::string &src, const boost::regex &regex, const std::string &replace, MatchFlag mFlags) throw (RegexException) {
276  try {
277  src = boost::regex_replace(src, regex, replace, mFlags);
278 
279  return src;
280  } catch (boost::bad_expression &e) {
281  RETHROW_CODE(RegexException, 0, e);
282  } catch (std::exception &e) {
283  RETHROW_CODE(RegexException, 0, e);
284  }
285 }
286 
287 std::string& String::regex_replace(std::string &src, const std::string &regex, const std::string &replace, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
288  try {
289  const boost::regex rx(regex, reFlags);
290 
291  src = boost::regex_replace(src, rx, replace, mFlags);
292 
293  return src;
294  } catch (boost::bad_expression &e) {
295  RETHROW_CODE(RegexException, 0, e);
296  } catch (std::exception &e) {
297  RETHROW_CODE(RegexException, 0, e);
298  }
299 }
300 
301 std::string String::regex_ireplace(const std::string &src, const boost::regex &regex, const std::string &replace, MatchFlag mFlags) throw (RegexException) {
302  try {
303  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
304 
305  return regex_replace(src, rx, replace, mFlags);
306  } catch (boost::bad_expression &e) {
307  RETHROW_CODE(RegexException, 0, e);
308  } catch (std::exception &e) {
309  RETHROW_CODE(RegexException, 0, e);
310  }
311 }
312 
313 std::string String::regex_ireplace(const std::string &src, const std::string &regex, const std::string &replace, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
314  try {
315  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
316 
317  return regex_replace(src, rx, replace, mFlags);
318  } catch (boost::bad_expression &e) {
319  RETHROW_CODE(RegexException, 0, e);
320  } catch (std::exception &e) {
321  RETHROW_CODE(RegexException, 0, e);
322  }
323 }
324 
325 std::string& String::regex_ireplace(std::string &src, const boost::regex &regex, const std::string &replace, MatchFlag mFlags) throw (RegexException) {
326  try {
327  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
328 
329  return regex_replace(src, rx, replace, mFlags);
330  } catch (boost::bad_expression &e) {
331  RETHROW_CODE(RegexException, 0, e);
332  } catch (std::exception &e) {
333  RETHROW_CODE(RegexException, 0, e);
334  }
335 }
336 
337 std::string& String::regex_ireplace(std::string &src, const std::string &regex, const std::string &replace, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
338  try {
339  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
340 
341  return regex_replace(src, rx, replace, mFlags);
342  } catch (boost::bad_expression &e) {
343  RETHROW_CODE(RegexException, 0, e);
344  } catch (std::exception &e) {
345  RETHROW_CODE(RegexException, 0, e);
346  }
347 }
348 
349 bool String::regex_match(const std::string &src, const boost::regex &regex, MatchFlag mFlags) throw (RegexException) {
350  try {
351  return boost::regex_match(src, regex, mFlags);
352  } catch (boost::bad_expression &e) {
353  RETHROW_CODE(RegexException, 0, e);
354  } catch (std::exception &e) {
355  RETHROW_CODE(RegexException, 0, e);
356  }
357 }
358 
359 bool String::regex_match(const std::string &src, const std::string &regex, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
360  try {
361  const boost::regex rx(regex, reFlags);
362 
363  return regex_match(src, rx, mFlags);
364  } catch (boost::bad_expression &e) {
365  RETHROW_CODE(RegexException, 0, e);
366  } catch (std::exception &e) {
367  RETHROW_CODE(RegexException, 0, e);
368  }
369 }
370 
371 bool String::regex_match(const std::string &src, const boost::regex &regex, boost::cmatch &matches, MatchFlag mFlags) throw (RegexException) {
372  try {
373  return boost::regex_match(src.c_str(), matches, regex);
374  } catch (boost::bad_expression &e) {
375  RETHROW_CODE(RegexException, 0, e);
376  } catch (std::exception &e) {
377  RETHROW_CODE(RegexException, 0, e);
378  }
379 }
380 
381 bool String::regex_match(const std::string &src, const std::string &regex, boost::cmatch &matches, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
382  try {
383  const boost::regex rx(regex, reFlags);
384 
385  return regex_match(src, rx, matches, mFlags);
386  } catch (boost::bad_expression &e) {
387  RETHROW_CODE(RegexException, 0, e);
388  } catch (std::exception &e) {
389  RETHROW_CODE(RegexException, 0, e);
390  }
391 }
392 
393 bool String::regex_match(const std::string &src, const boost::regex &regex, std::string &match, MatchFlag mFlags) throw (RegexException) {
394  boost::cmatch m;
395 
396  if (regex_match(src, regex, m, mFlags)) {
397  match = m[0];
398 
399  return true;
400  }
401 
402  return false;
403 }
404 
405 bool String::regex_match(const std::string &src, const std::string &regex, std::string &match, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
406  try {
407  const boost::regex rx(regex, reFlags);
408 
409  return regex_match(src, rx, match, mFlags);
410  } catch (boost::bad_expression &e) {
411  RETHROW_CODE(RegexException, 0, e);
412  } catch (std::exception &e) {
413  RETHROW_CODE(RegexException, 0, e);
414  }
415 }
416 
417 bool String::regex_match(const std::string &src, const boost::regex &regex, std::vector<std::string> &matches, MatchFlag mFlags) throw (RegexException) {
418  boost::cmatch m;
419 
420  if (regex_match(src, regex, m, mFlags)) {
421  for (size_t i = 0; i < m.size(); i++) {
422  matches.push_back(m[i]);
423  }
424 
425  return true;
426  }
427 
428  return false;
429 }
430 
431 bool String::regex_match(const std::string &src, const std::string &regex, std::vector<std::string> &matches, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
432  try {
433  const boost::regex rx(regex, reFlags);
434 
435  return regex_match(src, rx, matches, mFlags);
436  } catch (boost::bad_expression &e) {
437  RETHROW_CODE(RegexException, 0, e);
438  } catch (std::exception &e) {
439  RETHROW_CODE(RegexException, 0, e);
440  }
441 }
442 
443 bool String::regex_imatch(const std::string &src, const boost::regex &regex, MatchFlag mFlags) throw (RegexException) {
444  try {
445  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
446 
447  return regex_match(src, rx, mFlags);
448  } catch (boost::bad_expression &e) {
449  RETHROW_CODE(RegexException, 0, e);
450  } catch (std::exception &e) {
451  RETHROW_CODE(RegexException, 0, e);
452  }
453 }
454 
455 bool String::regex_imatch(const std::string &src, const std::string &regex, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
456  try {
457  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
458 
459  return regex_match(src, rx, mFlags);
460  } catch (boost::bad_expression &e) {
461  RETHROW_CODE(RegexException, 0, e);
462  } catch (std::exception &e) {
463  RETHROW_CODE(RegexException, 0, e);
464  }
465 }
466 
467 bool String::regex_imatch(const std::string &src, const boost::regex &regex, boost::cmatch &matches, MatchFlag mFlags) throw (RegexException) {
468  try {
469  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
470 
471  return regex_match(src, rx, matches, mFlags);
472  } catch (boost::bad_expression &e) {
473  RETHROW_CODE(RegexException, 0, e);
474  } catch (std::exception &e) {
475  RETHROW_CODE(RegexException, 0, e);
476  }
477 }
478 
479 bool String::regex_imatch(const std::string &src, const std::string &regex, boost::cmatch &matches, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
480  try {
481  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
482 
483  return regex_match(src, rx, matches, mFlags);
484  } catch (boost::bad_expression &e) {
485  RETHROW_CODE(RegexException, 0, e);
486  } catch (std::exception &e) {
487  RETHROW_CODE(RegexException, 0, e);
488  }
489 }
490 
491 bool String::regex_imatch(const std::string &src, const boost::regex &regex, std::string &match, MatchFlag mFlags) throw (RegexException) {
492  try {
493  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
494 
495  return regex_match(src, rx, match, mFlags);
496  } catch (boost::bad_expression &e) {
497  RETHROW_CODE(RegexException, 0, e);
498  } catch (std::exception &e) {
499  RETHROW_CODE(RegexException, 0, e);
500  }
501 }
502 
503 bool String::regex_imatch(const std::string &src, const std::string &regex, std::string &match, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
504  try {
505  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
506 
507  return regex_match(src, rx, match, mFlags);
508  } catch (boost::bad_expression &e) {
509  RETHROW_CODE(RegexException, 0, e);
510  } catch (std::exception &e) {
511  RETHROW_CODE(RegexException, 0, e);
512  }
513 }
514 
515 bool String::regex_imatch(const std::string &src, const boost::regex &regex, std::vector<std::string> &matches, MatchFlag mFlags) throw (RegexException) {
516  try {
517  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
518 
519  return regex_match(src, rx, matches, mFlags);
520  } catch (boost::bad_expression &e) {
521  RETHROW_CODE(RegexException, 0, e);
522  } catch (std::exception &e) {
523  RETHROW_CODE(RegexException, 0, e);
524  }
525 }
526 
527 bool String::regex_imatch(const std::string &src, const std::string &regex, std::vector<std::string> &matches, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
528  try {
529  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
530 
531  return regex_match(src, rx, matches, mFlags);
532  } catch (boost::bad_expression &e) {
533  RETHROW_CODE(RegexException, 0, e);
534  } catch (std::exception &e) {
535  RETHROW_CODE(RegexException, 0, e);
536  }
537 }
538 
539 bool String::regex_search(const std::string &src, const boost::regex &regex, MatchFlag mFlags) throw (RegexException) {
540  try {
541  return boost::regex_search(src, regex, mFlags);
542  } catch (boost::bad_expression &e) {
543  RETHROW_CODE(RegexException, 0, e);
544  } catch (std::exception &e) {
545  RETHROW_CODE(RegexException, 0, e);
546  }
547 }
548 
549 bool String::regex_search(const std::string &src, const std::string &regex, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
550  try {
551  const boost::regex rx(regex, reFlags);
552 
553  return regex_search(src, rx, mFlags);
554  } catch (boost::bad_expression &e) {
555  RETHROW_CODE(RegexException, 0, e);
556  } catch (std::exception &e) {
557  RETHROW_CODE(RegexException, 0, e);
558  }
559 }
560 
561 bool String::regex_search(const std::string &src, const boost::regex &regex, boost::cmatch &matches, MatchFlag mFlags) throw (RegexException) {
562  try {
563  return boost::regex_search(src.c_str(), matches, regex);
564  } catch (boost::bad_expression &e) {
565  RETHROW_CODE(RegexException, 0, e);
566  } catch (std::exception &e) {
567  RETHROW_CODE(RegexException, 0, e);
568  }
569 }
570 
571 bool String::regex_search(const std::string &src, const std::string &regex, boost::cmatch &matches, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
572  try {
573  const boost::regex rx(regex, reFlags);
574 
575  return regex_search(src, rx, matches, mFlags);
576  } catch (boost::bad_expression &e) {
577  RETHROW_CODE(RegexException, 0, e);
578  } catch (std::exception &e) {
579  RETHROW_CODE(RegexException, 0, e);
580  }
581 }
582 
583 bool String::regex_search(const std::string &src, const boost::regex &regex, std::string &match, MatchFlag mFlags) throw (RegexException) {
584  boost::cmatch m;
585 
586  if (regex_search(src, regex, m, mFlags)) {
587  match = m[0];
588 
589  return true;
590  }
591 
592  return false;
593 }
594 
595 bool String::regex_search(const std::string &src, const std::string &regex, std::string &match, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
596  try {
597  const boost::regex rx(regex, reFlags);
598 
599  return regex_search(src, rx, match, mFlags);
600  } catch (boost::bad_expression &e) {
601  RETHROW_CODE(RegexException, 0, e);
602  } catch (std::exception &e) {
603  RETHROW_CODE(RegexException, 0, e);
604  }
605 }
606 
607 bool String::regex_search(const std::string &src, const boost::regex &regex, std::vector<std::string> &matches, bool global, bool subexp, MatchFlag mFlags) throw (RegexException) {
608  try {
609  const char *p = src.c_str();
610  boost::cmatch m;
611 
612  while (boost::regex_search(p, m, regex, mFlags)) {
613  if (subexp) {
614  for (size_t i = 0; i < m.size(); i++) {
615  matches.push_back(m[i]);
616  }
617  } else {
618  matches.push_back(m[0]);
619  }
620  p = m.suffix().str().c_str();
621 
622  if (!global) break;
623  }
624 
625  return (!matches.empty());
626  } catch (boost::bad_expression &e) {
627  RETHROW_CODE(RegexException, 0, e);
628  } catch (std::exception &e) {
629  RETHROW_CODE(RegexException, 0, e);
630  }
631 }
632 
633 bool String::regex_search(const std::string &src, const std::string &regex, std::vector<std::string> &matches, bool global, bool subexp, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
634  try {
635  const boost::regex rx(regex, reFlags);
636 
637  return regex_search(src, rx, matches, global, subexp, mFlags);
638  } catch (boost::bad_expression &e) {
639  RETHROW_CODE(RegexException, 0, e);
640  } catch (std::exception &e) {
641  RETHROW_CODE(RegexException, 0, e);
642  }
643 }
644 
645 bool String::regex_search(const std::string &src, const boost::regex &regex, std::set<std::string> &matches, bool global, bool subexp, MatchFlag mFlags) throw (RegexException) {
646  try {
647  std::string s(src);
648  boost::smatch m;
649 
650  while (boost::regex_search(s, m, regex, mFlags)) {
651  if (subexp) {
652  for (auto &&r: m) {
653  matches.insert(r);
654  }
655  } else {
656  matches.insert(m[0]);
657  }
658 
659  if (!global) break;
660 
661  s = m.suffix().str();
662  }
663 
664  return (!matches.empty());
665  } catch (boost::bad_expression &e) {
666  RETHROW_CODE(RegexException, 0, e);
667  } catch (std::exception &e) {
668  RETHROW_CODE(RegexException, 0, e);
669  }
670 }
671 
672 bool String::regex_search(const std::string &src, const std::string &regex, std::set<std::string> &matches, bool global, bool subexp, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
673  try {
674  const boost::regex rx(regex, reFlags);
675 
676  return regex_search(src, rx, matches, global, subexp, mFlags);
677  } catch (boost::bad_expression &e) {
678  RETHROW_CODE(RegexException, 0, e);
679  } catch (std::exception &e) {
680  RETHROW_CODE(RegexException, 0, e);
681  }
682 }
683 
684 bool String::regex_search_sub(const std::string &src, const boost::regex &regex, std::vector<std::string> &matches, bool global, MatchFlag mFlags) throw (RegexException) {
685  try {
686  std::string s(src);
687  boost::smatch m;
688 
689  while (boost::regex_search(s, m, regex, mFlags)) {
690  for (size_t i = 1, size = m.size(); i < size; i++) {
691  matches.push_back(m[i]);
692  }
693 
694  if (!global) break;
695 
696  s = m.suffix().str();
697  }
698 
699  return (!matches.empty());
700  } catch (boost::bad_expression &e) {
701  RETHROW_CODE(RegexException, 0, e);
702  } catch (std::exception &e) {
703  RETHROW_CODE(RegexException, 0, e);
704  }
705 }
706 
707 bool String::regex_search_sub(const std::string &src, const std::string &regex, std::vector<std::string> &matches, bool global, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
708  try {
709  const boost::regex rx(regex, reFlags);
710 
711  return regex_search_sub(src, rx, matches, global, mFlags);
712  } catch (boost::bad_expression &e) {
713  RETHROW_CODE(RegexException, 0, e);
714  } catch (std::exception &e) {
715  RETHROW_CODE(RegexException, 0, e);
716  }
717 }
718 
719 bool String::regex_search_sub(const std::string &src, const boost::regex &regex, std::set<std::string> &matches, bool global, MatchFlag mFlags) throw (RegexException) {
720  try {
721  std::string s(src);
722  boost::smatch m;
723 
724  while (boost::regex_search(s, m, regex, mFlags)) {
725  for (size_t i = 1, size = m.size(); i < size; i++) {
726  matches.insert(m[i]);
727  }
728 
729  if (!global) break;
730 
731  s = m.suffix().str();
732  }
733 
734  return (!matches.empty());
735  } catch (boost::bad_expression &e) {
736  RETHROW_CODE(RegexException, 0, e);
737  } catch (std::exception &e) {
738  RETHROW_CODE(RegexException, 0, e);
739  }
740 }
741 
742 bool String::regex_search_sub(const std::string &src, const std::string &regex, std::set<std::string> &matches, bool global, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
743  try {
744  const boost::regex rx(regex, reFlags);
745 
746  return regex_search_sub(src, rx, matches, global, mFlags);
747  } catch (boost::bad_expression &e) {
748  RETHROW_CODE(RegexException, 0, e);
749  } catch (std::exception &e) {
750  RETHROW_CODE(RegexException, 0, e);
751  }
752 }
753 
754 bool String::regex_isearch(const std::string &src, const boost::regex &regex, MatchFlag mFlags) throw (RegexException) {
755  try {
756  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
757 
758  return regex_search(src, rx, mFlags);
759  } catch (boost::bad_expression &e) {
760  RETHROW_CODE(RegexException, 0, e);
761  } catch (std::exception &e) {
762  RETHROW_CODE(RegexException, 0, e);
763  }
764 }
765 
766 bool String::regex_isearch(const std::string &src, const std::string &regex, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
767  try {
768  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
769 
770  return regex_search(src, rx, mFlags);
771  } catch (boost::bad_expression &e) {
772  RETHROW_CODE(RegexException, 0, e);
773  } catch (std::exception &e) {
774  RETHROW_CODE(RegexException, 0, e);
775  }
776 }
777 
778 bool String::regex_isearch(const std::string &src, const boost::regex &regex, boost::cmatch &matches, MatchFlag mFlags) throw (RegexException) {
779  try {
780  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
781 
782  return regex_search(src, rx, matches, mFlags);
783  } catch (boost::bad_expression &e) {
784  RETHROW_CODE(RegexException, 0, e);
785  } catch (std::exception &e) {
786  RETHROW_CODE(RegexException, 0, e);
787  }
788 }
789 
790 bool String::regex_isearch(const std::string &src, const std::string &regex, boost::cmatch &matches, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
791  try {
792  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
793 
794  return regex_search(src, rx, matches, mFlags);
795  } catch (boost::bad_expression &e) {
796  RETHROW_CODE(RegexException, 0, e);
797  } catch (std::exception &e) {
798  RETHROW_CODE(RegexException, 0, e);
799  }
800 }
801 
802 bool String::regex_isearch(const std::string &src, const boost::regex &regex, std::string &match, MatchFlag mFlags) throw (RegexException) {
803  try {
804  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
805 
806  return regex_search(src, rx, match, mFlags);
807  } catch (boost::bad_expression &e) {
808  RETHROW_CODE(RegexException, 0, e);
809  } catch (std::exception &e) {
810  RETHROW_CODE(RegexException, 0, e);
811  }
812 }
813 
814 bool String::regex_isearch(const std::string &src, const std::string &regex, std::string &match, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
815  try {
816  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
817 
818  return regex_search(src, rx, match, mFlags);
819  } catch (boost::bad_expression &e) {
820  RETHROW_CODE(RegexException, 0, e);
821  } catch (std::exception &e) {
822  RETHROW_CODE(RegexException, 0, e);
823  }
824 }
825 
826 bool String::regex_isearch(const std::string &src, const boost::regex &regex, std::vector<std::string> &matches, bool global, bool subexp, MatchFlag mFlags) throw (RegexException) {
827  try {
828  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
829 
830  return regex_search(src, rx, matches, global, subexp, mFlags);
831  } catch (boost::bad_expression &e) {
832  RETHROW_CODE(RegexException, 0, e);
833  } catch (std::exception &e) {
834  RETHROW_CODE(RegexException, 0, e);
835  }
836 }
837 
838 bool String::regex_isearch(const std::string &src, const std::string &regex, std::vector<std::string> &matches, bool global, bool subexp, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
839  try {
840  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
841 
842  return regex_search(src, rx, matches, global, subexp, mFlags);
843  } catch (boost::bad_expression &e) {
844  RETHROW_CODE(RegexException, 0, e);
845  } catch (std::exception &e) {
846  RETHROW_CODE(RegexException, 0, e);
847  }
848 }
849 
850 bool String::regex_isearch(const std::string &src, const boost::regex &regex, std::set<std::string> &matches, bool global, bool subexp, MatchFlag mFlags) throw (RegexException) {
851  try {
852  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
853 
854  return regex_search(src, rx, matches, global, subexp, mFlags);
855  } catch (boost::bad_expression &e) {
856  RETHROW_CODE(RegexException, 0, e);
857  } catch (std::exception &e) {
858  RETHROW_CODE(RegexException, 0, e);
859  }
860 }
861 
862 bool String::regex_isearch(const std::string &src, const std::string &regex, std::set<std::string> &matches, bool global, bool subexp, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
863  try {
864  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
865 
866  return regex_search(src, rx, matches, global, subexp, mFlags);
867  } catch (boost::bad_expression &e) {
868  RETHROW_CODE(RegexException, 0, e);
869  } catch (std::exception &e) {
870  RETHROW_CODE(RegexException, 0, e);
871  }
872 }
873 
874 bool String::regex_isearch_sub(const std::string &src, const boost::regex &regex, std::vector<std::string> &matches, bool global, MatchFlag mFlags) throw (RegexException) {
875  try {
876  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
877 
878  return regex_search_sub(src, rx, matches, global, mFlags);
879  } catch (boost::bad_expression &e) {
880  RETHROW_CODE(RegexException, 0, e);
881  } catch (std::exception &e) {
882  RETHROW_CODE(RegexException, 0, e);
883  }
884 }
885 
886 bool String::regex_isearch_sub(const std::string &src, const std::string &regex, std::vector<std::string> &matches, bool global, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
887  try {
888  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
889 
890  return regex_search_sub(src, rx, matches, global, mFlags);
891  } catch (boost::bad_expression &e) {
892  RETHROW_CODE(RegexException, 0, e);
893  } catch (std::exception &e) {
894  RETHROW_CODE(RegexException, 0, e);
895  }
896 }
897 
898 bool String::regex_isearch_sub(const std::string &src, const boost::regex &regex, std::set<std::string> &matches, bool global, MatchFlag mFlags) throw (RegexException) {
899  try {
900  const boost::regex rx(regex.str(), regex.flags() | boost::regex_constants::icase);
901 
902  return regex_search_sub(src, rx, matches, global, mFlags);
903  } catch (boost::bad_expression &e) {
904  RETHROW_CODE(RegexException, 0, e);
905  } catch (std::exception &e) {
906  RETHROW_CODE(RegexException, 0, e);
907  }
908 }
909 
910 bool String::regex_isearch_sub(const std::string &src, const std::string &regex, std::set<std::string> &matches, bool global, REFlag reFlags, MatchFlag mFlags) throw (RegexException) {
911  try {
912  const boost::regex rx(regex, reFlags | boost::regex_constants::icase);
913 
914  return regex_search_sub(src, rx, matches, global, mFlags);
915  } catch (boost::bad_expression &e) {
916  RETHROW_CODE(RegexException, 0, e);
917  } catch (std::exception &e) {
918  RETHROW_CODE(RegexException, 0, e);
919  }
920 }
921 
922 std::vector<std::string> String::regex_split(const std::string &str, const boost::regex &delim, bool empty, size_t limit) throw (RegexException) {
923  std::vector<std::string> vector;
924  std::string estr;
925  size_t chunks = 0;
926 
927  try {
928  boost::sregex_token_iterator it(str.begin(), str.end(), delim, -1);
929  boost::sregex_token_iterator end;
930 
931  for (; it != end && chunks < limit; ++it, chunks++) {
932  if (empty || !it->str().empty()) {
933  vector.push_back(*it);
934  }
935  }
936 
937  return vector;
938  } catch (boost::bad_expression &e) {
939  RETHROW_CODE(RegexException, 0, e);
940  } catch (std::exception &e) {
941  RETHROW_CODE(RegexException, 0, e);
942  }
943 }
944 
945 std::vector<std::string> String::regex_split(const std::string &str, const std::string &regex, bool empty, size_t limit, REFlag reFlags) throw (RegexException) {
946  std::vector<std::string> vector;
947  std::string estr;
948  size_t chunks = 0;
949 
950  try {
951  const boost::regex delim(regex, reFlags);
952 
953  boost::sregex_token_iterator it(str.begin(), str.end(), delim, -1);
954  boost::sregex_token_iterator end;
955 
956  for (; it != end && chunks < limit; ++it, chunks++) {
957  if (empty || !it->str().empty()) {
958  vector.push_back(*it);
959  }
960  }
961 
962  return vector;
963  } catch (boost::bad_expression &e) {
964  RETHROW_CODE(RegexException, 0, e);
965  } catch (std::exception &e) {
966  RETHROW_CODE(RegexException, 0, e);
967  }
968 }
969 
970 std::vector<std::string> String::regex_isplit(const std::string &str, const boost::regex &delim, bool empty, size_t limit) throw (RegexException) {
971  std::vector<std::string> vector;
972  std::string estr;
973  size_t chunks = 0;
974 
975  try {
976  const boost::regex idelim(delim.str(), delim.flags() | boost::regex_constants::icase);
977 
978  boost::sregex_token_iterator it(str.begin(), str.end(), idelim, -1);
979  boost::sregex_token_iterator end;
980 
981  for (; it != end && chunks < limit; ++it, chunks++) {
982  if (empty || !it->str().empty()) {
983  vector.push_back(*it);
984  }
985  }
986 
987  return vector;
988  } catch (boost::bad_expression &e) {
989  RETHROW_CODE(RegexException, 0, e);
990  } catch (std::exception &e) {
991  RETHROW_CODE(RegexException, 0, e);
992  }
993 }
994 
995 std::vector<std::string> String::regex_isplit(const std::string &str, const std::string &regex, bool empty, size_t limit, REFlag reFlags) throw (RegexException) {
996  std::vector<std::string> vector;
997  std::string estr;
998  size_t chunks = 0;
999 
1000  try {
1001  const boost::regex delim(regex, reFlags | boost::regex_constants::icase);
1002 
1003  boost::sregex_token_iterator it(str.begin(), str.end(), delim, -1);
1004  boost::sregex_token_iterator end;
1005 
1006  for (; it != end && chunks < limit; ++it, chunks++) {
1007  if (empty || !it->str().empty()) {
1008  vector.push_back(*it);
1009  }
1010  }
1011 
1012  return vector;
1013  } catch (boost::bad_expression &e) {
1014  RETHROW_CODE(RegexException, 0, e);
1015  } catch (std::exception &e) {
1016  RETHROW_CODE(RegexException, 0, e);
1017  }
1018 }
1019 
1020 std::vector<std::string> String::split(const std::string &str, const std::string &delim, bool exact, bool empty, size_t limit) throw () {
1021  std::vector<std::string> vector;
1022  std::size_t prev = 0, pos, chunks = 0;
1023 
1024  if (exact) {
1025  while (++chunks < limit && (pos = str.find(delim, prev)) != std::string::npos) {
1026  if (pos > prev || (empty && pos == prev)) {
1027  vector.push_back(str.substr(prev, pos - prev));
1028  }
1029 
1030  prev = pos + delim.length();
1031  }
1032  } else {
1033  while (++chunks < limit && (pos = str.find_first_of(delim, prev)) != std::string::npos) {
1034  if (pos > prev || (empty && pos == prev)) {
1035  vector.push_back(str.substr(prev, pos - prev));
1036  }
1037 
1038  prev = pos + 1;
1039  }
1040 
1041  }
1042 
1043  if (chunks >= limit || prev < str.length() || (empty && prev == str.length())) {
1044  vector.push_back(str.substr(prev, std::string::npos));
1045  }
1046 
1047  return vector;
1048 }
1049 
1050 std::vector<std::string> String::split(const std::string &str, char delim, bool empty, size_t limit) throw () {
1051  std::vector<std::string> vector;
1052  std::string s;
1053  std::stringstream ss(str);
1054  std::size_t chunks = 0;
1055 
1056  while (++chunks < limit && std::getline(ss, s, delim)) {
1057  if (empty || !s.empty()) {
1058  vector.push_back(s);
1059  }
1060  }
1061 
1062  if (chunks >= limit) {
1063  if (std::getline(ss, s)) {
1064  vector.push_back(s);
1065  }
1066  } else {
1067  if (empty && !str.empty() && str[str.length() - 1] == delim) {
1068  vector.push_back(std::string());
1069  }
1070  }
1071 
1072  return vector;
1073 }
1074 
1075 std::vector<std::string> String::split_csv(const std::string &line, const std::string &delim, bool empty, size_t limit) throw () {
1076  std::vector<std::string> parts;
1077  std::string part;
1078  bool quote = false;
1079  std::size_t chunks = 0;
1080 
1081  for (size_t i = 0, size = line.size(); i < size; i++) {
1082  if (!quote && line[i] == '"') {
1083  quote = true;
1084 
1085  continue;
1086  }
1087 
1088  if (quote && line[i] == '"') {
1089  if (size > i && line[i + 1] == '"') {
1090  i++;
1091  } else {
1092  quote = false;
1093 
1094  continue;
1095  }
1096  }
1097 
1098  if (!quote && delim.find(line[i]) != std::string::npos) {
1099  if (empty || !part.empty()) {
1100  parts.push_back(part);
1101 
1102  if (chunks++ >= limit) {
1103  break;
1104  }
1105 
1106  part.clear();
1107  }
1108  } else {
1109  part.push_back(line[i]);
1110  }
1111  }
1112 
1113  if (empty || !part.empty()) {
1114  parts.push_back(part);
1115  }
1116 
1117  return parts;
1118 }
1119 
1120 std::string String::join(const std::vector<std::string> &src, const std::string &delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1121  const size_t size = src.size();
1122 
1123  if (size > 0) {
1124  std::string dst;
1125 
1126  if (size > threshold && !lbr.empty()) {
1127  dst.append(lbr);
1128  }
1129 
1130  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1131  if (quote != '\0') {
1132  dst.append(1, quote).append(*it).append(1, quote).append(delim);
1133  } else {
1134  dst.append(*it).append(delim);
1135  }
1136  }
1137 
1138  dst.erase(dst.size() - delim.size());
1139 
1140  if (size > threshold && !rbr.empty()) {
1141  dst.append(rbr);
1142  }
1143 
1144  return dst;
1145  }
1146 
1147  return empty;
1148 }
1149 
1150 std::string String::join(const std::vector<std::string> &src, char delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1151  const size_t size = src.size();
1152 
1153  if (size > 0) {
1154  std::string dst;
1155 
1156  if (size > threshold && !lbr.empty()) {
1157  dst.append(lbr);
1158  }
1159 
1160  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1161  if (quote != '\0') {
1162  dst.append(1, quote).append(*it).append(1, quote).push_back(delim);
1163  } else {
1164  dst.append(*it).push_back(delim);
1165  }
1166  }
1167 
1168  dst.erase(dst.size() - 1);
1169 
1170  if (size > threshold && !rbr.empty()) {
1171  dst.append(rbr);
1172  }
1173 
1174  return dst;
1175  }
1176 
1177  return empty;
1178 }
1179 
1180 std::string String::join(const std::list<std::string> &src, const std::string &delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1181  const size_t size = src.size();
1182 
1183  if (size > 0) {
1184  std::string dst;
1185 
1186  if (size > threshold && !lbr.empty()) {
1187  dst.append(lbr);
1188  }
1189 
1190  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1191  if (quote != '\0') {
1192  dst.append(1, quote).append(*it).append(1, quote).append(delim);
1193  } else {
1194  dst.append(*it).append(delim);
1195  }
1196  }
1197 
1198  dst.erase(dst.size() - delim.size());
1199 
1200  if (size > threshold && !rbr.empty()) {
1201  dst.append(rbr);
1202  }
1203 
1204  return dst;
1205  }
1206 
1207  return empty;
1208 }
1209 
1210 std::string String::join(const std::list<std::string> &src, char delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1211  const size_t size = src.size();
1212 
1213  if (size > 0) {
1214  std::string dst;
1215 
1216  if (size > threshold && !lbr.empty()) {
1217  dst.append(lbr);
1218  }
1219 
1220  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1221  if (quote != '\0') {
1222  dst.append(1, quote).append(*it).append(1, quote).push_back(delim);
1223  } else {
1224  dst.append(*it).push_back(delim);
1225  }
1226  }
1227 
1228  dst.erase(dst.size() - 1);
1229 
1230  if (size > threshold && !rbr.empty()) {
1231  dst.append(rbr);
1232  }
1233 
1234  return dst;
1235  }
1236 
1237  return empty;
1238 }
1239 
1240 std::string String::join(const std::set<std::string> &src, const std::string &delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1241  const size_t size = src.size();
1242 
1243  if (size > 0) {
1244  std::string dst;
1245 
1246  if (size > threshold && !lbr.empty()) {
1247  dst.append(lbr);
1248  }
1249 
1250  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1251  if (quote != '\0') {
1252  dst.append(1, quote).append(*it).append(1, quote).append(delim);
1253  } else {
1254  dst.append(*it).append(delim);
1255  }
1256  }
1257 
1258  dst.erase(dst.size() - delim.size());
1259 
1260  if (size > threshold && !rbr.empty()) {
1261  dst.append(rbr);
1262  }
1263 
1264  return dst;
1265  }
1266 
1267  return empty;
1268 }
1269 
1270 std::string String::join(const std::set<std::string> &src, char delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1271  const size_t size = src.size();
1272 
1273  if (size > 0) {
1274  std::string dst;
1275 
1276  if (size > threshold && !lbr.empty()) {
1277  dst.append(lbr);
1278  }
1279 
1280  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1281  if (quote != '\0') {
1282  dst.append(1, quote).append(*it).append(1, quote).push_back(delim);
1283  } else {
1284  dst.append(*it).push_back(delim);
1285  }
1286  }
1287 
1288  dst.erase(dst.size() - 1);
1289 
1290  if (size > threshold && !rbr.empty()) {
1291  dst.append(rbr);
1292  }
1293 
1294  return dst;
1295  }
1296 
1297  return empty;
1298 }
1299 
1300 std::string String::join(const std::vector<variant::Variant> &src, const std::string &delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1301  const size_t size = src.size();
1302 
1303  if (size > 0) {
1304  std::string dst, str;
1305 
1306  if (size > threshold && !lbr.empty()) {
1307  dst.append(lbr);
1308  }
1309 
1310  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1311  try {
1312  str = it->str();
1313  } catch (...) {
1314  str = "(null)";
1315  }
1316 
1317  if (quote != '\0') {
1318  dst.append(1, quote).append(str).append(1, quote).append(delim);
1319  } else {
1320  dst.append(str).append(delim);
1321  }
1322  }
1323 
1324  dst.erase(dst.size() - delim.size());
1325 
1326  if (size > threshold && !rbr.empty()) {
1327  dst.append(rbr);
1328  }
1329 
1330  return dst;
1331  }
1332 
1333  return empty;
1334 }
1335 
1336 std::string String::join(const std::vector<variant::Variant> &src, char delim, char quote, const std::string &empty, const std::string &lbr, const std::string &rbr, size_t threshold) throw () {
1337  const size_t size = src.size();
1338 
1339  if (size > 0) {
1340  std::string dst, str;
1341 
1342  if (size > threshold && !lbr.empty()) {
1343  dst.append(lbr);
1344  }
1345 
1346  for (auto it = src.cbegin(), end = src.cend(); it != end; ++it) {
1347  try {
1348  str = it->str();
1349  } catch (...) {
1350  str = "(null)";
1351  }
1352 
1353  if (quote != '\0') {
1354  dst.append(1, quote).append(str).append(1, quote).push_back(delim);
1355  } else {
1356  dst.append(str).push_back(delim);
1357  }
1358  }
1359 
1360  dst.erase(dst.size() - 1);
1361 
1362  if (size > threshold && !rbr.empty()) {
1363  dst.append(rbr);
1364  }
1365 
1366  return dst;
1367  }
1368 
1369  return empty;
1370 }
1371 
1372 std::string String::trim(const std::string &str, const std::string &space) throw () {
1373  return ltrim(rtrim(str, space), space);
1374 }
1375 
1376 std::string String::trim(const std::string &str, char space) throw () {
1377  return ltrim(rtrim(str, space), space);
1378 }
1379 
1380 std::string& String::trim(std::string &str, const std::string &space) throw () {
1381  return ltrim(rtrim(str, space), space);
1382 }
1383 
1384 std::string& String::trim(std::string &str, char space) throw () {
1385  return ltrim(rtrim(str, space), space);
1386 }
1387 
1388 std::string String::rtrim(const std::string &str, const std::string &space) throw () {
1389  size_t i;
1390 
1391  if ((i = str.find_last_not_of(space)) != std::string::npos) {
1392  return str.substr(0, i + 1);
1393  } else {
1394  return std::string();
1395  }
1396 
1397  return str;
1398 }
1399 
1400 std::string String::rtrim(const std::string &str, char space) throw () {
1401  size_t i;
1402 
1403  if ((i = str.find_last_not_of(space)) != std::string::npos) {
1404  return str.substr(0, i + 1);
1405  } else {
1406  return std::string();
1407  }
1408 
1409  return str;
1410 }
1411 
1412 std::string& String::rtrim(std::string &str, const std::string &space) throw () {
1413  size_t i;
1414 
1415  if ((i = str.find_last_not_of(space)) != std::string::npos) {
1416  str.substr(0, i + 1).swap(str);
1417  } else {
1418  str.clear();
1419  }
1420 
1421  return str;
1422 }
1423 
1424 std::string& String::rtrim(std::string &str, char space) throw () {
1425  size_t i;
1426 
1427  if ((i = str.find_last_not_of(space)) != std::string::npos) {
1428  str.substr(0, i + 1).swap(str);
1429  } else {
1430  str.clear();
1431  }
1432 
1433  return str;
1434 }
1435 
1436 std::string String::ltrim(const std::string &str, const std::string &space) throw () {
1437  size_t i;
1438 
1439  if ((i = str.find_first_not_of(space)) != std::string::npos) {
1440  return str.substr(i);
1441  } else {
1442  return std::string();
1443  }
1444 
1445  return str;
1446 }
1447 
1448 std::string String::ltrim(const std::string &str, char space) throw () {
1449  size_t i;
1450 
1451  if ((i = str.find_first_not_of(space)) != std::string::npos) {
1452  return str.substr(i);
1453  } else {
1454  return std::string();
1455  }
1456 
1457  return str;
1458 }
1459 
1460 std::string& String::ltrim(std::string &str, const std::string &space) throw () {
1461  size_t i;
1462 
1463  if ((i = str.find_first_not_of(space)) != std::string::npos) {
1464  str.substr(i).swap(str);
1465  } else {
1466  str.clear();
1467  }
1468 
1469  return str;
1470 }
1471 
1472 std::string& String::ltrim(std::string &str, char space) throw () {
1473  size_t i;
1474 
1475  if ((i = str.find_first_not_of(space)) != std::string::npos) {
1476  str.substr(i).swap(str);
1477  } else {
1478  str.clear();
1479  }
1480 
1481  return str;
1482 }
1483 
1484 std::string String::lower(const std::string &src) throw () {
1485  std::string dst(src);
1486 
1487  std::transform(dst.begin(), dst.end(), dst.begin(), ::tolower);
1488 
1489  return dst;
1490 }
1491 
1492 std::string& String::lower(std::string &src) throw () {
1493  std::transform(src.begin(), src.end(), src.begin(), ::tolower);
1494 
1495  return src;
1496 }
1497 
1498 std::string String::upper(const std::string &src) throw () {
1499  std::string dst(src);
1500 
1501  std::transform(dst.begin(), dst.end(), dst.begin(), ::toupper);
1502 
1503  return dst;
1504 }
1505 
1506 std::string& String::upper(std::string &src) throw () {
1507  std::transform(src.begin(), src.end(), src.begin(), ::toupper);
1508 
1509  return src;
1510 }
1511 
1512 std::string String::ucfirst(const std::string &src) throw () {
1513  std::string dst(lower(src));
1514 
1515  for (auto it = dst.begin(), end = dst.end(); it != end; ++it) {
1516  if (!isspace(*it)) {
1517  *it = std::toupper(*it);
1518 
1519  break;
1520  }
1521  }
1522 
1523  return dst;
1524 }
1525 
1526 std::string& String::ucfirst(std::string &src) throw () {
1527  lower(src);
1528 
1529  for (auto it = src.begin(), end = src.end(); it != end; ++it) {
1530  if (!isspace(*it)) {
1531  *it = std::toupper(*it);
1532 
1533  break;
1534  }
1535  }
1536 
1537  return src;
1538 }
1539 
1540 std::string String::ucword(const std::string &src) throw () {
1541  std::string dst(src);
1542  bool space = true;
1543 
1544  for (auto it = dst.begin(), end = dst.end(); it != end; ++it) {
1545  if (space) {
1546  *it = std::toupper(*it);
1547  } else {
1548  *it = std::tolower(*it);
1549  }
1550 
1551  space = isspace(*it);
1552  }
1553 
1554  return src;
1555 }
1556 
1557 std::string& String::ucword(std::string &src) throw () {
1558  bool space = true;
1559 
1560  for (auto it = src.begin(), end = src.end(); it != end; ++it) {
1561  if (space) {
1562  *it = std::toupper(*it);
1563  } else {
1564  *it = std::tolower(*it);
1565  }
1566 
1567  space = isspace(*it);
1568  }
1569 
1570  return src;
1571 }
1572 
1573 std::string String::itoa(int64_t src, int base) throw () { // NOTE: Look at boosting performance with data here: https://github.com/miloyip/itoa-benchmark
1574  int i, c = 0, negative = 0;
1575  std::string dst;
1576 
1577  if (UNLIKELY((unsigned int) base > 16)) {
1578  return dst;
1579  }
1580 
1581  if (src < 0) {
1582  src = -src;
1583  negative = 1;
1584  c++;
1585  }
1586 
1587  int64_t tmp = src;
1588 
1589  do {
1590  c++;
1591  tmp /= base;
1592  } while (tmp);
1593 
1594  dst.resize(c);
1595 
1596  if (negative) dst[0] = '-';
1597 
1598  i = c - 1;
1599  do {
1600  dst[i--] = RadixLookup()[src % base];
1601  src /= base;
1602  } while (src);
1603 
1604  return dst;
1605 }
1606 
1607 std::string String::itoa(uint64_t src, int base) throw () {
1608  int i, c = 0;
1609  std::string dst;
1610 
1611  if (UNLIKELY((unsigned int) base > 16)) {
1612  return dst;
1613  }
1614 
1615  uint64_t tmp = src;
1616 
1617  do {
1618  c++;
1619  tmp /= base;
1620  } while (tmp);
1621 
1622  dst.resize(c);
1623 
1624  i = c - 1;
1625  do {
1626  dst[i--] = RadixLookup()[src % base];
1627  src /= base;
1628  } while (src);
1629 
1630  return dst;
1631 }
1632 
1633 char* String::itoa(int64_t src, char *dst, size_t &len, int base) throw () {
1634  int i, c = 0, negative = 0;
1635 
1636  if (UNLIKELY(base < 2 || base > 16)) {
1637  return NULL;
1638  }
1639 
1640  if (src < 0) {
1641  src = -src;
1642  negative = 1;
1643  c++;
1644  }
1645 
1646  int64_t tmp = src;
1647 
1648  do {
1649  c++;
1650  tmp /= base;
1651  } while (tmp);
1652 
1653  if (UNLIKELY(c >= (int) len)) {
1654  return NULL;
1655  }
1656 
1657  dst[c] = '\0';
1658 
1659  if (negative) dst[0] = '-';
1660 
1661  i = c - 1;
1662  do {
1663  dst[i--] = RadixLookup()[src % base];
1664  src /= base;
1665  } while (src);
1666 
1667  len = c;
1668 
1669  return dst;
1670 }
1671 
1672 char* String::itoa(uint64_t src, char *dst, size_t &len, int base) throw () {
1673  int i, c = 0;
1674 
1675  if (UNLIKELY((unsigned int) base > 16)) {
1676  return NULL;
1677  }
1678 
1679  uint64_t tmp = src;
1680 
1681  do {
1682  c++;
1683  tmp /= base;
1684  } while (tmp);
1685 
1686  if (UNLIKELY(c >= (int) len)) {
1687  return NULL;
1688  }
1689 
1690  dst[c] = '\0';
1691 
1692  i = c - 1;
1693  do {
1694  dst[i--] = RadixLookup()[src % base];
1695  src /= base;
1696  } while (src);
1697 
1698  len = c;
1699 
1700  return dst;
1701 }
1702 
1703 std::string String::bandwidth(int64_t bps, int decimals) throw () {
1704  if (decimals == 0) {
1705  if (bps % 1000000000000000000LL == 0 && bps >= 1000000000000000000LL) {
1706  return String::sprintf("%" PRId64 "Ebs", bps / 1000000000000000000LL);
1707  } else if (bps % 1000000000000000LL == 0 && bps >= 1000000000000000LL) {
1708  return String::sprintf("%" PRId64 "Pbs", bps / 1000000000000000LL);
1709  } else if (bps % 1000000000000LL == 0 && bps >= 1000000000000LL) {
1710  return String::sprintf("%" PRId64 "Tbs", bps / 1000000000000LL);
1711  } else if (bps % 1000000000LL == 0 && bps >= 1000000000LL) {
1712  return String::sprintf("%" PRId64 "Gbs", bps / 1000000000LL);
1713  } else if (bps % 1000000LL == 0 && bps >= 1000000LL) {
1714  return String::sprintf("%" PRId64 "Mbs", bps / 1000000LL);
1715  } else if (bps % 1000LL == 0 && bps >= 1000LL) {
1716  return String::sprintf("%" PRId64 "Kbs", bps / 1000LL);
1717  }
1718  } else {
1719  double adj = pow(10, decimals);
1720  std::string buf;
1721 
1722  if (bps >= 1000000000000000000LL) {
1723  buf = String::sprintf("%gEbs", roundf((double) bps / 1000000000000000000.0f * adj) / adj);
1724  } else if (bps >= 1000000000000000LL) {
1725  buf = String::sprintf("%gPbs", roundf((double) bps / 1000000000000000.0f * adj) / adj);
1726  } else if (bps >= 1000000000000LL) {
1727  buf = String::sprintf("%gTbs", roundf((double) bps / 1000000000000.0f * adj) / adj);
1728  } else if (bps >= 1000000000LL) {
1729  buf = String::sprintf("%gGbs", roundf((double) bps / 1000000000.0f * adj) / adj);
1730  } else if (bps >= 1000000LL) {
1731  buf = String::sprintf("%gMbs", roundf((double) bps / 1000000.0f * adj) / adj);
1732  } else if (bps >= 1000LL) {
1733  buf = String::sprintf("%gKbs", roundf((double) bps / 1000.0f * adj) / adj);
1734  }
1735 
1736  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
1737  size_t pos = buf.find("e+", 3);
1738 
1739  if (pos != buf.npos) {
1740  size_t off = buf.find_first_of("EPTGMK", pos + 2);
1741 
1742  buf.replace(pos, off - pos, "", 0);
1743  }
1744 
1745  return buf;
1746  }
1747  }
1748 
1749  return String::sprintf("%" PRId64 "bps", bps);
1750 }
1751 
1752 std::string String::bandwidth(uint64_t bps, int decimals) throw () {
1753  if (decimals == 0) {
1754  if (bps % 1000000000000000000LLU == 0 && bps >= 1000000000000000000LLU) {
1755  return String::sprintf("%" PRIu64 "Ebs", bps / 1000000000000000000LLU);
1756  } else if (bps % 1000000000000000LLU == 0 && bps >= 1000000000000000LLU) {
1757  return String::sprintf("%" PRIu64 "Pbs", bps / 1000000000000000LLU);
1758  } else if (bps % 1000000000000LLU == 0 && bps >= 1000000000000LLU) {
1759  return String::sprintf("%" PRIu64 "Tbs", bps / 1000000000000LLU);
1760  } else if (bps % 1000000000LLU == 0 && bps >= 1000000000LLU) {
1761  return String::sprintf("%" PRIu64 "Gbs", bps / 1000000000LLU);
1762  } else if (bps % 1000000LLU == 0 && bps >= 1000000LLU) {
1763  return String::sprintf("%" PRIu64 "Mbs", bps / 1000000LLU);
1764  } else if (bps % 1000LLU == 0 && bps >= 1000LLU) {
1765  return String::sprintf("%" PRIu64 "Kbs", bps / 1000LLU);
1766  }
1767  } else {
1768  double adj = pow(10, decimals);
1769  std::string buf;
1770 
1771  if (bps >= 1000000000000000000LLU) {
1772  buf = String::sprintf("%gEbs", roundf((double) bps / 1000000000000000000.0f * adj) / adj);
1773  } else if (bps >= 1000000000000000LLU) {
1774  buf = String::sprintf("%gPbs", roundf((double) bps / 1000000000000000.0f * adj) / adj);
1775  } else if (bps >= 1000000000000LLU) {
1776  buf = String::sprintf("%gTbs", roundf((double) bps / 1000000000000.0f * adj) / adj);
1777  } else if (bps >= 1000000000LLU) {
1778  buf = String::sprintf("%gGbs", roundf((double) bps / 1000000000.0f * adj) / adj);
1779  } else if (bps >= 1000000LLU) {
1780  buf = String::sprintf("%gMbs", roundf((double) bps / 1000000.0f * adj) / adj);
1781  } else if (bps >= 1000LLU) {
1782  buf = String::sprintf("%gKbs", roundf((double) bps / 1000.0f * adj) / adj);
1783  }
1784 
1785  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
1786  size_t pos = buf.find("e+", 3);
1787 
1788  if (pos != buf.npos) {
1789  size_t off = buf.find_first_of("EPTGMK", pos + 2);
1790 
1791  buf.replace(pos, off - pos, "", 0);
1792  }
1793 
1794  return buf;
1795  }
1796  }
1797 
1798  return String::sprintf("%" PRIu64 "bps", bps);
1799 }
1800 
1801 std::string String::rate(int64_t bps, int decimals, const std::string &suffix) throw () {
1802  if (decimals == 0) {
1803  if (bps % 1000000000000000000LL == 0 && bps >= 1000000000000000000LL) {
1804  return String::sprintf("%" PRId64 "E%s", bps / 1000000000000000000LL, suffix.c_str());
1805  } else if (bps % 1000000000000000LL == 0 && bps >= 1000000000000000LL) {
1806  return String::sprintf("%" PRId64 "P%s", bps / 1000000000000000LL, suffix.c_str());
1807  } else if (bps % 1000000000000LL == 0 && bps >= 1000000000000LL) {
1808  return String::sprintf("%" PRId64 "T%s", bps / 1000000000000LL, suffix.c_str());
1809  } else if (bps % 1000000000LL == 0 && bps >= 1000000000LL) {
1810  return String::sprintf("%" PRId64 "G%s", bps / 1000000000LL, suffix.c_str());
1811  } else if (bps % 1000000LL == 0 && bps >= 1000000LL) {
1812  return String::sprintf("%" PRId64 "M%s", bps / 1000000LL, suffix.c_str());
1813  } else if (bps % 1000LL == 0 && bps >= 1000LL) {
1814  return String::sprintf("%" PRId64 "K%s", bps / 1000LL, suffix.c_str());
1815  }
1816  } else {
1817  double adj = pow(10, decimals);
1818  std::string buf;
1819 
1820  if (bps >= 1000000000000000000LL) {
1821  buf = String::sprintf("%gE%s", roundf((double) bps / 1000000000000000000.0f * adj) / adj, suffix.c_str());
1822  } else if (bps >= 1000000000000000LL) {
1823  buf = String::sprintf("%gP%s", roundf((double) bps / 1000000000000000.0f * adj) / adj, suffix.c_str());
1824  } else if (bps >= 1000000000000LL) {
1825  buf = String::sprintf("%gT%s", roundf((double) bps / 1000000000000.0f * adj) / adj, suffix.c_str());
1826  } else if (bps >= 1000000000LL) {
1827  buf = String::sprintf("%gG%s", roundf((double) bps / 1000000000.0f * adj) / adj, suffix.c_str());
1828  } else if (bps >= 1000000LL) {
1829  buf = String::sprintf("%gM%s", roundf((double) bps / 1000000.0f * adj) / adj, suffix.c_str());
1830  } else if (bps >= 1000LL) {
1831  buf = String::sprintf("%gK%s", roundf((double) bps / 1000.0f * adj) / adj, suffix.c_str());
1832  }
1833 
1834  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
1835  size_t pos = buf.find("e+", 3);
1836 
1837  if (pos != buf.npos) {
1838  size_t off = buf.find_first_of("EPTGMK", pos + 2);
1839 
1840  buf.replace(pos, off - pos, "", 0);
1841  }
1842 
1843  return buf;
1844  }
1845  }
1846 
1847  return String::sprintf("%" PRId64 "b%s", bps, suffix.c_str());
1848 }
1849 
1850 std::string String::rate(uint64_t bps, int decimals, const std::string &suffix) throw () {
1851  if (decimals == 0) {
1852  if (bps % 1000000000000000000LLU == 0 && bps >= 1000000000000000000LLU) {
1853  return String::sprintf("%" PRIu64 "E%s", bps / 1000000000000000000LLU, suffix.c_str());
1854  } else if (bps % 1000000000000000LLU == 0 && bps >= 1000000000000000LLU) {
1855  return String::sprintf("%" PRIu64 "P%s", bps / 1000000000000000LLU, suffix.c_str());
1856  } else if (bps % 1000000000000LLU == 0 && bps >= 1000000000000LLU) {
1857  return String::sprintf("%" PRIu64 "T%s", bps / 1000000000000LLU, suffix.c_str());
1858  } else if (bps % 1000000000LLU == 0 && bps >= 1000000000LLU) {
1859  return String::sprintf("%" PRIu64 "G%s", bps / 1000000000LLU, suffix.c_str());
1860  } else if (bps % 1000000LLU == 0 && bps >= 1000000LLU) {
1861  return String::sprintf("%" PRIu64 "M%s", bps / 1000000LLU, suffix.c_str());
1862  } else if (bps % 1000LLU == 0 && bps >= 1000LLU) {
1863  return String::sprintf("%" PRIu64 "K%s", bps / 1000LLU, suffix.c_str());
1864  }
1865  } else {
1866  double adj = pow(10, decimals);
1867  std::string buf;
1868 
1869  if (bps >= 1000000000000000000LLU) {
1870  buf = String::sprintf("%gE%s", roundf((double) bps / 1000000000000000000.0f * adj) / adj, suffix.c_str());
1871  } else if (bps >= 1000000000000000LLU) {
1872  buf = String::sprintf("%gP%s", roundf((double) bps / 1000000000000000.0f * adj) / adj, suffix.c_str());
1873  } else if (bps >= 1000000000000LLU) {
1874  buf = String::sprintf("%gT%s", roundf((double) bps / 1000000000000.0f * adj) / adj, suffix.c_str());
1875  } else if (bps >= 1000000000LLU) {
1876  buf = String::sprintf("%gG%s", roundf((double) bps / 1000000000.0f * adj) / adj, suffix.c_str());
1877  } else if (bps >= 1000000LLU) {
1878  buf = String::sprintf("%gM%s", roundf((double) bps / 1000000.0f * adj) / adj, suffix.c_str());
1879  } else if (bps >= 1000LLU) {
1880  buf = String::sprintf("%gK%s", roundf((double) bps / 1000.0f * adj) / adj, suffix.c_str());
1881  }
1882 
1883  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
1884  size_t pos = buf.find("e+", 3);
1885 
1886  if (pos != buf.npos) {
1887  size_t off = buf.find_first_of("EPTGMK", pos + 2);
1888 
1889  buf.replace(pos, off - pos, "", 0);
1890  }
1891 
1892  return buf;
1893  }
1894  }
1895 
1896  return String::sprintf("%" PRIu64 "b%s", bps, suffix.c_str());
1897 }
1898 
1899 std::string String::dataSize(int64_t bytes, int decimals) throw () {
1900  if (decimals == 0) {
1901  if (bytes % (int64_t) pow(2, 60) == 0 && bytes >= (int64_t) pow(2, 60)) {
1902  return String::sprintf("%" PRId64 "EB", bytes / (int64_t) pow(2, 60));
1903  } else if (bytes % (int64_t) pow(2, 50) == 0 && bytes >= (int64_t) pow(2, 50)) {
1904  return String::sprintf("%" PRId64 "PB", bytes / (int64_t) pow(2, 50));
1905  } else if (bytes % (int64_t) pow(2, 40) == 0 && bytes >= (int64_t) pow(2, 40)) {
1906  return String::sprintf("%" PRId64 "TB", bytes / (int64_t) pow(2, 40));
1907  } else if (bytes % (int64_t) pow(2, 30) == 0 && bytes >= (int64_t) pow(2, 30)) {
1908  return String::sprintf("%" PRId64 "GB", bytes / (int64_t) pow(2, 30));
1909  } else if (bytes % (int64_t) pow(2, 20) == 0 && bytes >= (int64_t) pow(2, 20)) {
1910  return String::sprintf("%" PRId64 "MB", bytes / (int64_t) pow(2, 20));
1911  } else if (bytes % (int64_t) pow(2, 10) == 0 && bytes >= (int64_t) pow(2, 10)) {
1912  return String::sprintf("%" PRId64 "KB", bytes / (int64_t) pow(2, 10));
1913  }
1914  } else {
1915  double adj = pow(10, decimals);
1916  std::string buf;
1917 
1918  if (bytes >= (int64_t) pow(2, 60)) {
1919  buf = String::sprintf("%gEB", roundf((double) bytes / pow(2, 60) * adj) / adj);
1920  } else if (bytes >= (int64_t) pow(2, 50)) {
1921  buf = String::sprintf("%gPB", roundf((double) bytes / pow(2, 50) * adj) / adj);
1922  } else if (bytes >= (int64_t) pow(2, 40)) {
1923  buf = String::sprintf("%gTB", roundf((double) bytes / pow(2, 40) * adj) / adj);
1924  } else if (bytes >= (int64_t) pow(2, 30)) {
1925  buf = String::sprintf("%gGB", roundf((double) bytes / pow(2, 30) * adj) / adj);
1926  } else if (bytes >= (int64_t) pow(2, 20)) {
1927  buf = String::sprintf("%gMB", roundf((double) bytes / pow(2, 20) * adj) / adj);
1928  } else if (bytes >= (int64_t) pow(2, 10)) {
1929  buf = String::sprintf("%gKB", roundf((double) bytes / pow(2, 10) * adj) / adj);
1930  }
1931 
1932  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
1933  size_t pos = buf.find("e+", 3);
1934 
1935  if (pos != buf.npos) {
1936  size_t off = buf.find_first_of("EPTGMK", pos + 2);
1937 
1938  buf.replace(pos, off - pos, "", 0);
1939  }
1940 
1941  return buf;
1942  }
1943  }
1944 
1945  return String::sprintf("%lld", bytes);
1946 }
1947 
1948 std::string String::dataSize(uint64_t bytes, int decimals) throw () {
1949  if (decimals == 0) {
1950  if (bytes % (uint64_t) pow(2, 60) == 0 && bytes >= (uint64_t) pow(2, 60)) {
1951  return String::sprintf("%" PRIu64 "EB", bytes / (uint64_t) pow(2, 60));
1952  } else if (bytes % (uint64_t) pow(2, 50) == 0 && bytes >= (uint64_t) pow(2, 50)) {
1953  return String::sprintf("%" PRIu64 "PB", bytes / (uint64_t) pow(2, 50));
1954  } else if (bytes % (uint64_t) pow(2, 40) == 0 && bytes >= (uint64_t) pow(2, 40)) {
1955  return String::sprintf("%" PRIu64 "TB", bytes / (uint64_t) pow(2, 40));
1956  } else if (bytes % (uint64_t) pow(2, 30) == 0 && bytes >= (uint64_t) pow(2, 30)) {
1957  return String::sprintf("%" PRIu64 "GB", bytes / (uint64_t) pow(2, 30));
1958  } else if (bytes % (uint64_t) pow(2, 20) == 0 && bytes >= (uint64_t) pow(2, 20)) {
1959  return String::sprintf("%" PRIu64 "MB", bytes / (uint64_t) pow(2, 20));
1960  } else if (bytes % (uint64_t) pow(2, 10) == 0 && bytes >= (uint64_t) pow(2, 10)) {
1961  return String::sprintf("%" PRIu64 "KB", bytes / (uint64_t) pow(2, 10));
1962  }
1963  } else {
1964  double adj = pow(10, decimals);
1965  std::string buf;
1966 
1967  if (bytes >= (uint64_t) pow(2, 60)) {
1968  buf = String::sprintf("%gEB", roundf((double) bytes / pow(2, 60) * adj) / adj);
1969  } else if (bytes >= (uint64_t) pow(2, 50)) {
1970  buf = String::sprintf("%gPB", roundf((double) bytes / pow(2, 50) * adj) / adj);
1971  } else if (bytes >= (uint64_t) pow(2, 40)) {
1972  buf = String::sprintf("%gTB", roundf((double) bytes / pow(2, 40) * adj) / adj);
1973  } else if (bytes >= (uint64_t) pow(2, 30)) {
1974  buf = String::sprintf("%gGB", roundf((double) bytes / pow(2, 30) * adj) / adj);
1975  } else if (bytes >= (uint64_t) pow(2, 20)) {
1976  buf = String::sprintf("%gMB", roundf((double) bytes / pow(2, 20) * adj) / adj);
1977  } else if (bytes >= (uint64_t) pow(2, 10)) {
1978  buf = String::sprintf("%gKB", roundf((double) bytes / pow(2, 10) * adj) / adj);
1979  }
1980 
1981  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
1982  size_t pos = buf.find("e+", 3);
1983 
1984  if (pos != buf.npos) {
1985  size_t off = buf.find_first_of("EPTGMK", pos + 2);
1986 
1987  buf.replace(pos, off - pos, "", 0);
1988  }
1989 
1990  return buf;
1991  }
1992  }
1993 
1994  return String::sprintf("%llu", bytes);
1995 }
1996 
1997 uint64_t String::dataSize(const std::string &dataSize) throw () {
1998  uint64_t number = std::stoull(dataSize);
1999 
2000  if (dataSize.size() > 1) {
2001  size_t offset = (isalpha(dataSize[dataSize.size() - 2]) == 0) ? 1 : 2;
2002 
2003  switch (::tolower(dataSize[dataSize.size() - offset])) {
2004  case 'e':
2005  number *= pow(2, 60);
2006  break;
2007 
2008  case 'p':
2009  number *= pow(2, 50);
2010  break;
2011 
2012  case 't':
2013  number *= pow(2, 40);
2014  break;
2015 
2016  case 'g':
2017  number *= pow(2, 30);
2018  break;
2019 
2020  case 'm':
2021  number *= pow(2, 20);
2022  break;
2023 
2024  case 'k':
2025  number *= pow(2, 10);
2026  break;
2027  }
2028  }
2029 
2030  return number;
2031 }
2032 
2033 std::string String::dataRate(int64_t bps, int decimals) throw () {
2034  if (decimals == 0) {
2035  if (bps % 1000000000000000000LL == 0 && bps >= 1000000000000000000LL) {
2036  return String::sprintf("%" PRId64 "e", bps / 1000000000000000000LL);
2037  } else if (bps % 1000000000000000LL == 0 && bps >= 1000000000000000LL) {
2038  return String::sprintf("%" PRId64 "p", bps / 1000000000000000LL);
2039  } else if (bps % 1000000000000LL == 0 && bps >= 1000000000000LL) {
2040  return String::sprintf("%" PRId64 "t", bps / 1000000000000LL);
2041  } else if (bps % 1000000000LL == 0 && bps >= 1000000000LL) {
2042  return String::sprintf("%" PRId64 "g", bps / 1000000000LL);
2043  } else if (bps % 1000000LL == 0 && bps >= 1000000LL) {
2044  return String::sprintf("%" PRId64 "m", bps / 1000000LL);
2045  } else if (bps % 1000LL == 0 && bps >= 1000LL) {
2046  return String::sprintf("%" PRId64 "k", bps / 1000LL);
2047  }
2048  } else {
2049  double adj = pow(10, decimals);
2050  std::string buf;
2051 
2052  if (bps >= 1000000000000000000LL) {
2053  buf = String::sprintf("%0ge", roundf((double) bps / 1000000000000000000.0f * adj) / adj);
2054  } else if (bps >= 1000000000000000LL) {
2055  buf = String::sprintf("%0gp", roundf((double) bps / 1000000000000000.0f * adj) / adj);
2056  } else if (bps >= 1000000000000LL) {
2057  buf = String::sprintf("%0gt", roundf((double) bps / 1000000000000.0f * adj) / adj);
2058  } else if (bps >= 1000000000LL) {
2059  buf = String::sprintf("%0gg", roundf((double) bps / 1000000000.0f * adj) / adj);
2060  } else if (bps >= 1000000LL) {
2061  buf = String::sprintf("%0gm", roundf((double) bps / 1000000.0f * adj) / adj);
2062  } else if (bps >= 1000LL) {
2063  buf = String::sprintf("%0gk", roundf((double) bps / 1000.0f * adj) / adj);
2064  }
2065 
2066  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
2067  size_t pos = buf.find("e+", 3);
2068 
2069  if (pos != buf.npos) {
2070  size_t off = buf.find_first_of("eptgmk", pos + 2);
2071 
2072  buf.replace(pos, off - pos, "", 0);
2073  }
2074 
2075  return buf;
2076  }
2077  }
2078 
2079  return String::sprintf("%" PRId64, bps);
2080 }
2081 
2082 std::string String::dataRate(uint64_t bps, int decimals) throw () {
2083  if (decimals == 0) {
2084  if (bps % 1000000000000000000LLU == 0 && bps >= 1000000000000000000LLU) {
2085  return String::sprintf("%" PRIu64 "e", bps / 1000000000000000000LLU);
2086  } else if (bps % 1000000000000000LLU == 0 && bps >= 1000000000000000LLU) {
2087  return String::sprintf("%" PRIu64 "p", bps / 1000000000000000LLU);
2088  } else if (bps % 1000000000000LLU == 0 && bps >= 1000000000000LLU) {
2089  return String::sprintf("%" PRIu64 "t", bps / 1000000000000LLU);
2090  } else if (bps % 1000000000LLU == 0 && bps >= 1000000000LLU) {
2091  return String::sprintf("%" PRIu64 "g", bps / 1000000000LLU);
2092  } else if (bps % 1000000LLU == 0 && bps >= 1000000LLU) {
2093  return String::sprintf("%" PRIu64 "m", bps / 1000000LLU);
2094  } else if (bps % 1000LLU == 0 && bps >= 1000LLU) {
2095  return String::sprintf("%" PRIu64 "k", bps / 1000LLU);
2096  }
2097  } else {
2098  double adj = pow(10, decimals);
2099  std::string buf;
2100 
2101  if (bps >= 1000000000000000000LLU) {
2102  buf = String::sprintf("%0ge", roundf((double) bps / 1000000000000000000.0f * adj) / adj);
2103  } else if (bps >= 1000000000000000LLU) {
2104  buf = String::sprintf("%0gp", roundf((double) bps / 1000000000000000.0f * adj) / adj);
2105  } else if (bps >= 1000000000000LLU) {
2106  buf = String::sprintf("%0gt", roundf((double) bps / 1000000000000.0f * adj) / adj);
2107  } else if (bps >= 1000000000LLU) {
2108  buf = String::sprintf("%0gg", roundf((double) bps / 1000000000.0f * adj) / adj);
2109  } else if (bps >= 1000000LLU) {
2110  buf = String::sprintf("%0gm", roundf((double) bps / 1000000.0f * adj) / adj);
2111  } else if (bps >= 1000LLU) {
2112  buf = String::sprintf("%0gk", roundf((double) bps / 1000.0f * adj) / adj);
2113  }
2114 
2115  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
2116  size_t pos = buf.find("e+", 3);
2117 
2118  if (pos != buf.npos) {
2119  size_t off = buf.find_first_of("eptgmk", pos + 2);
2120 
2121  buf.replace(pos, off - pos, "", 0);
2122  }
2123 
2124  return buf;
2125  }
2126  }
2127 
2128  return String::sprintf("%" PRIu64, bps);
2129 }
2130 
2131 uint64_t String::dataRate(const std::string &dataRate) throw () {
2132  uint64_t number = std::stoull(dataRate);
2133 
2134  if (dataRate.size() > 1) {
2135  size_t offset = (isalpha(dataRate[dataRate.size() - 2]) == 0) ? 1 : 2;
2136 
2137  switch (::tolower(dataRate[dataRate.size() - offset])) {
2138  case 'e':
2139  number *= pow(10, 18);
2140  break;
2141 
2142  case 'p':
2143  number *= pow(10, 15);
2144  break;
2145 
2146  case 't':
2147  number *= pow(10, 12);
2148  break;
2149 
2150  case 'g':
2151  number *= pow(10, 9);
2152  break;
2153 
2154  case 'm':
2155  number *= pow(10, 6);
2156  break;
2157 
2158  case 'k':
2159  number *= pow(10, 3);
2160  break;
2161  }
2162  }
2163 
2164  return number;
2165 }
2166 
2167 std::string String::duration(int64_t usec, int decimals) throw () {
2168  if (decimals == 0) {
2169  if (usec % (7LL * 86400LL * 1000000LL) == 0 && usec >= (7LL * 86400LL * (int64_t) pow(10, 6))) {
2170  return String::sprintf("%" PRId64 "w", usec / (7LL * 86400LL * 1000000LL));
2171  } else if (usec % (86400LL * 1000000LL) == 0 && usec >= (86400LL * (int64_t) pow(10, 6))) {
2172  return String::sprintf("%" PRId64 "d", usec / (86400LL * 1000000LL));
2173  } else if (usec % (3600LL * 1000000LL) == 0 && usec >= (3600LL * (int64_t) pow(10, 6))) {
2174  return String::sprintf("%" PRId64 "h", usec / (3600LL * 1000000LL));
2175  } else if (usec % (60LL * 1000000LL) == 0 && usec >= (60LL * (int64_t) pow(10, 6))) {
2176  return String::sprintf("%" PRId64 "min", usec / (60LL * 1000000LL));
2177  } else if (usec % 1000000LL == 0 && usec >= (int64_t) pow(10, 6)) {
2178  return String::sprintf("%" PRId64 "s", usec / 1000000LL);
2179  } else if (usec % 1000LL == 0 && usec >= 1000LL) {
2180  return String::sprintf("%" PRId64 "ms", usec / 1000LL);
2181  }
2182  } else {
2183  double adj = pow(10, decimals);
2184  std::string buf;
2185 
2186  if (usec >= (7LL * 86400LL * 1000000LL)) {
2187  double sec = (double) usec / 604800000000.0f;
2188 
2189  buf = String::sprintf("%gw", roundf(sec * adj) / adj);
2190  } else if (usec >= (86400LL * 1000000LL)) {
2191  double sec = (double) usec / 86400000000.0f;
2192 
2193  buf = String::sprintf("%gd", roundf(sec * adj) / adj);
2194  } else if (usec >= (3600LL * 1000000LL)) {
2195  double sec = (double) usec / 3600000000.0f;
2196 
2197  buf = String::sprintf("%gh", roundf(sec * adj) / adj);
2198  } else if (usec >= (60LL * 1000000LL)) {
2199  double sec = (double) usec / 60000000.0f;
2200 
2201  buf = String::sprintf("%gmin", roundf(sec * adj) / adj);
2202  } else if (usec >= 1000000LL) {
2203  double sec = (double) usec / 1000000.0f;
2204 
2205  buf = String::sprintf("%gs", roundf(sec * adj) / adj);
2206  } else if (usec >= 1000LL) {
2207  double sec = (double) usec / 1000.0f;
2208 
2209  buf = String::sprintf("%gms", roundf(sec * adj) / adj);
2210  }
2211 
2212 #if 0
2213  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
2214  size_t pos = buf.find("e+", 3);
2215 
2216  if (pos != buf.npos) {
2217  printf("FOFOFOFOFO\n");
2218  size_t off = buf.find_first_of("wdhms", pos + 2);
2219 
2220  buf.replace(pos, off - pos, "", 0);
2221  }
2222 
2223  return buf;
2224  }
2225 #else
2226  if (LIKELY(!buf.empty())) {
2227  return buf;
2228  }
2229 #endif
2230  }
2231 
2232  return String::sprintf("%" PRId64 "us", usec);
2233 }
2234 
2235 std::string String::duration(uint64_t usec, int decimals) throw () {
2236  if (decimals == 0) {
2237  if (usec % (7LLU * 86400LLU * 1000000LLU) == 0 && usec >= (7LLU * 86400LLU * 1000000LLU)) {
2238  return String::sprintf("%" PRIu64 "w", usec / (7LLU * 86400LLU * 1000000LLU));
2239  } else if (usec % (86400LLU * 1000000LLU) == 0 && usec >= (86400LLU * 1000000LLU)) {
2240  return String::sprintf("%" PRIu64 "d", usec / (86400LLU * 1000000LLU));
2241  } else if (usec % (3600LLU * 1000000LLU) == 0 && usec >= (3600LLU * 1000000LLU)) {
2242  return String::sprintf("%" PRIu64 "h", usec / (3600LLU * 1000000LLU));
2243  } else if (usec % (60LLU * 1000000LLU) == 0 && usec >= (60LLU * 1000000LLU)) {
2244  return String::sprintf("%" PRIu64 "min", usec / (60LLU * 1000000LLU));
2245  } else if (usec % 1000000LLU == 0 && usec >= 1000000LLU) {
2246  return String::sprintf("%" PRIu64 "s", usec / 1000000LLU);
2247  } else if (usec % 1000LLU == 0 && usec >= 1000LLU) {
2248  return String::sprintf("%" PRIu64 "ms", usec / 1000LLU);
2249  }
2250  } else {
2251  double adj = pow(10, decimals);
2252  std::string buf;
2253 
2254  if (usec >= (7LLU * 86400LLU * 1000000LLU)) {
2255  double sec = (double) usec / 604800000000.0f;
2256 
2257  buf = String::sprintf("%gw", roundf(sec * adj) / adj);
2258  } else if (usec >= (86400LLU * 1000000LLU)) {
2259  double sec = (double) usec / 86400000000.0f;
2260 
2261  buf = String::sprintf("%gd", roundf(sec * adj) / adj);
2262  } else if (usec >= (3600LLU * 1000000LLU)) {
2263  double sec = (double) usec / 3600000000.0f;
2264 
2265  buf = String::sprintf("%gh", roundf(sec * adj) / adj);
2266  } else if (usec >= (60LLU * 1000000LLU)) {
2267  double sec = (double) usec / 60000000.0f;
2268 
2269  buf = String::sprintf("%gmin", roundf(sec * adj) / adj);
2270  } else if (usec >= 1000000LLU) {
2271  double sec = (double) usec / 1000000.0f;
2272 
2273  buf = String::sprintf("%gs", roundf(sec * adj) / adj);
2274  } else if (usec >= 1000LLU) {
2275  double sec = (double) usec / 1000.0f;
2276 
2277  buf = String::sprintf("%gms", roundf(sec * adj) / adj);
2278  }
2279 
2280 #if 0
2281  if (LIKELY(!buf.empty())) { /* Chop off the mantissa. */
2282  size_t pos = buf.find("e+", 3);
2283 
2284  if (pos != buf.npos) {
2285  size_t off = buf.find_first_of("wdhms", pos + 2);
2286 
2287  buf.replace(pos, off - pos, "", 0);
2288  }
2289 
2290  return buf;
2291  }
2292 #else
2293  if (LIKELY(!buf.empty())) {
2294  return buf;
2295  }
2296 #endif
2297  }
2298 
2299  return String::sprintf("%" PRIu64 "u", usec);
2300 }
2301 
2302 std::string String::scale(int64_t value, int decimals) throw () {
2303  if (decimals == 0) {
2304  if (value % 1000000000000000LL == 0 && value >= 1000000000000000LL) {
2305  return String::sprintf("%" PRId64 "q", value / 1000000000000000LL);
2306  } else if (value % 1000000000000LL == 0 && value >= 1000000000000LL) {
2307  return String::sprintf("%" PRId64 "t", value / 1000000000000LL);
2308  } else if (value % 1000000000LL == 0 && value >= 1000000000LL) {
2309  return String::sprintf("%" PRId64 "b", value / 1000000000LL);
2310  } else if (value % 1000000LL == 0 && value >= 1000000LL) {
2311  return String::sprintf("%" PRId64 "m", value / 1000000LL);
2312  } else if (value % 1000LL == 0 && value >= 1000LL) {
2313  return String::sprintf("%" PRId64 "k", value / 1000LL);
2314  }
2315  } else {
2316  double adj = pow(10, decimals);
2317  std::string buf;
2318 
2319  if (value >= 1000000000000000LL) {
2320  return String::sprintf("%0gq", roundf((double) value / 1000000000000000.0f * adj) / adj);
2321  } else if (value >= 1000000000000LL) {
2322  return String::sprintf("%0gt", roundf((double) value / 1000000000000.0f * adj) / adj);
2323  } else if (value >= 1000000000LL) {
2324  return String::sprintf("%0gb", roundf((double) value / 1000000000.0f * adj) / adj);
2325  } else if (value >= 1000000LL) {
2326  return String::sprintf("%0gm", roundf((double) value / 1000000.0f * adj) / adj);
2327  } else if (value >= 1000LL) {
2328  return String::sprintf("%0gk", roundf((double) value / 1000.0f * adj) / adj);
2329  }
2330  }
2331 
2332  return String::sprintf("%" PRId64, value);
2333 }
2334 
2335 std::string String::scale(uint64_t value, int decimals) throw () {
2336  if (decimals == 0) {
2337  if (value % 1000000000000000LLU == 0 && value >= 1000000000000000LLU) {
2338  return String::sprintf("%" PRIu64 "q", value / 1000000000000000LLU);
2339  } else if (value % 1000000000000LLU == 0 && value >= 1000000000000LLU) {
2340  return String::sprintf("%" PRIu64 "t", value / 1000000000000LLU);
2341  } else if (value % 1000000000LLU == 0 && value >= 1000000000LLU) {
2342  return String::sprintf("%" PRIu64 "b", value / 1000000000LLU);
2343  } else if (value % 1000000LLU == 0 && value >= 1000000LLU) {
2344  return String::sprintf("%" PRIu64 "m", value / 1000000LLU);
2345  } else if (value % 1000LLU == 0 && value >= 1000LLU) {
2346  return String::sprintf("%" PRIu64 "k", value / 1000LLU);
2347  }
2348  } else {
2349  double adj = pow(10, decimals);
2350  std::string buf;
2351 
2352  if (value >= 1000000000000000LLU) {
2353  return String::sprintf("%0gq", roundf((double) value / 1000000000000000.0f * adj) / adj);
2354  } else if (value >= 1000000000000LLU) {
2355  return String::sprintf("%0gt", roundf((double) value / 1000000000000.0f * adj) / adj);
2356  } else if (value >= 1000000000LLU) {
2357  return String::sprintf("%0gb", roundf((double) value / 1000000000.0f * adj) / adj);
2358  } else if (value >= 1000000LLU) {
2359  return String::sprintf("%0gm", roundf((double) value / 1000000.0f * adj) / adj);
2360  } else if (value >= 1000LLU) {
2361  return String::sprintf("%0gk", roundf((double) value / 1000.0f * adj) / adj);
2362  }
2363  }
2364 
2365  return String::sprintf("%" PRIu64, value);
2366 }
2367 
2368 std::string String::deflate(const std::string &src, Algo algo, int level) throw (CompressionException) {
2369  size_t src_len = src.size();
2370  std::string dst;
2371 
2372  if (algo == Zlib) {
2373  int ret;
2374  size_t buf_len = ::compressBound(src_len);
2375  char *buf = (char*) malloc(buf_len);
2376  z_stream strm;
2377 
2378  if (UNLIKELY(buf == NULL)) {
2379  THROW(CompressionException, "Failed to allocate inflate buffer of %zd bytes", buf_len);
2380  }
2381 
2382  memset(&strm, 0, sizeof(strm));
2383 
2384  if (UNLIKELY(::deflateInit(&strm, level) != Z_OK)) {
2385  free(buf);
2386 
2387  THROW(CompressionException, "deflateInit failure");
2388  }
2389 
2390  strm.next_in = (Bytef*) src.data();
2391  strm.avail_in = src_len;
2392 
2393  strm.next_out = (Bytef*) buf;
2394  strm.avail_out = buf_len;
2395 
2396  ret = ::deflate(&strm, Z_FINISH);
2397 
2398  if (ret == Z_STREAM_END) {
2399  dst.append(buf, strm.total_out);
2400  }
2401 
2402  free(buf);
2403  ::deflateEnd(&strm);
2404 
2405  if (UNLIKELY(ret != Z_STREAM_END)) {
2406  THROW(CompressionException, "Failure during zlib deflate (%d): %s", ret, strm.msg);
2407  }
2408  } else if (algo == LZ4) {
2409  ssize_t c;
2410  size_t buf_len = ::LZ4_compressBound(src_len) + sizeof(struct lz4);
2411  char *buf = (char*) malloc(buf_len);
2412  struct lz4 *lz4 = (struct lz4*) buf;
2413 
2414  if (UNLIKELY(buf == NULL)) {
2415  THROW(CompressionException, "Failed to allocate inflate buffer of %zd bytes", buf_len);
2416  }
2417 
2418  if (UNLIKELY((c = ::LZ4_compress_default(src.data(), lz4->data, src_len, buf_len)) < 0)) {
2419  free(buf);
2420 
2421  THROW(CompressionException, "Failure during LZ4 deflate");
2422  }
2423 
2424  lz4->magic = 0x184D2204;
2425  lz4->size = src_len;
2426 
2427  dst.append(buf, c + sizeof(struct lz4));
2428 
2429  free(buf);
2430  } else if (algo == Gzip) { /* Same as Zlib, but with RFC 1952 GZIP file format specification added - http://www.gzip.org/zlib/rfc-gzip.html */
2431  int ret;
2432  size_t src_len = src.size();
2433  size_t buf_len = ::compressBound(src_len) + sizeof(gzip_header) + 8;
2434  char *buf = (char*) malloc(buf_len);
2435  unsigned long crc = ::crc32(0L, Z_NULL, 0);
2436  z_stream strm;
2437 
2438  if (UNLIKELY(buf == NULL)) {
2439  THROW(CompressionException, "Failed to allocate inflate buffer of %zd bytes", buf_len);
2440  }
2441 
2442  memset(&strm, 0, sizeof(strm));
2443 
2444  if (UNLIKELY(::deflateInit2(&strm, level, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK)) {
2445  free(buf);
2446 
2447  THROW(CompressionException, "deflateInit2 failure");
2448  }
2449 
2450  /* Append gzip file header */
2451  dst.append((const char*) gzip_header, sizeof(gzip_header));
2452 
2453  /* Compress input data */
2454  strm.next_in = (Bytef*) src.data();
2455  strm.avail_in = src_len;
2456 
2457  crc = ::crc32(crc, strm.next_in, src_len);
2458 
2459  strm.next_out = (Bytef*) buf;
2460  strm.avail_out = buf_len;
2461 
2462  if (LIKELY((ret = ::deflate(&strm, Z_FINISH)) == Z_STREAM_END)) {
2463  dst.append(buf, strm.total_out);
2464  }
2465 
2466  free(buf);
2467  ::deflateEnd(&strm);
2468 
2469  if (UNLIKELY(ret != Z_STREAM_END)) {
2470  THROW(CompressionException, "Failure during gzip deflate (%d): %s", ret, strm.msg);
2471  }
2472 
2473  /* Append gzip footer */
2474  unsigned char c[8];
2475 
2476  c[0] = (crc >> 0) & 0xff;
2477  c[1] = (crc >> 8) & 0xff;
2478  c[2] = (crc >> 16) & 0xff;
2479  c[3] = (crc >> 24) & 0xff;
2480  c[4] = (src_len >> 0) & 0xff;
2481  c[5] = (src_len >> 8) & 0xff;
2482  c[6] = (src_len >> 16) & 0xff;
2483  c[7] = (src_len >> 24) & 0xff;
2484 
2485  dst.append((const char*) c, sizeof(c));
2486  } else {
2487  THROW(CompressionException, "Unsupported compression algorithm");
2488  }
2489 
2490  return dst;
2491 }
2492 
2493 std::vector<char> String::deflate(const std::vector<char> &src, Algo algo, int level, size_t size) throw (CompressionException) {
2494  size_t src_len = (size == 0) ? src.size() : size;
2495  std::vector<char> dst;
2496 
2497  if (algo == Zlib) {
2498  size_t buf_len = ::compressBound(src_len) + sizeof(gzip_header) + 8;
2499  char *buf = (char*) malloc(buf_len);
2500  z_stream strm;
2501 
2502  if (UNLIKELY(buf == NULL)) {
2503  THROW(CompressionException, "Failed to allocate inflate buffer of %zd bytes", buf_len);
2504  }
2505 
2506  memset(&strm, 0, sizeof(strm));
2507 
2508  if (UNLIKELY(::deflateInit(&strm, level) != Z_OK)) {
2509  free(buf);
2510 
2511  THROW(CompressionException, "deflateInit failure");
2512  }
2513 
2514  strm.next_in = (Bytef*) src.data();
2515  strm.avail_in = src_len;
2516 
2517  strm.next_out = (Bytef*) buf;
2518  strm.avail_out = buf_len;
2519 
2520  int ret = ::deflate(&strm, Z_FINISH);
2521 
2522  if (LIKELY(ret == Z_STREAM_END)) {
2523  for (size_t i = 0; i < strm.total_out; i++) {
2524  dst.push_back(buf[i]);
2525  }
2526  }
2527 
2528  free(buf);
2529  ::deflateEnd(&strm);
2530 
2531  if (UNLIKELY(ret != Z_STREAM_END)) {
2532  THROW(CompressionException, "Failure during deflate (%d): %s", ret, strm.msg);
2533  }
2534  } else if (algo == LZ4) {
2535  ssize_t c;
2536  size_t buf_len = ::LZ4_compressBound(src_len) + sizeof(struct lz4);
2537  char *buf = (char*) malloc(buf_len);
2538  struct lz4 *lz4 = (struct lz4*) buf;
2539 
2540  if (UNLIKELY(buf == NULL)) {
2541  THROW(CompressionException, "Failed to allocate inflate buffer of %zd bytes", buf_len);
2542  }
2543 
2544  if (UNLIKELY((c = ::LZ4_compress_default(src.data(), lz4->data, src_len, buf_len)) < 0)) {
2545  free(buf);
2546 
2547  THROW(CompressionException, "Failure during LZ4 deflate");
2548  }
2549 
2550  lz4->magic = 0x184D2204;
2551  lz4->size = src_len;
2552 
2553  dst.reserve(c + sizeof(struct lz4));
2554 
2555  for (size_t i = 0; i < c + sizeof(struct lz4); i++) {
2556  dst.push_back(buf[i]);
2557  }
2558 
2559  free(buf);
2560  } else if (algo == Gzip) { /* Same as Zlib, but with RFC 1952 GZIP file format specification added - http://www.gzip.org/zlib/rfc-gzip.html */
2561  int ret;
2562  size_t src_len = src.size();
2563  size_t buf_len = ::compressBound(src_len) + sizeof(gzip_header) + 8;
2564  char *buf = (char*) malloc(buf_len);
2565  unsigned long crc = ::crc32(0L, Z_NULL, 0);
2566  z_stream strm;
2567 
2568  if (UNLIKELY(buf == NULL)) {
2569  THROW(CompressionException, "Failed to allocate inflate buffer of %zd bytes", buf_len);
2570  }
2571 
2572  memset(&strm, 0, sizeof(strm));
2573 
2574  if (UNLIKELY(::deflateInit2(&strm, level, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK)) {
2575  free(buf);
2576 
2577  THROW(CompressionException, "deflateInit2 failure");
2578  }
2579 
2580  dst.reserve(sizeof(gzip_header) + (src_len / 10) + 8);
2581 
2582  /* Append gzip file header */
2583  for (size_t i = 0; i < sizeof(gzip_header); i++) {
2584  dst.push_back(gzip_header[i]);
2585  }
2586 
2587  /* Compress input data */
2588  strm.next_in = (Bytef*) src.data();
2589  strm.avail_in = src_len;
2590 
2591  crc = ::crc32(crc, strm.next_in, src_len);
2592 
2593  strm.next_out = (Bytef*) buf;
2594  strm.avail_out = buf_len;
2595 
2596  if (LIKELY((ret = ::deflate(&strm, Z_FINISH)) == Z_STREAM_END)) {
2597  dst.reserve(sizeof(gzip_header) + strm.total_out + 8);
2598 
2599  for (size_t i = 0; i < strm.total_out; i++) {
2600  dst.push_back(buf[i]);
2601  }
2602  }
2603 
2604  free(buf);
2605  ::deflateEnd(&strm);
2606 
2607  if (UNLIKELY(ret != Z_STREAM_END)) {
2608  THROW(CompressionException, "Failure during gzip deflate (%d): %s", ret, strm.msg);
2609  }
2610 
2611  /* Append gzip footer */
2612  unsigned char c[8];
2613 
2614  c[0] = (crc >> 0) & 0xff;
2615  c[1] = (crc >> 8) & 0xff;
2616  c[2] = (crc >> 16) & 0xff;
2617  c[3] = (crc >> 24) & 0xff;
2618  c[4] = (src_len >> 0) & 0xff;
2619  c[5] = (src_len >> 8) & 0xff;
2620  c[6] = (src_len >> 16) & 0xff;
2621  c[7] = (src_len >> 24) & 0xff;
2622 
2623  for (size_t i = 0; i < sizeof(c); i++) {
2624  dst.push_back(c[i]);
2625  }
2626  } else {
2627  THROW(CompressionException, "Unsupported compression algorithm");
2628  }
2629 
2630  return dst;
2631 }
2632 
2633 std::string String::inflate(const std::string &src, Algo algo) throw (CompressionException) {
2634  std::string dst;
2635 
2636  if (src.size() < 8) {
2637  THROW(CompressionException, "Malformed input to inflate");
2638  }
2639 
2640  if (algo == Auto) {
2641  const union magic *u = reinterpret_cast<const magic*>(src.data());
2642 
2643  if (u->u16 == 0x0178) { /* No/low compression (0-1) */
2644  algo = Zlib;
2645  } else if (u->u16 == 0x9c78) { /* Default compression (6) */
2646  algo = Zlib;
2647  } else if (u->u32 == 0x184D2204) { /* New Magic Number */
2648  algo = LZ4;
2649  } else if (u->u16 == 0x5e78) { /* Medium compression (2-5) */
2650  algo = Zlib;
2651  } else if (u->u16 == 0xDA78) { /* Best compression (7-9) */
2652  algo = Zlib;
2653  } else if (u->u16 == 0x8B1F) { /* Gzip */
2654  algo = Gzip;
2655  }
2656  }
2657 
2658  if (algo == Zlib) {
2659  int ret;
2660  char buf[CHUNK];
2661  z_stream strm;
2662 
2663  memset(&strm, 0, sizeof(strm));
2664 
2665  if (UNLIKELY(::inflateInit(&strm) != Z_OK)) {
2666  THROW(CompressionException, "inflateInit failure");
2667  }
2668 
2669  strm.next_in = (Bytef*) src.data();
2670  strm.avail_in = src.size();
2671 
2672  do {
2673  strm.next_out = (Bytef*) buf;
2674  strm.avail_out = sizeof(buf);
2675 
2676  ret = ::inflate(&strm, 0);
2677 
2678  if (dst.size() < strm.total_out) {
2679  dst.append(buf, strm.total_out - dst.size());
2680  }
2681  } while (ret == Z_OK);
2682 
2683  ::inflateEnd(&strm);
2684 
2685  if (UNLIKELY(ret != Z_STREAM_END)) {
2686  THROW(CompressionException, "Failure during inflate (%d): %s", ret, strm.msg);
2687  }
2688  } else if (algo == LZ4) {
2689  ssize_t c;
2690  struct lz4 *lz4 = (struct lz4*) src.c_str();
2691  char *buf = (char*) malloc(lz4->size);
2692 
2693  if (UNLIKELY(buf == NULL)) {
2694  THROW(CompressionException, "Failed to allocate inflate buffer");
2695  }
2696 
2697  if (UNLIKELY((c = ::LZ4_decompress_safe(lz4->data, buf, src.size() - sizeof(struct lz4), lz4->size)) < 0)) {
2698  free(buf);
2699 
2700  THROW(CompressionException, "Failure during LZ4 inflate");
2701  }
2702 
2703  dst.reserve(c);
2704  dst.assign(buf, c);
2705 
2706  free(buf);
2707  } else if (algo == Gzip) {
2708  int ret;
2709  char buf[CHUNK];
2710  z_stream strm;
2711 
2712  memset(&strm, 0, sizeof(strm));
2713 
2714  if (UNLIKELY(::inflateInit2(&strm, -MAX_WBITS) != Z_OK)) {
2715  THROW(CompressionException, "inflateInit failure");
2716  }
2717 
2718  strm.next_in = (Bytef*) src.data() + sizeof(gzip_header);
2719  strm.avail_in = src.size() - sizeof(gzip_header) - 8;
2720 
2721  do {
2722  strm.next_out = (Bytef*) buf;
2723  strm.avail_out = sizeof(buf);
2724 
2725  ret = ::inflate(&strm, 0);
2726 
2727  if (dst.size() < strm.total_out) {
2728  dst.append(buf, strm.total_out - dst.size());
2729  }
2730  } while (ret == Z_OK);
2731 
2732  ::inflateEnd(&strm);
2733 
2734  if (UNLIKELY(ret != Z_STREAM_END)) {
2735  THROW(CompressionException, "Failure during inflate (%d): %s", ret, strm.msg);
2736  }
2737  } else {
2738  THROW(CompressionException, "Unsupported compression algorithm");
2739  }
2740 
2741  return dst;
2742 }
2743 
2744 std::vector<char> String::inflate(const std::vector<char> &src, Algo algo, size_t size) throw (CompressionException) {
2745  size_t len = (size == 0) ? src.size() : size;
2746  std::vector<char> dst;
2747 
2748  if (len < 8) {
2749  THROW(CompressionException, "Malformed input to inflate");
2750  }
2751 
2752  if (algo == Auto) {
2753  const union magic *u = reinterpret_cast<const magic*>(src.data());
2754 
2755  if (u->u16 == 0x0178) { /* No/low compression (0-1) */
2756  algo = Zlib;
2757  } else if (u->u16 == 0x9c78) { /* Default compression (6) */
2758  algo = Zlib;
2759  } else if (u->u32 == 0x184D2204) { /* New Magic Number */
2760  algo = LZ4;
2761  } else if (u->u16 == 0x5e78) { /* Medium compression (2-5) */
2762  algo = Zlib;
2763  } else if (u->u16 == 0xDA78) { /* Best compression (7-9) */
2764  algo = Zlib;
2765  } else if (u->u32 == 0x184D2A50) { /* Legacy Magic Number */
2766  algo = LZ4;
2767  } else if (u->u16 == 0x8B1F) { /* Gzip */
2768  algo = Gzip;
2769  }
2770  }
2771 
2772  if (algo == Zlib) {
2773  int ret;
2774  char buf[CHUNK];
2775  z_stream strm;
2776 
2777  memset(&strm, 0, sizeof(strm));
2778 
2779  if (UNLIKELY(::inflateInit(&strm) != Z_OK)) {
2780  THROW(CompressionException, "inflateInit failure");
2781  }
2782 
2783  strm.next_in = (Bytef*) src.data();
2784  strm.avail_in = (size == 0) ? src.size(): size;
2785 
2786  do {
2787  strm.next_out = (Bytef*) buf;
2788  strm.avail_out = sizeof(buf);
2789 
2790  ret = ::inflate(&strm, 0);
2791 
2792  if (dst.size() < strm.total_out) {
2793  for (size_t i = 0, len = strm.total_out - dst.size(); i < len; i++) {
2794  dst.push_back(buf[i]);
2795  }
2796  }
2797  } while (ret == Z_OK);
2798 
2799  ::inflateEnd(&strm);
2800 
2801  if (UNLIKELY(ret != Z_STREAM_END)) {
2802  THROW(CompressionException, "Failure during inflate (%d): %s", ret, strm.msg);
2803  }
2804  } else if (algo == LZ4) {
2805  ssize_t c;
2806  struct lz4 *lz4 = (struct lz4*) src.data();
2807  char *buf = (char*) malloc(lz4->size);
2808 
2809  if (UNLIKELY(buf == NULL)) {
2810  THROW(CompressionException, "Failed to allocate inflate buffer");
2811  }
2812 
2813  if (UNLIKELY((c = ::LZ4_decompress_safe(lz4->data, buf, len - sizeof(struct lz4), lz4->size)) < 0)) {
2814  free(buf);
2815 
2816  THROW(CompressionException, "Failure during LZ4 inflate");
2817  }
2818 
2819  dst.reserve(c);
2820 
2821  for (size_t i = 0; i < (size_t) c; i++) {
2822  dst.push_back(buf[i]);
2823  }
2824 
2825  free(buf);
2826  } else if (algo == Gzip) {
2827  int ret;
2828  char buf[CHUNK];
2829  z_stream strm;
2830 
2831  memset(&strm, 0, sizeof(strm));
2832 
2833  if (UNLIKELY(::inflateInit2(&strm, -MAX_WBITS) != Z_OK)) {
2834  THROW(CompressionException, "inflateInit failure");
2835  }
2836 
2837  strm.next_in = (Bytef*) src.data() + sizeof(gzip_header);
2838  strm.avail_in = src.size() - sizeof(gzip_header) - 8;
2839 
2840  do {
2841  strm.next_out = (Bytef*) buf;
2842  strm.avail_out = sizeof(buf);
2843 
2844  ret = ::inflate(&strm, 0);
2845 
2846  if (dst.size() < strm.total_out) {
2847  for (size_t i = 0, len = strm.total_out - dst.size(); i < len; i++) {
2848  dst.push_back(buf[i]);
2849  }
2850  }
2851  } while (ret == Z_OK);
2852 
2853  ::inflateEnd(&strm);
2854 
2855  if (UNLIKELY(ret != Z_STREAM_END)) {
2856  THROW(CompressionException, "Failure during inflate (%d): %s", ret, strm.msg);
2857  }
2858  } else {
2859  THROW(CompressionException, "Unsupported compression algorithm");
2860  }
2861 
2862  return dst;
2863 }
2864 
2865 std::string String::encrypt(const std::string &buffer, const std::string &password, const std::string &salt, uint32_t seed) throw (CryptException) {
2866  Crypt crypt("twofish", "cfb", 256, seed);
2867 
2868  crypt.setFlipSeed(CRYPT_SERIAL_XOR);
2869 
2870  if (!crypt.setPassword(password.c_str(), salt.c_str())) {
2871  THROW(CryptException, "Failed to set password and salt");
2872  }
2873 
2874  std::string buf(buffer, 0); // Use substr constructor to prevent shared buffer from internal copy-on-write
2875 
2876  if (!crypt.encrypt((char*) buf.data(), buf.size())) {
2877  for (size_t i = 0; i < buf.size(); i++) { /* Scrub buffer before release back to stack. */
2878  buf.at(i) = 0;
2879  }
2880 
2881  THROW(CryptException, "Failed to encrypt buffer");
2882  }
2883 
2884  return buf;
2885 }
2886 
2887 std::string& String::encrypt(std::string &buffer, const std::string &password, const std::string &salt, uint32_t seed) throw (CryptException) {
2888  Crypt crypt("twofish", "cfb", 256, seed);
2889 
2890  crypt.setFlipSeed(CRYPT_SERIAL_XOR);
2891 
2892  if (!crypt.setPassword(password.c_str(), salt.c_str())) {
2893  THROW(CryptException, "Failed to set password and salt");
2894  }
2895 
2896  if (!crypt.encrypt((char*) buffer.data(), buffer.size())) {
2897  THROW(CryptException, "Failed to encrypt buffer");
2898  }
2899 
2900  return buffer;
2901 }
2902 
2903 std::string String::decrypt(const std::string &buffer, const std::string &password, const std::string &salt, uint32_t seed) throw (CryptException) {
2904  Crypt crypt("twofish", "cfb", 256, seed);
2905 
2906  crypt.setFlipSeed(CRYPT_SERIAL_XOR);
2907 
2908  if (!crypt.setPassword(password.c_str(), salt.c_str())) {
2909  THROW(CryptException, "Failed to set password and salt");
2910  }
2911 
2912  std::string buf(buffer, 0); // Use substr constructor to prevent shared buffer from internal copy-on-write
2913 
2914  if (!crypt.decrypt((char*) buf.data(), buf.size())) {
2915  for (size_t i = 0; i < buf.size(); i++) { /* Scrub buffer before release back to stack. */
2916  buf.at(i) = 0;
2917  }
2918 
2919  THROW(CryptException, "Failed to decrypt buffer");
2920  }
2921 
2922  return buf;
2923 }
2924 
2925 std::string& String::decrypt(std::string &buffer, const std::string &password, const std::string &salt, uint32_t seed) throw (CryptException) {
2926  Crypt crypt("twofish", "cfb", 256, seed);
2927 
2928  crypt.setFlipSeed(CRYPT_SERIAL_XOR);
2929 
2930  if (!crypt.setPassword(password.c_str(), salt.c_str())) {
2931  THROW(CryptException, "Failed to set password and salt");
2932  }
2933 
2934  if (!crypt.decrypt((char*) buffer.data(), buffer.size())) {
2935  THROW(CryptException, "Failed to decrypt buffer");
2936  }
2937 
2938  return buffer;
2939 }
2940 
2941 std::string String::random(size_t len, const std::string &charset, uint32_t seed) throw () {
2942  struct drand48_data state;
2943  long int r;
2944  size_t size = charset.size();
2945  std::string buffer;
2946 
2947  buffer.reserve(len);
2948 
2949  if (seed == 0) {
2950  seed = ~(Time::gettimeofday_usec()) ^ 0xA5B65A69;
2951  }
2952 
2953  srand48_r(seed, &state);
2954 
2955  for (size_t i = 0; i < len; i++) {
2956  lrand48_r(&state, &r);
2957  char c = charset.at(r % (size - 1));
2958 
2959  buffer.push_back(c);
2960 
2961  }
2962 
2963  return buffer;
2964 }
2965 
2966 /* http://www.adp-gmbh.ch/cpp/common/base64.html
2967  base64.cpp and base64.h
2968 
2969  Copyright (C) 2004-2008 RenĂ© Nyffenegger
2970 
2971  This source code is provided 'as-is', without any express or implied
2972  warranty. In no event will the author be held liable for any damages
2973  arising from the use of this software.
2974 
2975  Permission is granted to anyone to use this software for any purpose,
2976  including commercial applications, and to alter it and redistribute it
2977  freely, subject to the following restrictions:
2978 
2979  1. The origin of this source code must not be misrepresented; you must not
2980  claim that you wrote the original source code. If you use this source code
2981  in a product, an acknowledgment in the product documentation would be
2982  appreciated but is not required.
2983 
2984  2. Altered source versions must be plainly marked as such, and must not be
2985  misrepresented as being the original source code.
2986 
2987  3. This notice may not be removed or altered from any source distribution.
2988 
2989  RenĂ© Nyffenegger rene.nyffenegger@adp-gmbh.ch
2990 */
2991 
2992 static const std::string base64_chars_std = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2993 static const std::string base64_chars_alt = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
2994 
2995 static inline bool is_base64(unsigned char c) {
2996  return (isalnum(c) || c == '+' || c == '/');
2997 }
2998 
2999 std::string String::base64_encode(unsigned char const *src, unsigned int in_len, bool standard) throw () { /* Added standard vs alternate chracter feature */
3000  std::string ret;
3001  int i = 0;
3002  int j = 0;
3003  unsigned char char_array_3[3];
3004  unsigned char char_array_4[4];
3005  const std::string &base64_chars = (standard) ? base64_chars_std : base64_chars_alt;
3006 
3007  while (in_len--) {
3008  char_array_3[i++] = *(src++);
3009  if (i == 3) {
3010  char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
3011  char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
3012  char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
3013  char_array_4[3] = char_array_3[2] & 0x3f;
3014 
3015  for (i = 0; (i < 4) ; i++) {
3016  ret += base64_chars[char_array_4[i]];
3017  }
3018 
3019  i = 0;
3020  }
3021  }
3022 
3023  if (i) {
3024  for (j = i; j < 3; j++) {
3025  char_array_3[j] = '\0';
3026  }
3027 
3028  char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
3029  char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
3030  char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
3031  char_array_4[3] = char_array_3[2] & 0x3f;
3032 
3033  for (j = 0; j < i + 1; j++) {
3034  ret += base64_chars[char_array_4[j]];
3035  }
3036 
3037  while (standard && i++ < 3) {
3038  ret += '=';
3039  }
3040  }
3041 
3042  return ret;
3043 }
3044 
3045 std::string String::base64_encode(const std::string &src, bool standard) throw () { /* Added std::string alternative */
3046  unsigned char const *p = (unsigned char const*) src.data();
3047 
3048  return base64_encode(p, src.size());
3049 }
3050 
3051 std::string String::base64_decode(const std::string &src, bool standard) throw () { /* Added standard vs alternate chracter feature */
3052  int in_len = src.size();
3053  int i = 0;
3054  int j = 0;
3055  int in_ = 0;
3056  unsigned char char_array_4[4], char_array_3[3];
3057  std::string ret;
3058  const std::string &base64_chars = (standard) ? base64_chars_std : base64_chars_alt;
3059 
3060  while (in_len-- && (src[in_] != '=') && is_base64(src[in_])) {
3061  char_array_4[i++] = src[in_];
3062  in_++;
3063 
3064  if (i == 4) {
3065  for (i = 0; i < 4; i++) {
3066  char_array_4[i] = base64_chars.find(char_array_4[i]);
3067  }
3068 
3069  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
3070  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
3071  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
3072 
3073  for (i = 0; i < 3; i++) {
3074  ret += char_array_3[i];
3075  }
3076 
3077  i = 0;
3078  }
3079  }
3080 
3081  if (i) {
3082  for (j = i; j < 4; j++) {
3083  char_array_4[j] = 0;
3084  }
3085 
3086  for (j = 0; j < 4; j++) {
3087  char_array_4[j] = base64_chars.find(char_array_4[j]);
3088  }
3089 
3090  char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
3091  char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
3092  char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
3093 
3094  for (j = 0; j < i - 1; j++) {
3095  ret += char_array_3[j];
3096  }
3097  }
3098 
3099  return ret;
3100 }
3101 
3102 bool String::isPrintable(const std::string &src) throw () {
3103  bool printable = true;
3104 
3105  for (auto i = src.begin(), end = src.end(); i != end; ++i) {
3106  if (!std::isprint(*i)) {
3107  printable = false;
3108  break;
3109  }
3110  }
3111 
3112  return printable;
3113 }
3114 
3115 /*
3116 ** vim: noet ts=3 sw=3
3117 */
Definition: String.cpp:34
Definition: String.cpp:39