1/* -*-c++-*- */
2/* osgEarth - Geospatial SDK for OpenSceneGraph
3 * Copyright 2019 Pelican Mapping
4 * http://osgearth.org
5 *
6 * osgEarth is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>
18 */
19#ifndef OSGEARTH_STRING_UTILS_H
20#define OSGEARTH_STRING_UTILS_H 1
21
22#include <osgEarth/Common>
23#include <osg/Vec3>
24#include <osg/Vec3d>
25#include <osg/Vec4>
26#include <osg/Vec4ub>
27#include <string>
28#include <algorithm>
29#include <vector>
30#include <sstream>
31#include <locale>
32#include <iomanip>
33#include <map>
34#include <set>
35#include <ctype.h>
36
37namespace osgEarth
38{
39    extern OSGEARTH_EXPORT const std::string EMPTY_STRING;
40
41    typedef std::vector<std::string> StringVector;
42    typedef std::set<std::string> StringSet;
43
44    /** Replaces all the instances of "pattern" with "replacement" in "in_out" */
45    extern OSGEARTH_EXPORT std::string& replaceIn(
46        std::string&       in_out,
47        const std::string& pattern,
48        const std::string& replacement );
49
50    /** Replaces all the instances of "pattern" with "replacement" in "in_out" (case-insensitive) */
51    extern OSGEARTH_EXPORT std::string& ciReplaceIn(
52        std::string&       in_out,
53        const std::string& pattern,
54        const std::string& replacement );
55
56    /**
57     * Trims whitespace from the ends of a string.
58     */
59    extern OSGEARTH_EXPORT std::string trim( const std::string& in );
60
61    /**
62     * Trims whitespace from the ends of a string; in-place modification on the string to reduce string copies.
63     */
64    extern OSGEARTH_EXPORT void trim2( std::string& str );
65
66    //! Removes leading and trailing whitespace, and replaces all other
67    //! whitespace with single spaces
68    extern OSGEARTH_EXPORT std::string trimAndCompress(const std::string& in);
69
70    /**
71     * True is "ref" starts with "pattern"
72     */
73    extern OSGEARTH_EXPORT bool startsWith(
74        const std::string& ref,
75        const std::string& pattern,
76        bool               caseSensitive =true,
77        const std::locale& locale        =std::locale() );
78
79    /**
80     * True is "ref" ends with "pattern"
81     */
82    extern OSGEARTH_EXPORT bool endsWith(
83        const std::string& ref,
84        const std::string& pattern,
85        bool               caseSensitive =true,
86        const std::locale& locale        =std::locale() );
87
88    /**
89     * Case-insensitive compare
90     */
91    extern OSGEARTH_EXPORT bool ciEquals(
92        const std::string& lhs,
93        const std::string& rhs,
94        const std::locale& local = std::locale() );
95
96    /**
97     * Case-insensitive STL comparator
98     */
99    struct OSGEARTH_EXPORT CIStringComp {
100        bool operator()(const std::string& lhs, const std::string& rhs) const;
101    };
102
103
104    extern OSGEARTH_EXPORT std::string joinStrings( const StringVector& input, char delim );
105
106    /** Returns a lower-case version of the input string. */
107    extern OSGEARTH_EXPORT std::string toLower( const std::string& input );
108
109    /** Parses a color string in the form "255 255 255 255" (r g b a [0..255]) into an OSG color. */
110    extern OSGEARTH_EXPORT osg::Vec4ub stringToColor(const std::string& str, osg::Vec4ub default_value);
111
112    /** Creates a string in the form "255 255 255 255" (r g b a [0..255]) from a color */
113    extern OSGEARTH_EXPORT std::string colorToString( const osg::Vec4ub& c );
114
115    /** Converts a string to a vec3f */
116    extern OSGEARTH_EXPORT osg::Vec3f stringToVec3f( const std::string& str, const osg::Vec3f& default_value );
117
118    /** Converts a vec3f to a string */
119    extern OSGEARTH_EXPORT std::string vec3fToString( const osg::Vec3f& v );
120
121    /** Parses an HTML color ("#rrggbb" or "#rrggbbaa") into an OSG color. */
122    extern OSGEARTH_EXPORT osg::Vec4f htmlColorToVec4f( const std::string& html );
123
124    /** Makes an HTML color ("#rrggbb" or "#rrggbbaa") from an OSG color. */
125    extern OSGEARTH_EXPORT std::string vec4fToHtmlColor( const osg::Vec4f& c );
126
127    /** Makes a valid filename out of a string */
128    extern OSGEARTH_EXPORT std::string toLegalFileName( const std::string& input, bool allowSubdir=false );
129
130    /** Generates a hashed integer for a string (poor man's MD5) */
131    extern OSGEARTH_EXPORT unsigned hashString( const std::string& input );
132
133    /** Same as hashString but returns a string value. */
134    extern OSGEARTH_EXPORT std::string hashToString(const std::string& input);
135
136    /**
137    * Gets the total number of seconds formatted as H:M:S
138    */
139    extern OSGEARTH_EXPORT std::string prettyPrintTime( double seconds );
140
141    /**
142    * Gets a pretty printed version of the given size in MB.
143    */
144    extern OSGEARTH_EXPORT std::string prettyPrintSize( double mb );
145
146    //------------------------------------------------------------------------
147    // conversion templates
148
149    // converts a string to primitive using serialization
150    template<typename T> inline T
151    as( const std::string& str, const T& default_value )
152    {
153        T temp = default_value;
154        std::istringstream strin( str );
155        if ( !strin.eof() ) strin >> temp;
156        return temp;
157    }
158
159    // template specialization for integers (to handle hex)
160#define AS_INT_DEC_OR_HEX(TYPE) \
161    template<> inline TYPE \
162    as< TYPE >(const std::string& str, const TYPE & dv) { \
163        TYPE temp = dv; \
164        std::istringstream strin( trim(str) ); \
165        if ( !strin.eof() ) { \
166            if ( str.length() >= 2 && str[0] == '0' && str[1] == 'x' ) { \
167                strin.seekg( 2 ); \
168                strin >> std::hex >> temp; \
169            } \
170            else { \
171                strin >> temp; \
172            } \
173        } \
174        return temp; \
175    }
176
177    AS_INT_DEC_OR_HEX(int)
178    AS_INT_DEC_OR_HEX(unsigned)
179    AS_INT_DEC_OR_HEX(short)
180    AS_INT_DEC_OR_HEX(unsigned short)
181    AS_INT_DEC_OR_HEX(long)
182    AS_INT_DEC_OR_HEX(unsigned long)
183
184    // template specialization for a bool
185    template<> inline bool
186    as<bool>( const std::string& str, const bool& default_value )
187    {
188        std::string temp = toLower(str);
189        return
190            temp == "true"  || temp == "yes" || temp == "on" ? true :
191            temp == "false" || temp == "no" || temp == "off" ? false :
192            default_value;
193    }
194
195    template<> inline osg::Vec3f
196    as<osg::Vec3f>( const std::string& str, const osg::Vec3f& default_value )
197    {
198        return stringToVec3f(str, default_value);
199    }
200
201    // template specialization for string
202    template<> inline std::string
203    as<std::string>( const std::string& str, const std::string& default_value )
204    {
205        return str;
206    }
207
208    // snips a substring and parses it.
209    template<typename T> inline bool
210    as(const std::string& in, unsigned start, unsigned len, T default_value)
211    {
212        std::string buf;
213        std::copy( in.begin()+start, in.begin()+start+len, std::back_inserter(buf) );
214        return as<T>(buf, default_value);
215    }
216
217    // converts a primitive to a string
218    // TODO: precision??
219    template<typename T> inline std::string
220    toString(const T& value)
221    {
222        std::stringstream out;
223		//out << std::setprecision(20) << std::fixed << value;
224		out << std::setprecision(20) <<  value;
225        std::string outStr;
226        outStr = out.str();
227        return outStr;
228    }
229
230    // template speciallization for a bool to print out "true" or "false"
231    template<> inline std::string
232    toString<bool>(const bool& value)
233    {
234        return value ? "true" : "false";
235    }
236
237    template<> inline std::string
238    toString<osg::Vec3f>(const osg::Vec3f& value)
239    {
240        return vec3fToString(value);
241    }
242
243    /**
244     * Assembles and returns an inline string using a stream-like << operator.
245     * Example:
246     *     std::string str = Stringify() << "Hello, world " << variable;
247     */
248    struct Stringify
249    {
250        operator std::string () const
251        {
252            std::string result;
253            result = buf.str();
254            return result;
255        }
256
257        template<typename T>
258        Stringify& operator << (const T& val) { buf << val; return (*this); }
259
260        Stringify& operator << (const Stringify& val) { buf << (std::string)val; return (*this); }
261
262    protected:
263        std::stringstream buf;
264    };
265
266    template<> inline
267    Stringify& Stringify::operator << <bool>(const bool& val) { buf << (val ? "true" : "false"); return (*this); }
268
269    template<> inline
270    Stringify& Stringify::operator << <osg::Vec3f>(const osg::Vec3f& val) {
271        buf << val.x() << " " << val.y() << " " << val.z(); return (*this); }
272
273    template<> inline
274    Stringify& Stringify::operator << <osg::Vec3d>(const osg::Vec3d& val ) {
275        buf << val.x() << " " << val.y() << " " << val.z(); return (*this); }
276
277    template<> inline
278    Stringify& Stringify::operator << <osg::Vec4f>(const osg::Vec4f& val) {
279        buf << val.r() << " " << val.g() << " " << val.b() << " " << val.a(); return (*this); }
280
281    /**
282     * Splits a string up into a vector of strings based on a set of
283     * delimiters, quotes, and rules.
284     */
285    class OSGEARTH_EXPORT StringTokenizer
286    {
287    public:
288        StringTokenizer( const std::string& delims =" \t\r\n", const std::string& quotes ="'\"" );
289
290        StringTokenizer(
291            const std::string& input, StringVector& output,
292            const std::string& delims =" \t\r\n", const std::string& quotes ="'\"",
293            bool keepEmpties =true, bool trimTokens =true);
294
295        void tokenize( const std::string& input, StringVector& output ) const;
296
297        bool& keepEmpties() { return _allowEmpties; }
298
299        bool& trimTokens() { return _trimTokens; }
300
301        void addDelim( char delim, bool keepAsToken =false );
302
303        void addDelims( const std::string& delims, bool keepAsTokens =false );
304
305        void addQuote( char delim, bool keepInToken =false );
306
307        void addQuotes( const std::string& delims, bool keepInTokens =false );
308
309    private:
310        typedef std::map<char,bool> TokenMap;
311        TokenMap _delims;
312        TokenMap _quotes;
313        bool     _allowEmpties;
314        bool     _trimTokens;
315    };
316}
317
318#endif // OSGEARTH_STRING_UTILS_H
319
320