~ubuntu-branches/ubuntu/trusty/liblas/trusty-proposed

« back to all changes in this revision

Viewing changes to include/liblas/external/property_tree/detail/info_parser_read.hpp

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2014-01-05 17:00:29 UTC
  • mfrom: (7.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20140105170029-ddtp0j63x5jvck2u
Tags: 1.7.0+dfsg-2
Fixed missing linking of system boost component.
(closes: #733282)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ----------------------------------------------------------------------------
 
2
// Copyright (C) 2002-2006 Marcin Kalicinski
 
3
//
 
4
// Distributed under the Boost Software License, Version 1.0. 
 
5
// (See accompanying file LICENSE_1_0.txt or copy at 
 
6
// http://www.boost.org/LICENSE_1_0.txt)
 
7
//
 
8
// For more information, see www.boost.org
 
9
// ----------------------------------------------------------------------------
 
10
#ifndef LIBLAS_BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
 
11
#define LIBLAS_BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_READ_HPP_INCLUDED
 
12
 
 
13
#include "boost/property_tree/ptree.hpp"
 
14
#include "boost/property_tree/detail/info_parser_error.hpp"
 
15
#include "boost/property_tree/detail/info_parser_utils.hpp"
 
16
#include <iterator>
 
17
#include <string>
 
18
#include <stack>
 
19
#include <fstream>
 
20
#include <cctype>
 
21
 
 
22
namespace liblas { namespace property_tree { namespace info_parser
 
23
{
 
24
 
 
25
    // Expand known escape sequences
 
26
    template<class It>
 
27
    std::basic_string<typename std::iterator_traits<It>::value_type>
 
28
        expand_escapes(It b, It e)
 
29
    {
 
30
        typedef typename std::iterator_traits<It>::value_type Ch;
 
31
        std::basic_string<Ch> result;
 
32
        while (b != e)
 
33
        {
 
34
            if (*b == Ch('\\'))
 
35
            {
 
36
                ++b;
 
37
                if (b == e)
 
38
                {
 
39
                    BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
40
                        "character expected after backslash", "", 0));
 
41
                }
 
42
                else if (*b == Ch('0')) result += Ch('\0');
 
43
                else if (*b == Ch('a')) result += Ch('\a');
 
44
                else if (*b == Ch('b')) result += Ch('\b');
 
45
                else if (*b == Ch('f')) result += Ch('\f');
 
46
                else if (*b == Ch('n')) result += Ch('\n');
 
47
                else if (*b == Ch('r')) result += Ch('\r');
 
48
                else if (*b == Ch('t')) result += Ch('\t');
 
49
                else if (*b == Ch('v')) result += Ch('\v');
 
50
                else if (*b == Ch('"')) result += Ch('"');
 
51
                else if (*b == Ch('\'')) result += Ch('\'');
 
52
                else if (*b == Ch('\\')) result += Ch('\\');
 
53
                else
 
54
                    BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
55
                        "unknown escape sequence", "", 0));
 
56
            }
 
57
            else
 
58
                result += *b;
 
59
            ++b;
 
60
        }
 
61
        return result;
 
62
    }
 
63
 
 
64
    // Advance pointer past whitespace
 
65
    template<class Ch>
 
66
    void skip_whitespace(const Ch *&text)
 
67
    {
 
68
        using namespace std;
 
69
        while (isspace(*text))
 
70
            ++text;
 
71
    }
 
72
 
 
73
    // Extract word (whitespace delimited) and advance pointer accordingly
 
74
    template<class Ch>
 
75
    std::basic_string<Ch> read_word(const Ch *&text)
 
76
    {
 
77
        using namespace std;
 
78
        skip_whitespace(text);
 
79
        const Ch *start = text;
 
80
        while (!isspace(*text) && *text != Ch(';') && *text != Ch('\0'))
 
81
            ++text;
 
82
        return expand_escapes(start, text);
 
83
    }
 
84
 
 
85
    // Extract line (eol delimited) and advance pointer accordingly
 
86
    template<class Ch>
 
87
    std::basic_string<Ch> read_line(const Ch *&text)
 
88
    {
 
89
        using namespace std;
 
90
        skip_whitespace(text);
 
91
        const Ch *start = text;
 
92
        while (*text != Ch('\0') && *text != Ch(';'))
 
93
            ++text;
 
94
        while (text > start && isspace(*(text - 1)))
 
95
            --text;
 
96
        return expand_escapes(start, text);
 
97
    }
 
98
 
 
99
    // Extract string (inside ""), and advance pointer accordingly
 
100
    // Set need_more_lines to true if \ continuator found
 
101
    template<class Ch>
 
102
    std::basic_string<Ch> read_string(const Ch *&text, bool *need_more_lines)
 
103
    {
 
104
        skip_whitespace(text);
 
105
        if (*text == Ch('\"'))
 
106
        {
 
107
 
 
108
            // Skip "
 
109
            ++text;
 
110
 
 
111
            // Find end of string, but skip escaped "
 
112
            bool escaped = false;
 
113
            const Ch *start = text;
 
114
            while ((escaped || *text != Ch('\"')) && *text != Ch('\0'))
 
115
            {
 
116
                escaped = (!escaped && *text == Ch('\\'));
 
117
                ++text;
 
118
            }
 
119
 
 
120
            // If end of string found
 
121
            if (*text == Ch('\"'))
 
122
            {
 
123
                std::basic_string<Ch> result = expand_escapes(start, text++);
 
124
                skip_whitespace(text);
 
125
                if (*text == Ch('\\'))
 
126
                {
 
127
                    if (!need_more_lines)
 
128
                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
129
                            "unexpected \\", "", 0));
 
130
                    ++text;
 
131
                    skip_whitespace(text);
 
132
                    if (*text == Ch('\0') || *text == Ch(';'))
 
133
                        *need_more_lines = true;
 
134
                    else
 
135
                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
136
                            "expected end of line after \\", "", 0));
 
137
                }
 
