textfileparser.h 12.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#ifndef TEXTFILEPARSER_H__
#define TEXTFILEPARSER_H__

#include "tgt/exception.h"
#include "tgt/filesystem.h"
#include "tgt/vector.h"

#include "core/tools/stringutils.h"

#include <map>
#include <functional>
#include <string>
#include <vector>

namespace TUMVis {

    /**
     * Helper class for parsing simple text files containing key-value pairs.
     * The file will be read in text mode and split into single key-value items using the template argument
     * functor of parse(). Finally, each item will be split into key and value using the given delimiters.
     *
     * \todo    Better vector support (e.g. "x,y,z" format)
     *          Test and debug o_O
     */
    class TextFileParser {
    public:
        /**
         * Item separator for letting each line in the file result in one key-value pair item.
         * \note    The behaviour is not implemented as functor but by template specialization!
         */
        struct ItemSeparatorLines {
            // no operator() to implement due to template specialization
        };

        /**
         * Creates a new text file parser with the given settings.
         * \param url               URL of file
         * \param caseSensitiveKeys Flag whether keys are case-sensitive or not
         * \param delimiters        Set of delimiters for separating key-value pair
         * \param whitespace        Set of characters identifying whitespace
         */
        TextFileParser(const std::string& url, bool caseSensitiveKeys, const std::string& delimiters, const std::string& whitespace = " \t");


        /**
         * Performs the parsing of the text file into key-value pairs.
         * The file will be read in text mode and split into single items using the template argument
schultezub's avatar
schultezub committed
48
         * functor \a T. Then, each item will be split into key-value pairs.
49
50
51
52
53
54
55
56
57
58
59
60
61
         * 
         * \sa TextFileParser::ItemSeparatorLines
         * \tparam  T   Functor for splitting the file into items, must implement std::unary_function<std::string, std::vector<std::string> >
         * \throw   tgt::FileException if file not found/not readable, tgt::CorruptedFileException on parsing errors during key-value pair parsing.
         */
        template<class T>
        void parse() throw (tgt::FileException, tgt::CorruptedFileException);

        /**
         * Checks whether there exists a token with the given key \a key.
         * \param key   The key to search for.
         * \return  True if a key-value pair with the given key is existent, otherwise false.
         */
schultezub's avatar
schultezub committed
62
        bool hasKey(const std::string& key) const;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

        /**
         * Returns the value to the given key \a key.
         * \param key   The key to search for.
         * \return      The corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent.
         */
        const std::string& getString(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the bool representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      Boolean representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        bool getBool(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the integer representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      Integer representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        int getInt(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the ivec2 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      ivec2 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::ivec2 getIvec2(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the ivec3 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      ivec3 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::ivec3 getIvec3(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the ivec4 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      ivec4 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::ivec4 getIvec4(const std::string& key) const throw (tgt::CorruptedFileException);


schultezub's avatar
schultezub committed
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
        /**
         * Returns the size_t representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      size_t representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        size_t getSizeT(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the svec2 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      svec2 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::svec2 getSvec2(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the svec3 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      svec3 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::svec3 getSvec3(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the svec4 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      svec4 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::svec4 getSvec4(const std::string& key) const throw (tgt::CorruptedFileException);


146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
        /**
         * Returns the float representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      Float representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        float getFloat(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the vec2 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      vec2 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::vec2 getVec2(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the vec3 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      vec3 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::vec3 getVec3(const std::string& key) const throw (tgt::CorruptedFileException);

        /**
         * Returns the vec4 representation of the value for the given key \a key.
         * \param key   The key to search for.
         * \return      vec4 representation for the corresponding value to the given key.
         * \throw       tgt::CorruptedFileException if no such key existent or conversion failed.
         */
        tgt::vec4 getVec4(const std::string& key) const throw (tgt::CorruptedFileException);


    protected:
        /**
         * Loads the text file and parses it into items.
         * Item parsing is done using the Functor of the template parameter.
         * 
         * \sa TextFileParser::ItemSeparatorLines
         * \tparam  T   Functor for splitting the file into items, must implement std::unary_function<std::string, std::vector<std::string> >
         * \throw   tgt::FileException if file not found/not readable, tgt::CorruptedFileException on parsing errors during key-value pair parsing.
         */
        template<class T>
        inline std::vector<std::string> readAndParseItems() const throw (tgt::FileException, tgt::CorruptedFileException) ;

        std::string _url;                               ///< URL of file
        bool _caseSensitiveKeys;                        ///< Flag whether keys are case-sensitive or not
        std::string _delimiters;                        ///< Set of delimiters for separating key-value pair
        std::string _whitespace;                        ///< Set of characters identifying whitespace

        std::map<std::string, std::string> _tokens;     ///< map of key-value pairs
    };

// - Template definitions -------------------------------------------------------------------------

    template<typename T>
    void TextFileParser::parse() throw (tgt::FileException, tgt::CorruptedFileException) {
        _tokens.clear();
        std::vector<std::string> items = readAndParseItems<T>();

        for (std::vector<std::string>::const_iterator it = items.begin(); it != items.end(); ++it) {
            std::vector<std::string> tokens = StringUtils::split(*it, _delimiters);
            if (tokens.size() == 2) {
                if (_caseSensitiveKeys)
                    _tokens.insert(std::make_pair(StringUtils::trim(tokens[0], _whitespace), StringUtils::trim(tokens[1], _whitespace)));
                else
                    _tokens.insert(std::make_pair(StringUtils::lowercase(StringUtils::trim(tokens[0], _whitespace)), StringUtils::trim(tokens[1], _whitespace)));
            }
            else {
                throw tgt::CorruptedFileException("Error parsing item '" + *it + "': expected delimiter.", _url);
            }
        }
    }

    template<typename T>
    inline std::vector<std::string> TUMVis::TextFileParser::readAndParseItems() const throw (tgt::FileException, tgt::CorruptedFileException) {
        tgt::File* file = FileSys.open(_url);
        if (!file || !file->isOpen())
            throw tgt::FileException("Could not open file " + _url + " for reading.", _url);

        // somewhat cumbersome but it works:
        // read file line-based, glue them back together and run item spitter.
        std::vector<std::string> lines;
        while (!file->eof()) {
            lines.push_back(file->getLine('\n'));
        }
        std::string data = StringUtils::join(lines, "\n");
schultezub's avatar
schultezub committed
233
234
        file->close();
        delete file;
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252

        T itemSplitter;
        return itemSplitter(data);
    }

// - Template specializations ---------------------------------------------------------------------

    /// Template specialization for avoiding redundant split-join-split of lines.
    template<>
    inline std::vector<std::string> TUMVis::TextFileParser::readAndParseItems<TextFileParser::ItemSeparatorLines>() const throw (tgt::FileException, tgt::CorruptedFileException) {
        tgt::File* file = FileSys.open(_url);
        if (!file || !file->isOpen())
            throw tgt::FileException("Could not open file " + _url + " for reading.", _url);

        std::vector<std::string> lines;
        while (!file->eof()) {
            lines.push_back(file->getLine());
        }
schultezub's avatar
schultezub committed
253
254
        file->close();
        delete file;
255
256
257
258
259
260
        return lines;
    }

}

#endif // TEXTFILEPARSER_H__