-/***************************************************************************
- escape.cpp - escaping of strings
- -------------------
- begin : Sun Nov 14 1999
- copyright : (C) 1999 by Intra2net AG
- email : info@intra2net.com
- ***************************************************************************/
+/*
+The software in this package is distributed under the GNU General
+Public License version 2 (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING.GPL.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file
+does not by itself cause the resulting work to be covered
+by the GNU General Public License.
+
+However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based
+on this file might be covered by the GNU General Public License.
+*/
+/** @file
+ *
+ * (c) Copyright 2007-2008 by Intra2net AG
+ */
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>
+#include <algorithm>
+#include <cmath> // for round()
+#include <climits>
#include <wchar.h>
#include <stdlib.h>
#include <iconv.h>
#include <i18n.h>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/foreach.hpp>
+
+#include <boost/assert.hpp>
+#include <boost/shared_ptr.hpp>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+
#include <stringfunc.hxx>
using namespace std;
-std::string iso_to_utf8(const std::string& isostring)
+namespace I2n
+{
+
+
+namespace
+{
+
+const std::string hexDigitsLower("0123456789abcdef");
+const std::string hexDigitsUpper("0123456789ABCDEF");
+
+
+struct UpperFunc
+{
+ char operator() (char c)
+ {
+ return std::toupper(c);
+ }
+}; // eo struct UpperFunc
+
+
+struct LowerFunc
{
- string result;
+ char operator() (char c)
+ {
+ return std::tolower(c);
+ }
+}; // eo struct LowerFunc
- iconv_t i2utf8 = iconv_open ("UTF-8", "ISO-8859-1");
- if (iso_to_utf8 == (iconv_t)-1)
- throw runtime_error("iconv can't convert from ISO-8859-1 to UTF-8");
+} // eo namespace <anonymous>
- size_t in_size=isostring.size();
- size_t out_size=in_size*4;
- char *buf = (char *)malloc(out_size+1);
- if (buf == NULL)
- throw runtime_error("out of memory for iconv buffer");
- const char *in = isostring.c_str();
- char *out = buf;
- iconv (i2utf8, &in, &in_size, &out, &out_size);
+/**
+ * default list of Whitespaces (" \t\r\n");
+ */
+const std::string Whitespaces = " \t\r\n";
+
+/**
+ * default list of lineendings ("\r\n");
+ */
+const std::string LineEndings= "\r\n";
+
+
+
+/**
+ * @brief checks if a string begins with a given prefix.
+ * @param[in,out] str the string which is tested
+ * @param prefix the prefix which should be tested for.
+ * @return @a true iff the prefix is not empty and the string begins with that prefix.
+ */
+bool has_prefix(const std::string& str, const std::string& prefix)
+{
+ if (prefix.empty() || str.empty() || str.size() < prefix.size() )
+ {
+ return false;
+ }
+ return str.compare(0, prefix.size(), prefix) == 0;
+} // eo has_prefix(const std::string&,const std::string&)
+
+
+/**
+ * @brief checks if a string ends with a given suffix.
+ * @param[in,out] str the string which is tested
+ * @param suffix the suffix which should be tested for.
+ * @return @a true iff the suffix is not empty and the string ends with that suffix.
+ */
+bool has_suffix(const std::string& str, const std::string& suffix)
+{
+ if (suffix.empty() || str.empty() || str.size() < suffix.size() )
+ {
+ return false;
+ }
+ return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
+} // eo has_suffix(const std::string&,const std::string&)
+
+
+/**
+ * cut off characters from a given list from front and end of a string.
+ * @param[in,out] str the string which should be trimmed.
+ * @param charlist the list of characters to remove from beginning and end of string
+ * @return the result string.
+ */
+std::string trim_mod(std::string& str, const std::string& charlist)
+{
+ // first: trim the beginning:
+ std::string::size_type pos= str.find_first_not_of (charlist);
+ if (pos == std::string::npos)
+ {
+ // whole string consists of charlist (or is already empty)
+ str.clear();
+ return str;
+ }
+ else if (pos>0)
+ {
+ // str starts with charlist
+ str.erase(0,pos);
+ }
+ // now let's look at the tail:
+ pos= str.find_last_not_of(charlist) +1; // note: we already know there is at least one other char!
+ if ( pos < str.size() )
+ {
+ str.erase(pos, str.size()-pos);
+ }
+ return str;
+} // eo trim_mod(std::string&,const std::string&)
+
+
+
+/**
+ * removes last character from a string when it is in a list of chars to be removed.
+ * @param[in,out] str the string.
+ * @param what the list of chars which will be tested for.
+ * @return the resulting string with last char removed (if applicable)
+ */
+std::string chomp_mod(std::string& str, const std::string& what)
+{
+ if (str.empty() || what.empty() )
+ {
+ return str;
+ }
+ if (what.find(str.at (str.size()-1) ) != std::string::npos)
+ {
+ str.erase(str.size() - 1);
+ }
+ return str;
+} // eo chomp_mod(std::string&,const std::string&)
+
+
+/**
+ * @brief converts a string to lower case.
+ * @param[in,out] str the string to modify.
+ * @return the string
+ */
+std::string to_lower_mod(std::string& str)
+{
+ std::transform(str.begin(), str.end(), str.begin(), LowerFunc() );
+ return str;
+} // eo to_lower_mod(std::string&)
+
+
+/**
+ * @brief converts a string to upper case.
+ * @param[in,out] str the string to modify.
+ * @return the string
+ */
+std::string to_upper_mod(std::string& str)
+{
+ std::transform( str.begin(), str.end(), str.begin(), UpperFunc() );
+ return str;
+} // eo to_upper_mod(std::string&)
+
+
+
+/**
+ * cut off characters from a given list from front and end of a string.
+ * @param str the string which should be trimmed.
+ * @param charlist the list of characters to remove from beginning and end of string
+ * @return the result string.
+ */
+std::string trim (const std::string& str, const std::string& charlist)
+{
+ // first: trim the beginning:
+ std::string::size_type pos0= str.find_first_not_of(charlist);
+ if (pos0 == std::string::npos)
+ {
+ // whole string consists of charlist (or is already empty)
+ return std::string();
+ }
+ // now let's look at the end:
+ std::string::size_type pos1= str.find_last_not_of(charlist);
+ return str.substr(pos0, pos1 - pos0 + 1);
+} // eo trim(const std:.string&,const std::string&)
+
+
+/**
+ * removes last character from a string when it is in a list of chars to be removed.
+ * @param str the string.
+ * @param what the list of chars which will be tested for.
+ * @return the resulting string with last char removed (if applicable)
+ */
+std::string chomp (const std::string& str, const std::string& what)
+{
+ if (str.empty() || what.empty() )
+ {
+ return str;
+ }
+ if (what.find(str.at (str.size()-1) ) != std::string::npos)
+ {
+ return str.substr(0, str.size()-1);
+ }
+ return str;
+} // eo chomp(const std:.string&,const std::string&)
+
+
+/**
+ * @brief returns a lower case version of a given string.
+ * @param str the string
+ * @return the lower case version of the string
+ */
+std::string to_lower (const std::string& str)
+{
+ std::string result(str);
+ return to_lower_mod(result);
+} // eo to_lower(const std::string&)
+
+
+/**
+ * @brief returns a upper case version of a given string.
+ * @param str the string
+ * @return the upper case version of the string
+ */
+std::string to_upper(const std::string& str)
+{
+ std::string result(str);
+ return to_upper_mod(result);
+} // eo to_upper(const std::string&)
+
+
+
+/**
+ * @brief removes a given suffix from a string.
+ * @param str the string.
+ * @param suffix the suffix which should be removed if the string ends with it.
+ * @return the string without the suffix.
+ *
+ * If the string ends with the suffix, it is removed. If the the string doesn't end
+ * with the suffix the original string is returned.
+ */
+std::string remove_suffix(const std::string& str, const std::string& suffix)
+{
+ if (has_suffix(str,suffix) )
+ {
+ return str.substr(0, str.size()-suffix.size() );
+ }
+ return str;
+} // eo remove_suffix(const std::string&,const std::string&)
+
+
+
+/**
+ * @brief removes a given prefix from a string.
+ * @param str the string.
+ * @param prefix the prefix which should be removed if the string begins with it.
+ * @return the string without the prefix.
+ *
+ * If the string begins with the prefix, it is removed. If the the string doesn't begin
+ * with the prefix the original string is returned.
+ */
+std::string remove_prefix(const std::string& str, const std::string& prefix)
+{
+ if (has_prefix(str,prefix) )
+ {
+ return str.substr( prefix.size() );
+ }
+ return str;
+} // eo remove_prefix(const std::string&,const std::string&)
+
+
+/**
+ * split a string to key and value delimited by a given delimiter.
+ * The resulting key and value strings are trimmed (Whitespaces removed at beginning and end).
+ * @param str the string which should be splitted.
+ * @param[out] key the resulting key
+ * @param[out] value the resulting value
+ * @param delimiter the delimiter between key and value; default is '='.
+ * @return @a true if the split was successful.
+ */
+bool pair_split(
+ const std::string& str,
+ std::string& key,
+ std::string& value,
+ char delimiter)
+{
+ std::string::size_type pos = str.find (delimiter);
+ if (pos == std::string::npos) return false;
+ key= str.substr(0,pos);
+ value= str.substr(pos+1);
+ trim_mod(key);
+ trim_mod(value);
+ return true;
+} // eo pair_split(const std::string&,std::string&,std::string&,char)
+
+
+/**
+ * splits a string by given delimiter
+ *
+ * @param[in] str the string which should be splitted.
+ * @param[out] result the list resulting from splitting @a str.
+ * @param[in] delimiter the delimiter (word/phrase) at which @a str should be splitted.
+ * @param[in] omit_empty should empty parts not be stored?
+ * @param[in] trim_list list of characters the parts should be trimmed by.
+ * (empty string results in no trim)
+ */
+void split_string(
+ const std::string& str,
+ std::list<std::string>& result,
+ const std::string& delimiter,
+ bool omit_empty,
+ const std::string& trim_list
+)
+{
+ std::string::size_type pos, last_pos=0;
+ bool delimiter_found= false;
+ while ( last_pos < str.size() && last_pos != std::string::npos)
+ {
+ pos= str.find(delimiter, last_pos);
+ std::string part;
+ if (pos == std::string::npos)
+ {
+ part= str.substr(last_pos);
+ delimiter_found= false;
+ }
+ else
+ {
+ part= str.substr(last_pos, pos-last_pos);
+ delimiter_found=true;
+ }
+ if (pos != std::string::npos)
+ {
+ last_pos= pos+ delimiter.size();
+ }
+ else
+ {
+ last_pos= std::string::npos;
+ }
+ if (!trim_list.empty() ) trim_mod (part, trim_list);
+ if (omit_empty && part.empty() ) continue;
+ result.push_back( part );
+ }
+ // if the string ends with a delimiter we need to append an empty string if no omit_empty
+ // was given.
+ // (this way we keep the split result consistent to a join operation)
+ if (delimiter_found && !omit_empty)
+ {
+ result.push_back("");
+ }
+} // eo split_string(const std::string&,std::list< std::string >&,const std::string&,bool,const std::string&)
+
+
+/** call split_string with list<string>, converts result to vector; vector is clear()-ed first
+ *
+ * Note: Uses 3 O(n)-operations: list.size, vector.resize and std::swap_ranges;
+ * not sure whether there is a better way to do this
+ * */
+void split_string(
+ const std::string& str,
+ std::vector<std::string>& result,
+ const std::string& delimiter,
+ bool omit_empty,
+ const std::string& trim_list
+)
+{
+ std::list<std::string> tmp;
+ split_string(str, tmp, delimiter, omit_empty, trim_list);
+ std::size_t size = tmp.size(); // this is O(n)
+ result.clear();
+ result.resize(size); // also O(n)
+ std::swap_ranges(tmp.begin(), tmp.end(), result.begin()); // also O(n)
+}
+
+/**
+ * splits a string by a given delimiter
+ * @param str the string which should be splitted.
+ * @param delimiter delimiter the delimiter (word/phrase) at which @a str should be splitted.
+ * @param[in] omit_empty should empty parts not be stored?
+ * @param[in] trim_list list of characters the parts should be trimmed by.
+ * (empty string results in no trim)
+ * @return the list resulting from splitting @a str.
+ */
+std::list<std::string> split_string(
+ const std::string& str,
+ const std::string& delimiter,
+ bool omit_empty,
+ const std::string& trim_list
+)
+{
+ std::list<std::string> result;
+ split_string(str, result, delimiter, omit_empty, trim_list);
+ return result;
+} // eo split_string(const std::string&,const std::string&,bool,const std::string&)
+
+
+/**
+ * @brief joins a list of strings into a single string.
+ *
+ * This funtion is (basically) the reverse operation of @a split_string.
+ *
+ * @param parts the list of strings.
+ * @param delimiter the delimiter which is inserted between the strings.
+ * @return the joined string.
+ */
+std::string join_string(
+ const std::list< std::string >& parts,
+ const std::string& delimiter
+)
+{
+ std::string result;
+ if (! parts.empty() )
+ {
+ std::list< std::string >::const_iterator it= parts.begin();
+ result = *it;
+ while ( ++it != parts.end() )
+ {
+ result+= delimiter;
+ result+= *it;
+ }
+ }
+ return result;
+} // eo join_string(const std::list< std::string >&,const std::string&)
+
+
+/** @brief same as join_string for list, except uses a vector */
+std::string join_string(
+ const std::vector< std::string >& parts,
+ const std::string& delimiter
+)
+{
+ std::string result;
+ if (! parts.empty() )
+ {
+ std::vector< std::string >::const_iterator it= parts.begin();
+ result = *it;
+ while ( ++it != parts.end() )
+ {
+ result+= delimiter;
+ result+= *it;
+ }
+ }
+ return result;
+} // eo join_string(const std::vector< std::string >&,const std::string&)
+
+std::string join_string (
+ const char *const parts[], /* assumed NULL-terminated */
+ const std::string& delimiter
+)
+{
+ std::string result;
+
+ if (parts != NULL)
+ {
+ const char *const *cur = parts;
+
+ if (*cur != NULL) {
+ result = std::string (*cur);
+
+ while (*++cur != NULL) {
+ result += delimiter;
+ result += std::string (*cur);
+ }
+ }
+ }
+
+ return result;
+}
+
- buf[isostring.size()*4-out_size]=0;
- result=buf;
+/*
+** conversions
+*/
- free(buf);
- iconv_close (i2utf8);
+/**
+ * @brief returns a hex string from a binary string.
+ * @param str the (binary) string
+ * @param upper_case_digits determine whether to use upper case characters for digits A-F.
+ * @return the string in hex notation.
+ */
+std::string convert_binary_to_hex(
+ const std::string& str,
+ bool upper_case_digits
+)
+{
+ std::string result;
+ std::string hexDigits(upper_case_digits ? hexDigitsUpper : hexDigitsLower);
+ for ( std::string::const_iterator it= str.begin();
+ it != str.end();
+ ++it)
+ {
+ result.push_back( hexDigits[ ( (*it) >> 4) & 0x0f ] );
+ result.push_back( hexDigits[ (*it) & 0x0f ] );
+ }
+ return result;
+} // eo convert_binary_to_hex(const std::string&,bool)
+
+
+/**
+ * @brief converts a hex digit string to binary string.
+ * @param str hex digit string
+ * @return the binary string.
+ *
+ * The hex digit string may contains white spaces or colons which are treated
+ * as delimiters between hex digit groups.
+ *
+ * @todo rework the handling of half nibbles (consistency)!
+ */
+std::string convert_hex_to_binary(
+ const std::string& str
+)
+throw (std::runtime_error)
+{
+ std::string result;
+ char c= 0;
+ bool hasNibble= false;
+ bool lastWasWS= true;
+ for ( std::string::const_iterator it= str.begin();
+ it != str.end();
+ ++it)
+ {
+ std::string::size_type p = hexDigitsLower.find( *it );
+ if (p== std::string::npos)
+ {
+ p= hexDigitsUpper.find( *it );
+ }
+ if (p == std::string::npos)
+ {
+ if ( ( Whitespaces.find( *it ) != std::string::npos) // is it a whitespace?
+ or ( *it == ':') // or a colon?
+ )
+ {
+ // we treat that as a valid delimiter:
+ if (hasNibble)
+ {
+ // 1 nibble before WS is treate as lower part:
+ result.push_back(c);
+ // reset state:
+ hasNibble= false;
+ }
+ lastWasWS= true;
+ continue;
+ }
+ }
+ if (p == std::string::npos )
+ {
+ throw runtime_error("illegal character in hex digit string: " + str);
+ }
+ lastWasWS= false;
+ if (hasNibble)
+ {
+ c<<=4;
+ }
+ else
+ {
+ c=0;
+ }
+ c+= (p & 0x0f);
+ if (hasNibble)
+ {
+ //we already had a nibble, so a char is complete now:
+ result.push_back( c );
+ hasNibble=false;
+ }
+ else
+ {
+ // this is the first nibble of a new char:
+ hasNibble=true;
+ }
+ }
+ if (hasNibble)
+ {
+ //well, there is one nibble left
+ // let's do some heuristics:
+ if (lastWasWS)
+ {
+ // if the preceeding character was a white space (or a colon)
+ // we treat the nibble as lower part:
+ //( this is consistent with shortened hex notations where leading zeros are not noted)
+ result.push_back( c );
+ }
+ else
+ {
+ // if it was part of a hex digit chain, we treat it as UPPER part (!!)
+ result.push_back( c << 4 );
+ }
+ }
+ return result;
+} // eo convert_hex_to_binary(const std::string&)
+
+
+static list<string>& alloc_template_starts()
+{
+ static list<string> result;
+ if (result.empty())
+ {
+ result.push_back("std::list");
+ result.push_back("std::vector");
+ }
return result;
}
+string shorten_stl_types(const string &input)
+{
+ string output = input;
+
+ // first: replace fixed string for std::string
+ replace_all(output, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
+ "std::string");
+
+ // loop over list/vector/... that have an allocator, e.g.
+ // std::list< some_type_here, std::allocator<some_type_here> >
+ string::size_type start, comma, end, len, start_text_len;
+ int n_open_brackets;
+ string allocator_text;
+ BOOST_FOREACH(const string &start_text, alloc_template_starts())
+ {
+ start = 0;
+ comma = 0;
+ end = 0;
+ start_text_len = start_text.length();
+ while( (start=output.find(start_text+"<", start)) != string::npos )
+ {
+ len = output.length();
+ start += start_text_len+1; // start next iter and tests here after opening bracket
+
+ // now comes the tricky part: find matching ',' and the closing '>' even if "subtype" is template again
+ comma = start;
+ n_open_brackets = 1; // the bracket right after start_text counts as first
+ while (comma < len && n_open_brackets > 0)
+ {
+ if (output[comma] == ',' && n_open_brackets == 1)
+ break;
+ else if (output[comma] == '<')
+ ++n_open_brackets;
+ else if (output[comma] == '>')
+ --n_open_brackets;
+ ++comma;
+ }
+ end = comma+1;
+ while (end < len && n_open_brackets > 0)
+ {
+ if (output[end] == '<')
+ ++n_open_brackets;
+ else if (output[end] == '>')
+ {
+ --n_open_brackets;
+ if (n_open_brackets == 0)
+ break; // do not increment end
+ }
+ ++end;
+ }
+
+ // check that start < comma < end < len && n_open_brackets == 0
+ if (start >= comma || comma >= end || end >= len || n_open_brackets != 0)
+ continue; // input seems to be of unexpected form
+
+ // check that type in allocator is same as until comma
+ string type = output.substr(start, comma-start);
+ if (type[type.length()-1] == '>')
+ allocator_text = string("std::allocator<") + type + " > ";
+ else
+ allocator_text = string("std::allocator<") + type + "> ";
+ if (output.substr(comma+2, end-comma-2) == allocator_text)
+ output.replace(comma+2, end-comma-2, "_alloc_");
+ }
+ }
+
+ return output;
+}
+
+typedef boost::shared_ptr<BIO> BIO_Ptr;
+
+/**
+* @brief Converts openssl generic input/output to std::string
+*
+* Code adapted from keymakerd.
+*
+* @param bio Openssl's generic input/output
+* @return :string STL string
+**/
+static std::string _convert_BIO_to_string(BIO *input)
+{
+ std::string rtn;
+
+ char *output = NULL;
+ long written = BIO_get_mem_data(input, &output);
+ if (written <= 0 || output == NULL)
+ return rtn;
+
+ rtn.assign(output, written); //lint !e534 !e732
+ return rtn;
+} //lint !e1764
+
+/**
+ * @brief base64 encode a string using OpenSSL base64 functions
+ *
+ * Data size limit is 2GB on 32 bit (LONG_MAX)
+ *
+ * @param input String to encode
+ * @param one_line Encode all data as one line, no wrapping with line feeds
+ * @return base64 encoded string
+ */
+std::string base64_encode(const std::string &input, bool one_line)
+{
+ // check for empty buffer
+ if (input.empty())
+ return input;
+
+ // safety check to ensure our check afer BIO_write() works
+ if (input.size() >= LONG_MAX)
+ throw runtime_error("base64 encode: Too much data");
+
+ // setup encoder. Note: BIO_free_all frees both BIOs.
+ BIO_Ptr base64_encoder(BIO_new(BIO_f_base64()), BIO_free_all);
+ BIO *encoder_bio = base64_encoder.get();
+ if (one_line)
+ BIO_set_flags(encoder_bio, BIO_FLAGS_BASE64_NO_NL);
+
+ // chain output buffer and encoder together
+ BIO *encoded_result = BIO_new(BIO_s_mem());
+ BIO_push(encoder_bio, encoded_result);
+
+ // encode
+ long written = BIO_write(encoder_bio, input.c_str(), input.size());
+ if ((unsigned)written != input.size())
+ {
+ ostringstream out;
+ out << "base64 encoding failed: input size: "
+ << input.size() << " vs. output size: " << written;
+ throw runtime_error(out.str());
+ }
+ if (BIO_flush(encoder_bio) != 1)
+ throw runtime_error("base64 encode: BIO_flush() failed");
+
+ return _convert_BIO_to_string(encoded_result);
+}
+
+/**
+ * @brief base64 decode a string using OpenSSL base64 functions
+ *
+ * @param input String to decode
+ * @param one_line Expect all base64 data in one line. Input with line feeds will fail.
+ * @return base64 decoded string
+ */
+std::string base64_decode(const std::string &input, bool one_line)
+{
+ // check for empty buffer
+ if (input.empty())
+ return input;
+
+ // safety check for BIO_new_mem_buf()
+ if (input.size() >= INT_MAX)
+ throw runtime_error("base64 decode: Too much data");
+
+ // setup encoder. Note: BIO_free_all frees both BIOs.
+ BIO_Ptr base64_decoder(BIO_new(BIO_f_base64()), BIO_free_all);
+ BIO *bio_base64 = base64_decoder.get();
+ if (one_line)
+ BIO_set_flags(bio_base64, BIO_FLAGS_BASE64_NO_NL);
+
+ // chain input buffer and decoder together
+ BIO *bio_input = BIO_new_mem_buf((void*)input.c_str(), input.size());
+ bio_input = BIO_push(bio_base64, bio_input);
+
+ BIO_Ptr decoded_result(BIO_new(BIO_s_mem()), BIO_free_all);
+ BIO *bio_decoded = decoded_result.get();
+ const int convbuf_size = 512;
+ char convbuf[convbuf_size];
+
+ long read_bytes = 0;
+ while((read_bytes = BIO_read(bio_input, convbuf, convbuf_size)) > 0)
+ {
+ BOOST_ASSERT(read_bytes <= convbuf_size);
+ long written_bytes = BIO_write(bio_decoded, convbuf, read_bytes);
+ if (written_bytes != read_bytes)
+ {
+ ostringstream out;
+ out << "base64 decoding failed: read_bytes: "
+ << read_bytes << " vs. written_bytes: " << written_bytes;
+ throw runtime_error(out.str());
+ }
+ }
+ if (read_bytes == -2 || read_bytes == -1)
+ throw runtime_error("base64 decode: Error during decoding");
+
+ return _convert_BIO_to_string(bio_decoded);
+}
+
+} // eo namespace I2n
+
+
+
+
+std::string iso_to_utf8(const std::string& isostring)
+{
+ string result;
+
+ iconv_t i2utf8 = iconv_open("UTF-8", "ISO-8859-1");
+
+ if (iso_to_utf8 == (iconv_t)-1)
+ throw runtime_error("iconv can't convert from ISO-8859-1 to UTF-8");
+
+ size_t in_size=isostring.size();
+ size_t out_size=in_size*4;
+
+ char *buf = (char *)malloc(out_size+1);
+ if (buf == NULL)
+ throw runtime_error("out of memory for iconv buffer");
+
+ char *in = (char *)isostring.c_str();
+ char *out = buf;
+ iconv(i2utf8, &in, &in_size, &out, &out_size);
+
+ buf[isostring.size()*4-out_size]=0;
+
+ result=buf;
+
+ free(buf);
+ iconv_close(i2utf8);
+
+ return result;
+}
+
std::string utf8_to_iso(const std::string& utf8string)
{
- string result;
+ string result;
- iconv_t utf82iso = iconv_open ("ISO-8859-1","UTF-8");
+ iconv_t utf82iso = iconv_open("ISO-8859-1","UTF-8");
- if (utf82iso == (iconv_t)-1)
- throw runtime_error("iconv can't convert from UTF-8 to ISO-8859-1");
+ if (utf82iso == (iconv_t)-1)
+ throw runtime_error("iconv can't convert from UTF-8 to ISO-8859-1");
- size_t in_size=utf8string.size();
- size_t out_size=in_size;
+ size_t in_size=utf8string.size();
+ size_t out_size=in_size;
- char *buf = (char *)malloc(out_size+1);
- if (buf == NULL)
- throw runtime_error("out of memory for iconv buffer");
+ char *buf = (char *)malloc(out_size+1);
+ if (buf == NULL)
+ throw runtime_error("out of memory for iconv buffer");
- const char *in = utf8string.c_str();
- char *out = buf;
- iconv (utf82iso, &in, &in_size, &out, &out_size);
+ char *in = (char *)utf8string.c_str();
+ char *out = buf;
+ iconv(utf82iso, &in, &in_size, &out, &out_size);
- buf[utf8string.size()-out_size]=0;
+ buf[utf8string.size()-out_size]=0;
- result=buf;
+ result=buf;
- free(buf);
- iconv_close (utf82iso);
+ free(buf);
+ iconv_close(utf82iso);
- return result;
+ return result;
}
wchar_t* utf8_to_wbuf(const std::string& utf8string)
{
- iconv_t utf82wstr = iconv_open ("UCS-4LE","UTF-8");
+ iconv_t utf82wstr = iconv_open("UCS-4LE","UTF-8");
- if (utf82wstr == (iconv_t)-1)
- throw runtime_error("iconv can't convert from UTF-8 to UCS-4");
+ if (utf82wstr == (iconv_t)-1)
+ throw runtime_error("iconv can't convert from UTF-8 to UCS-4");
- size_t in_size=utf8string.size();
- size_t out_size=(in_size+1)*sizeof(wchar_t);
+ size_t in_size=utf8string.size();
+ size_t out_size= (in_size+1)*sizeof(wchar_t);
- wchar_t *buf = (wchar_t *)malloc(out_size);
- if (buf == NULL)
- throw runtime_error("out of memory for iconv buffer");
+ wchar_t *buf = (wchar_t *)malloc(out_size);
+ if (buf == NULL)
+ throw runtime_error("out of memory for iconv buffer");
- const char *in = utf8string.c_str();
- char *out = (char*)buf;
- if (iconv (utf82wstr, &in, &in_size, &out, &out_size) == -1)
- throw runtime_error("error converting char encodings");
+ char *in = (char *)utf8string.c_str();
+ char *out = (char*) buf;
+ if (iconv(utf82wstr, &in, &in_size, &out, &out_size) == (size_t)-1)
+ throw runtime_error("error converting char encodings");
- buf[((utf8string.size()+1)*sizeof(wchar_t)-out_size)/sizeof(wchar_t)]=0;
+ buf[ ( (utf8string.size()+1)*sizeof(wchar_t)-out_size) /sizeof(wchar_t) ]=0;
- iconv_close (utf82wstr);
+ iconv_close(utf82wstr);
- return buf;
+ return buf;
}
std::string utf7imap_to_utf8(const std::string& utf7imapstring)
{
- string result;
+ string result;
- iconv_t utf7imap2utf8 = iconv_open ("UTF-8","UTF-7-IMAP");
+ iconv_t utf7imap2utf8 = iconv_open("UTF-8","UTF-7-IMAP");
- if (utf7imap2utf8 == (iconv_t)-1)
- throw runtime_error("iconv can't convert from UTF-7-IMAP to UTF-8");
+ if (utf7imap2utf8 == (iconv_t)-1)
+ throw runtime_error("iconv can't convert from UTF-7-IMAP to UTF-8");
- size_t in_size=utf7imapstring.size();
- size_t out_size=in_size*4;
+ size_t in_size=utf7imapstring.size();
+ size_t out_size=in_size*4;
- char *buf = (char *)malloc(out_size+1);
- if (buf == NULL)
- throw runtime_error("out of memory for iconv buffer");
+ char *buf = (char *)malloc(out_size+1);
+ if (buf == NULL)
+ throw runtime_error("out of memory for iconv buffer");
- const char *in = utf7imapstring.c_str();
- char *out = buf;
- iconv (utf7imap2utf8, &in, &in_size, &out, &out_size);
+ char *in = (char *)utf7imapstring.c_str();
+ char *out = buf;
+ iconv(utf7imap2utf8, &in, &in_size, &out, &out_size);
- buf[utf7imapstring.size()*4-out_size]=0;
+ buf[utf7imapstring.size()*4-out_size]=0;
- result=buf;
+ result=buf;
- free(buf);
- iconv_close (utf7imap2utf8);
+ free(buf);
+ iconv_close(utf7imap2utf8);
- return result;
+ return result;
}
std::string utf8_to_utf7imap(const std::string& utf8string)
{
- string result;
+ string result;
- iconv_t utf82utf7imap = iconv_open ("UTF-7-IMAP", "UTF-8");
+ iconv_t utf82utf7imap = iconv_open("UTF-7-IMAP", "UTF-8");
- if (utf82utf7imap == (iconv_t)-1)
- throw runtime_error("iconv can't convert from UTF-7-IMAP to UTF-8");
+ if (utf82utf7imap == (iconv_t)-1)
+ throw runtime_error("iconv can't convert from UTF-7-IMAP to UTF-8");
- // UTF-7 is base64 encoded, a buffer 10x as large
- // as the utf-8 buffer should be enough. If not the string will be truncated.
- size_t in_size=utf8string.size();
- size_t out_size=in_size*10;
+ // UTF-7 is base64 encoded, a buffer 10x as large
+ // as the utf-8 buffer should be enough. If not the string will be truncated.
+ size_t in_size=utf8string.size();
+ size_t out_size=in_size*10;
- char *buf = (char *)malloc(out_size+1);
- if (buf == NULL)
- throw runtime_error("out of memory for iconv buffer");
+ char *buf = (char *)malloc(out_size+1);
+ if (buf == NULL)
+ throw runtime_error("out of memory for iconv buffer");
- const char *in = utf8string.c_str();
- char *out = buf;
- iconv (utf82utf7imap, &in, &in_size, &out, &out_size);
+ char *in = (char *)utf8string.c_str();
+ char *out = buf;
+ iconv(utf82utf7imap, &in, &in_size, &out, &out_size);
- buf[utf8string.size()*10-out_size]=0;
+ buf[utf8string.size()*10-out_size]= 0;
- result=buf;
+ result=buf;
- free(buf);
- iconv_close (utf82utf7imap);
+ free(buf);
+ iconv_close(utf82utf7imap);
- return result;
+ return result;
}
// Tokenize string by (html) tags
void tokenize_by_tag(vector<pair<string,bool> > &tokenized, const std::string &input)
{
- string::size_type pos, len = input.size();
- bool inside_tag = false;
- string current;
-
- for (pos = 0; pos < len; pos++) {
- if (input[pos] == '<') {
- inside_tag = true;
+ string::size_type pos, len = input.size();
+ bool inside_tag = false;
+ string current;
+
+ for (pos = 0; pos < len; pos++)
+ {
+ if (input[pos] == '<')
+ {
+ inside_tag = true;
+
+ if (!current.empty() )
+ {
+ tokenized.push_back( make_pair(current, false) );
+ current = "";
+ }
+
+ current += input[pos];
+ }
+ else if (input[pos] == '>' && inside_tag)
+ {
+ current += input[pos];
+ inside_tag = false;
+ if (!current.empty() )
+ {
+ tokenized.push_back( make_pair(current, true) );
+ current = "";
+ }
+ }
+ else
+ current += input[pos];
+ }
+
+ // String left over in buffer?
+ if (!current.empty() )
+ tokenized.push_back( make_pair(current, false) );
+} // eo tokenize_by_tag
- if (!current.empty()) {
- tokenized.push_back(make_pair(current, false));
- current = "";
- }
-
- current += input[pos];
- } else if (input[pos] == '>' && inside_tag) {
- current += input[pos];
- inside_tag = false;
- if (!current.empty()) {
- tokenized.push_back(make_pair(current, true));
- current = "";
- }
- } else
- current += input[pos];
- }
-
- // String left over in buffer?
- if (!current.empty())
- tokenized.push_back(make_pair(current, false));
-}
std::string strip_html_tags(const std::string &input)
{
- // Pair first: string, second: isTag
- vector<pair<string,bool> > tokenized;
- tokenize_by_tag(tokenized, input);
+ // Pair first: string, second: isTag
+ vector<pair<string,bool> > tokenized;
+ tokenize_by_tag (tokenized, input);
- string output;
- vector<pair<string,bool> >::const_iterator token, tokens_end = tokenized.end();
- for (token = tokenized.begin(); token != tokens_end; token++)
- if (!token->second)
- output += token->first;
+ string output;
+ vector<pair<string,bool> >::const_iterator token, tokens_end = tokenized.end();
+ for (token = tokenized.begin(); token != tokens_end; ++token)
+ if (!token->second)
+ output += token->first;
+
+ return output;
+} // eo strip_html_tags
- return output;
-}
// Smart-encode HTML en
string smart_html_entities(const std::string &input)
{
- // Pair first: string, second: isTag
- vector<pair<string,bool> > tokenized;
- tokenize_by_tag(tokenized, input);
-
- string output;
- vector<pair<string,bool> >::const_iterator token, tokens_end = tokenized.end();
- for (token = tokenized.begin(); token != tokens_end; token++) {
- // keep HTML tags as they are
- if (token->second)
- output += token->first;
- else
- output += html_entities(token->first);
- }
-
- return output;
+ // Pair first: string, second: isTag
+ vector<pair<string,bool> > tokenized;
+ tokenize_by_tag (tokenized, input);
+
+ string output;
+ vector<pair<string,bool> >::const_iterator token, tokens_end = tokenized.end();
+ for (token = tokenized.begin(); token != tokens_end; ++token)
+ {
+ // keep HTML tags as they are
+ if (token->second)
+ output += token->first;
+ else
+ output += html_entities(token->first);
+ }
+
+ return output;
}
+
string::size_type find_8bit(const std::string &str)
{
- string::size_type l=str.size();
- for (string::size_type p=0; p < l; p++)
- if (static_cast<unsigned char>(str[p]) > 127)
- return p;
+ string::size_type l=str.size();
+ for (string::size_type p=0; p < l; p++)
+ if (static_cast<unsigned char>(str[p]) > 127)
+ return p;
- return string::npos;
+ return string::npos;
}
// encoded UTF-8 chars into HTML entities
string html_entities(std::string str)
{
- // Normal chars
- replace_all (str, "&", "&");
- replace_all (str, "\"", """);
- replace_all (str, "<", "<");
- replace_all (str, ">", ">");
-
- // Umlauts
- replace_all (str, "\xC3\xA4", "ä");
- replace_all (str, "\xC3\xB6", "ö");
- replace_all (str, "\xC3\xBC", "ü");
- replace_all (str, "\xC3\x84", "Ä");
- replace_all (str, "\xC3\x96", "Ö");
- replace_all (str, "\xC3\x9C", "Ü");
-
- // Misc
- replace_all (str, "\xC3\x9F", "ß");
-
- // conversion of remaining non-ASCII chars needed?
- // just do if needed because of performance
- if (find_8bit(str) != string::npos)
+ // Normal chars
+ replace_all (str, "&", "&");
+ replace_all (str, "<", "<");
+ replace_all (str, ">", ">");
+ replace_all (str, "\"", """);
+ replace_all (str, "'", "'");
+ replace_all (str, "/", "/");
+
+ // Umlauts
+ replace_all (str, "\xC3\xA4", "ä");
+ replace_all (str, "\xC3\xB6", "ö");
+ replace_all (str, "\xC3\xBC", "ü");
+ replace_all (str, "\xC3\x84", "Ä");
+ replace_all (str, "\xC3\x96", "Ö");
+ replace_all (str, "\xC3\x9C", "Ü");
+
+ // Misc
+ replace_all (str, "\xC3\x9F", "ß");
+
+ // conversion of remaining non-ASCII chars needed?
+ // just do if needed because of performance
+ if (find_8bit(str) != string::npos)
+ {
+ // convert to fixed-size encoding UTF-32
+ wchar_t* wbuf=utf8_to_wbuf(str);
+ ostringstream target;
+
+ // replace all non-ASCII chars with HTML representation
+ for (int p=0; wbuf[p] != 0; p++)
+ {
+ unsigned int c=wbuf[p];
+
+ if (c <= 127)
+ target << static_cast<unsigned char>(c);
+ else
+ target << "&#" << c << ';';
+ }
+
+ free(wbuf);
+
+ str=target.str();
+ }
+
+ return str;
+} // eo html_entities(std::string)
+
+// convert HTML entities to something that can be viewed on a basic text console (restricted to ASCII-7)
+string html_entities_to_console(std::string str)
+{
+ // Normal chars
+ replace_all (str, "&", "&");
+ replace_all (str, "<", "<");
+ replace_all (str, ">", ">");
+ replace_all (str, """, "\"");
+ replace_all (str, "'", "'");
+ replace_all (str, "/", "/");
+
+ // Umlauts
+ replace_all (str, "ä", "ae");
+ replace_all (str, "ö", "oe");
+ replace_all (str, "ü", "ue");
+ replace_all (str, "Ä", "Ae");
+ replace_all (str, "Ö", "Oe");
+ replace_all (str, "Ü", "Ue");
+
+ // Misc
+ replace_all (str, "ß", "ss");
+
+ return str;
+}
+
+// find_html_comments + remove_html_comments(str, comments)
+void remove_html_comments(string &str)
+{
+ vector<CommentZone> comments = find_html_comments(str);
+ remove_html_comments(str, comments);
+}
+
+// find all html comments, behaving correctly if they are nested; ignores comment tags ("<!--FOO .... BAR-->")
+// If there are invalid comments ("-->" before "<!--" or different number of closing and opening tags),
+// then the unknown index of corresponding start/end tag will be represented by a string::npos
+// Indices are from start of start tag until first index after closing tag
+vector<CommentZone> find_html_comments(const std::string &str)
+{
+ static const string START = "<!--";
+ static const string CLOSE = "-->";
+ static const string::size_type START_LEN = START.length();
+ static const string::size_type CLOSE_LEN = CLOSE.length();
+
+ vector<CommentZone> comments;
+
+ // in order to find nested comments, need either recursion or a stack
+ vector<string::size_type> starts; // stack of start tags
+
+ string::size_type pos = 0;
+ string::size_type len = str.length();
+ string::size_type next_start, next_close;
+
+ while (pos < len) // not really needed but just in case
{
- // convert to fixed-size encoding UTF-32
- wchar_t* wbuf=utf8_to_wbuf(str);
- ostringstream target;
+ next_start = str.find(START, pos);
+ next_close = str.find(CLOSE, pos);
- // replace all non-ASCII chars with HTML representation
- for (int p=0; wbuf[p] != 0; p++)
- {
- unsigned int c=wbuf[p];
+ if ( (next_start == string::npos) && (next_close == string::npos) )
+ break; // we are done
- if (c <= 127)
- target << static_cast<unsigned char>(c);
+ else if ( (next_start == string::npos) || (next_close < next_start) ) // close one comment (pop)
+ {
+ if (starts.empty()) // closing tag without a start
+ comments.push_back(CommentZone(string::npos, next_close+CLOSE_LEN));
else
- target << "&#" << c << ';';
+ {
+ comments.push_back(CommentZone(starts.back(), next_close+CLOSE_LEN));
+ starts.pop_back();
+ }
+ pos = next_close + CLOSE_LEN;
}
- free(wbuf);
+ else if ( (next_close == string::npos) || (next_start < next_close) ) // start a new comment (push)
+ {
+ starts.push_back(next_start);
+ pos = next_start + START_LEN;
+ }
+ }
- str=target.str();
+ // add comments that have no closing tag from back to front (important for remove_html_comments!)
+ while (!starts.empty())
+ {
+ comments.push_back(CommentZone(starts.back(), string::npos));
+ starts.pop_back();
}
- return str;
+ return comments;
+}
+
+// remove all html comments foundby find_html_comments
+void remove_html_comments(std::string &str, const vector<CommentZone> &comments)
+{
+ // remember position where last removal started
+ string::size_type last_removal_start = str.length();
+
+ // Go from back to front to not mess up indices.
+ // This requires that bigger comments, that contain smaller comments, come AFTER
+ // the small contained comments in the comments vector (i.e. comments are ordered by
+ // their closing tag, not their opening tag). This is true for results from find_html_comments
+ BOOST_REVERSE_FOREACH(const CommentZone &comment, comments)
+ {
+ if (comment.first == string::npos)
+ {
+ str = str.replace(0, comment.second, ""); // comment starts "before" str --> delete from start
+ break; // there can be no more
+ }
+ else if (comment.first >= last_removal_start)
+ {
+ continue; // this comment is inside another comment that we have removed already
+ }
+ else if (comment.second == string::npos) // comment ends "after" str --> delete until end
+ {
+ str = str.replace(comment.first, string::npos, "");
+ last_removal_start = comment.first;
+ }
+ else
+ {
+ str = str.replace(comment.first, comment.second-comment.first, "");
+ last_removal_start = comment.first;
+ }
+ }
}
bool replace_all(string &base, const char *ist, const char *soll)
{
- string i=ist;
- string s=soll;
- return replace_all(base,&i,&s);
+ string i=ist;
+ string s=soll;
+ return replace_all(base,&i,&s);
}
bool replace_all(string &base, const string &ist, const char *soll)
{
- string s=soll;
- return replace_all(base,&ist,&s);
+ string s=soll;
+ return replace_all(base,&ist,&s);
}
bool replace_all(string &base, const string *ist, const string *soll)
{
- return replace_all(base,*ist,*soll);
+ return replace_all(base,*ist,*soll);
}
bool replace_all(string &base, const char *ist, const string *soll)
{
- string i=ist;
- return replace_all(base,&i,soll);
+ string i=ist;
+ return replace_all(base,&i,soll);
}
bool replace_all(string &base, const string &ist, const string &soll)
{
- bool found_ist = false;
- string::size_type a=0;
+ bool found_ist = false;
+ string::size_type a=0;
- if (ist.empty())
- throw runtime_error("replace_all called with empty search string");
+ if (ist.empty() )
+ throw runtime_error ("replace_all called with empty search string");
- while((a=base.find(ist,a))!=string::npos)
- {
- base.replace(a,ist.size(),soll);
- a=a+soll.size();
- found_ist = true;
- }
-
- return found_ist;
+ while ( (a=base.find(ist,a) ) != string::npos)
+ {
+ base.replace(a,ist.size(),soll);
+ a=a+soll.size();
+ found_ist = true;
+ }
+
+ return found_ist;
}
-string to_lower(const string &src)
+/**
+ * @brief replaces all characters that could be problematic or impose a security risk when being logged
+ * @param str the original string
+ * @param replace_with the character to replace the unsafe chars with
+ * @return a string that is safe to send to syslog or other logfiles
+ *
+ * All chars between 0x20 (space) and 0x7E (~) (including) are considered safe for logging.
+ * See e.g. RFC 5424, section 8.2 or the posix character class "printable".
+ * This eliminates all possible problems with NUL, control characters, 8 bit chars, UTF8.
+ *
+ */
+std::string sanitize_for_logging(const std::string &str, const char replace_with)
{
- string dst = src;
+ std::string output=str;
- string::size_type pos, end = dst.size();
- for (pos = 0; pos < end; pos++)
- dst[pos] = tolower(dst[pos]);
+ const string::size_type len = output.size();
+ for (std::string::size_type p=0; p < len; p++)
+ if (output[p] < 0x20 || output[p] > 0x7E)
+ output[p]=replace_with;
- return dst;
+ return output;
}
-string to_upper(const string &src)
+#if 0
+string to_lower(const string &src)
{
- string dst = src;
+ string dst = src;
- string::size_type pos, end = dst.size();
- for (pos = 0; pos < end; pos++)
- dst[pos] = toupper(dst[pos]);
+ string::size_type pos, end = dst.size();
+ for (pos = 0; pos < end; pos++)
+ dst[pos] = tolower(dst[pos]);
- return dst;
+ return dst;
}
-string nice_unit_format (int input) {
- float size = input;
- int sizecount = 0;
-
- while (size > 1000) {
- size = size / 1000;
- sizecount++;
- }
+string to_upper(const string &src)
+{
+ string dst = src;
- float tmp; // round
- tmp = size*10;
- tmp += 0.5;
- tmp = int (tmp);
- tmp = float(tmp)/float(10);
- size = tmp;
-
- ostringstream out;
-
- out.setf (ios::fixed);
- out.precision(2);
- switch (sizecount) {
- case 1:
- out << size << i18n(" KBytes");
- break;
- case 2:
- out << size << i18n(" MBytes");
- break;
- case 3:
- out << size << i18n(" Gbytes");
- break;
- default:
- out << size << i18n(" Bytes");
- break;
- }
+ string::size_type pos, end = dst.size();
+ for (pos = 0; pos < end; pos++)
+ dst[pos] = toupper(dst[pos]);
- return out.str();
+ return dst;
}
-
-string escape(const string &s)
+#endif
+
+const int MAX_UNIT_FORMAT_SYMBOLS = 6;
+
+const string shortUnitFormatSymbols[MAX_UNIT_FORMAT_SYMBOLS] = {
+ " B",
+ " KB",
+ " MB",
+ " GB",
+ " TB",
+ " PB"
+};
+
+const string longUnitFormatSymbols[MAX_UNIT_FORMAT_SYMBOLS] = {
+ i18n_noop(" Bytes"),
+ i18n_noop(" KBytes"),
+ i18n_noop(" MBytes"),
+ i18n_noop(" GBytes"),
+ i18n_noop(" TBytes"),
+ i18n_noop(" PBytes")
+};
+
+
+static long double rounding_upwards(
+ const long double number,
+ const int rounding_multiplier
+)
{
- string out(s);
- string::size_type p;
+ long double rounded_number;
+ rounded_number = number * rounding_multiplier;
+ rounded_number += 0.5;
+ rounded_number = (int64_t) (rounded_number);
+ rounded_number = (long double) (rounded_number) / (long double) (rounding_multiplier);
- p=0;
- while ((p=out.find_first_of("\"\\",p))!=out.npos)
- {
- out.insert(p,"\\");
- p+=2;
- }
+ return rounded_number;
+}
- p=0;
- while ((p=out.find_first_of("\r",p))!=out.npos)
- {
- out.replace(p,1,"\\r");
- p+=2;
- }
- p=0;
- while ((p=out.find_first_of("\n",p))!=out.npos)
- {
- out.replace(p,1,"\\n");
- p+=2;
- }
+string nice_unit_format(
+ const int64_t input,
+ const UnitFormat format,
+ const UnitBase base
+)
+{
+ // select the system of units (decimal or binary)
+ int multiple = 0;
+ if (base == UnitBase1000)
+ {
+ multiple = 1000;
+ }
+ else
+ {
+ multiple = 1024;
+ }
+
+ long double size = input;
+
+ // check the size of the input number to fit in the appropriate symbol
+ int sizecount = 0;
+ while (size > multiple)
+ {
+ size = size / multiple;
+ sizecount++;
+
+ // rollback to the previous values and stop the loop when cannot
+ // represent the number length.
+ if (sizecount >= MAX_UNIT_FORMAT_SYMBOLS)
+ {
+ size = size * multiple;
+ sizecount--;
+ break;
+ }
+ }
+
+ // round the input number "half up" to multiples of 10
+ const int rounding_multiplier = 10;
+ size = rounding_upwards(size, rounding_multiplier);
+
+ // format the input number, placing the appropriate symbol
+ ostringstream out;
+ out.setf (ios::fixed);
+ if (format == ShortUnitFormat)
+ {
+ out.precision(1);
+ out << size << i18n( shortUnitFormatSymbols[sizecount].c_str() );
+ }
+ else
+ {
+ out.precision (2);
+ out << size << i18n( longUnitFormatSymbols[sizecount].c_str() );
+ }
+
+ return out.str();
+} // eo nice_unit_format(int input)
+
+
+string nice_unit_format(
+ const double input,
+ const UnitFormat format,
+ const UnitBase base
+)
+{
+ // round as double and cast to int64_t
+ // cast raised overflow error near max val of int64_t (~9.2e18, see unittest)
+ int64_t input_casted_and_rounded =
+ boost::numeric_cast<int64_t>( round(input) );
- out='"'+out+'"';
+ // now call other
+ return nice_unit_format( input_casted_and_rounded, format, base );
+} // eo nice_unit_format(double input)
- return out;
-}
-string descape(const string &s, int startpos, int &endpos)
+string escape(const string &s)
{
- string out;
+ string out(s);
+ string::size_type p;
- if (s.at(startpos) != '"')
- throw out_of_range("value not type escaped string");
+ p=0;
+ while ( (p=out.find_first_of("\"\\",p) ) !=out.npos)
+ {
+ out.insert (p,"\\");
+ p+=2;
+ }
- out=s.substr(startpos+1);
- string::size_type p=0;
+ p=0;
+ while ( (p=out.find_first_of("\r",p) ) !=out.npos)
+ {
+ out.replace (p,1,"\\r");
+ p+=2;
+ }
- // search for the end of the string
- while((p=out.find("\"",p))!=out.npos)
- {
- int e=p-1;
- bool escaped=false;
+ p=0;
+ while ( (p=out.find_first_of("\n",p) ) !=out.npos)
+ {
+ out.replace (p,1,"\\n");
+ p+=2;
+ }
- // the " might be escaped with a backslash
- while(e>=0 && out.at(e)=='\\')
- {
- if (escaped == false)
- escaped=true;
- else
- escaped=false;
-
- e--;
- }
-
- if (escaped==false)
- break;
- else
- p++;
- }
+ out='"'+out+'"';
- // we now have the end of the string
- out=out.substr(0,p);
+ return out;
+} // eo scape(const std::string&)
- // tell calling prog about the endposition
- endpos=startpos+p+1;
- // descape all \ stuff inside the string now
- p=0;
- while((p=out.find_first_of("\\",p))!=out.npos)
- {
- switch(out.at(p+1))
- {
- case 'r':
+string descape(const string &s, int startpos, int &endpos)
+{
+ string out;
+
+ if (s.at(startpos) != '"')
+ throw out_of_range("value not type escaped string");
+
+ out=s.substr(startpos+1);
+ string::size_type p=0;
+
+ // search for the end of the string
+ while ( (p=out.find("\"",p) ) !=out.npos)
+ {
+ int e=p-1;
+ bool escaped=false;
+
+ // the " might be escaped with a backslash
+ while (e>=0 && out.at (e) =='\\')
+ {
+ if (escaped == false)
+ escaped=true;
+ else
+ escaped=false;
+
+ e--;
+ }
+
+ if (escaped==false)
+ break;
+ else
+ p++;
+ }
+
+ // we now have the end of the string
+ out=out.substr(0,p);
+
+ // tell calling prog about the endposition
+ endpos=startpos+p+1;
+
+ // descape all \ stuff inside the string now
+ p=0;
+ while ( (p=out.find_first_of("\\",p) ) !=out.npos)
+ {
+ switch (out.at(p+1) )
+ {
+ case 'r':
out.replace(p,2,"\r");
break;
- case 'n':
+ case 'n':
out.replace(p,2,"\n");
break;
- default:
+ default:
out.erase(p,1);
- }
- p++;
- }
+ }
+ p++;
+ }
+
+ return out;
+} // eo descape(const std::string&,int,int&)
- return out;
-}
string escape_shellarg(const string &input)
{
- string output = "'";
- string::const_iterator it, it_end = input.end();
- for (it = input.begin(); it != it_end; it++) {
- if ((*it) == '\'')
- output += "'\\'";
-
- output += *it;
- }
-
- output += "'";
- return output;
+ string output = "'";
+ string::const_iterator it, it_end = input.end();
+ for (it = input.begin(); it != it_end; ++it)
+ {
+ if ( (*it) == '\'')
+ output += "'\\'";
+
+ output += *it;
+ }
+
+ output += "'";
+ return output;
}