138
                else
 
139
                    if (need_more_lines)
 
140
                        *need_more_lines = false;
 
141
                return result;
 
142
            }
 
143
            else
 
144
                BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
145
                    "unexpected end of line", "", 0));
 
146
 
 
147
        }
 
148
        else
 
149
            BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \"", "", 0));
 
150
    }
 
151
 
 
152
    // Extract key
 
153
    template<class Ch>
 
154
    std::basic_string<Ch> read_key(const Ch *&text)
 
155
    {
 
156
        skip_whitespace(text);
 
157
        if (*text == Ch('\"'))
 
158
            return read_string(text, NULL);
 
159
        else
 
160
            return read_word(text);
 
161
    }
 
162
 
 
163
    // Extract data
 
164
    template<class Ch>
 
165
    std::basic_string<Ch> read_data(const Ch *&text, bool *need_more_lines)
 
166
    {
 
167
        skip_whitespace(text);
 
168
        if (*text == Ch('\"'))
 
169
            return read_string(text, need_more_lines);
 
170
        else
 
171
        {
 
172
            *need_more_lines = false;
 
173
            return read_word(text);
 
174
        }
 
175
    }
 
176
 
 
177
    // Build ptree from info stream
 
178
    template<class Ptree, class Ch>
 
179
    void read_info_internal(std::basic_istream<Ch> &stream,
 
180
                            Ptree &pt,
 
181
                            const std::string &filename,
 
182
                            int include_depth)
 
183
    {
 
184
        typedef std::basic_string<Ch> str_t;
 
185
        // Possible parser states
 
186
        enum state_t {
 
187
            s_key,              // Parser expects key
 
188
            s_data,             // Parser expects data
 
189
            s_data_cont         // Parser expects data continuation
 
190
        };
 
191
 
 
192
        unsigned long line_no = 0;
 
193
        state_t state = s_key;          // Parser state
 
194
        Ptree *last = NULL;             // Pointer to last created ptree
 
195
        // Define line here to minimize reallocations
 
196
        str_t line;
 
197
 
 
198
        // Initialize ptree stack (used to handle nesting)
 
199
        std::stack<Ptree *> stack;
 
200
        stack.push(&pt);                // Push root ptree on stack initially
 
201
 
 
202
        try {
 
203
            // While there are characters in the stream
 
204
            while (stream.good()) {
 
205
                // Read one line from stream
 
206
                ++line_no;
 
207
                std::getline(stream, line);
 
208
                if (!stream.good() && !stream.eof())
 
209
                    BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
210
                        "read error", filename, line_no));
 
211
                const Ch *text = line.c_str();
 
212
 
 
213
                // If directive found
 
214
                skip_whitespace(text);
 
215
                if (*text == Ch('#')) {
 
216
                    // Determine directive type
 
217
                    ++text;     // skip #
 
218
                    std::basic_string<Ch> directive = read_word(text);
 
219
                    if (directive == convert_chtype<Ch, char>("include")) {
 
220
                        // #include
 
221
                        if (include_depth > 100) {
 
222
                            BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
223
                                "include depth too large, "
 
224
                                "probably recursive include",
 
225
                                filename, line_no));
 
226
                        }
 
227
                        str_t s = read_string(text, NULL);
 
228
                        std::string inc_name =
 
229
                            convert_chtype<char, Ch>(s.c_str());
 
230
                        std::basic_ifstream<Ch> inc_stream(inc_name.c_str());
 
231
                        if (!inc_stream.good())
 
232
                            BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
233
                                "cannot open include file " + inc_name,
 
234
                                filename, line_no));
 
235
                        read_info_internal(inc_stream, *stack.top(),
 
236
                                           inc_name, include_depth + 1);
 
237
                    } else {   // Unknown directive
 
238
                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
239
                            "unknown directive", filename, line_no));
 
240
                    }
 
241
 
 
242
                    // Directive must be followed by end of line
 
243
                    skip_whitespace(text);
 
244
                    if (*text != Ch('\0')) {
 
245
                        BOOST_PROPERTY_TREE_THROW(info_parser_error(
 
246
                            "expected end of line", filename, line_no));
 
247
                    }
 
248
 
 
249
                    // Go to next line
 
250
                    continue;
 
251
                }
 
252
 
 
253
                // While there are characters left in line
 
254
                while (1) {
 
255
 
 
256
                    // Stop parsing on end of line or comment
 
257
                    skip_whitespace(text);
 
258
                    if (*text == Ch('\0') || *text == Ch(';')) {
 
259
                        if (state == s_data)    // If there was no data set state to s_key
 
260
                            state = s_key;
 
261
                        break;
 
262
                    }
 
263
 
 
264
                    // Process according to current parser state
 
265
                    switch (state)
 
266
                    {
 
267
 
 
268
                        // Parser expects key
 
269
                        case s_key:
 
270
                        {
 
271
 
 
272
                            if (*text == Ch('{'))   // Brace opening found
 
273
                            {
 
274
                                if (!last)
 
275
                                    BOOST_PROPERTY_TREE_THROW(info_parser_error("unexpected {", "", 0));
 
276
                                stack.push(last);
 
277
                                last = NULL;
 
278
                                ++text;
 
279
                            }
 
280
                            else if (*text == Ch('}'))  // Brace closing found
 
281
                            {
 
282
                                if (stack.size() <= 1)
 
283
                                    BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
 
284
                                stack.pop();
 
285
                                last = NULL;
 
286
                                ++text;
 
287
                            }
 
288
                            else    // Key text found
 
289
                            {
 
290
                                std::basic_string<Ch> key = read_key(text);
 
291
                                last = &stack.top()->push_back(
 
292
                                    std::make_pair(key, Ptree()))->second;
 
293
                                state = s_data;
 
294
                            }
 
295
 
 
296
                        }; break;
 
297
 
 
298
                        // Parser expects data
 
299
                        case s_data:
 
300
                        {
 
301
                            
 
302
                            // Last ptree must be defined because we are going to add data to it
 
303
                            BOOST_ASSERT(last);
 
304
                            
 
305
                            if (*text == Ch('{'))   // Brace opening found
 
306
                            {
 
307
                                stack.push(last);
 
308
                                last = NULL;
 
309
                                ++text;
 
310
                                state = s_key;
 
311
                            }
 
312
                            else if (*text == Ch('}'))  // Brace closing found
 
313
                            {
 
314
                                if (stack.size() <= 1)
 
315
                                    BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched }", "", 0));
 
316
                                stack.pop();
 
317
                                last = NULL;
 
318
                                ++text;
 
319
                                state = s_key;
 
320
                            }
 
321
                            else    // Data text found
 
322
                            {
 
323
                                bool need_more_lines;
 
324
                                std::basic_string<Ch> data = read_data(text, &need_more_lines);
 
325
                                last->data() = data;
 
326
                                state = need_more_lines ? s_data_cont : s_key;
 
327
                            }
 
328
 
 
329
 
 
330
                        }; break;
 
331
 
 
332
                        // Parser expects continuation of data after \ on previous line
 
333
                        case s_data_cont:
 
334
                        {
 
335
                            
 
336
                            // Last ptree must be defined because we are going to update its data
 
337
                            BOOST_ASSERT(last);
 
338
                            
 
339
                            if (*text == Ch('\"'))  // Continuation must start with "
 
340
                            {
 
341
                                bool need_more_lines;
 
342
                                std::basic_string<Ch> data = read_string(text, &need_more_lines);
 
343
                                last->put_value(last->template get_value<std::basic_string<Ch> >() + data);
 
344
                                state = need_more_lines ? s_data_cont : s_key;
 
345
                            }
 
346
                            else
 
347
                                BOOST_PROPERTY_TREE_THROW(info_parser_error("expected \" after \\ in previous line", "", 0));
 
348
 
 
349
                        }; break;
 
350
 
 
351
                        // Should never happen
 
352
                        default:
 
353
                            BOOST_ASSERT(0);
 
354
 
 
355
                    }
 
356
                }
 
357
            }
 
358
 
 
359
            // Check if stack has initial size, otherwise some {'s have not been closed
 
360
            if (stack.size() != 1)
 
361
                BOOST_PROPERTY_TREE_THROW(info_parser_error("unmatched {", "", 0));
 
362
 
 
363
        }
 
364
        catch (info_parser_error &e)
 
365
        {
 
366
            // If line undefined rethrow error with correct filename and line
 
367
            if (e.line() == 0)
 
368
            {
 
369
                BOOST_PROPERTY_TREE_THROW(info_parser_error(e.message(), filename, line_no));
 
370
            }
 
371
            else
 
372
                BOOST_PROPERTY_TREE_THROW(e);
 
373
 
 
374
        }
 
375
 
 
376
    }
 
377
 
 
378
} } }
 
379
 
 
380
#endif