data.cc 28.7 KB
Newer Older
1
// Copyright (C) 2010, 2014  Internet Systems Consortium, Inc. ("ISC")
Jelte Jansen's avatar
Jelte Jansen committed
2 3 4 5 6 7 8 9 10 11 12 13 14
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
#include <config.h>
16

17
#include <cc/data.h>
18

19
#include <cstring>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
20
#include <cassert>
Jeremy C. Reed's avatar
Jeremy C. Reed committed
21
#include <climits>
22
#include <map>
23 24
#include <cstdio>
#include <iostream>
25
#include <string>
26
#include <sstream>
27
#include <fstream>
28
#include <cerrno>
29
#include <climits>
30

31
#include <boost/algorithm/string.hpp> // for iequals
32
#include <boost/lexical_cast.hpp>
33

Jelte Jansen's avatar
Jelte Jansen committed
34 35
#include <cmath>

36 37
using namespace std;

38
namespace {
39
const char* const WHITESPACE = " \b\f\n\r\t";
40 41
} // end anonymous namespace

JINMEI Tatuya's avatar
JINMEI Tatuya committed
42 43 44
namespace isc {
namespace data {

45 46 47 48 49 50 51 52 53 54 55 56 57
std::string
Element::Position::str() const {
    std::ostringstream ss;
    ss << file_ << ":" << line_ << ":" << pos_;
    return (ss.str());
}

std::ostream&
operator<<(std::ostream& out, const Element::Position& pos) {
    out << pos.str();
    return (out);
}

58
std::string
59
Element::str() const {
60 61
    std::stringstream ss;
    toJSON(ss);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
62
    return (ss.str());
63 64 65
}

std::string
66
Element::toWire() const {
67 68
    std::stringstream ss;
    toJSON(ss);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
69
    return (ss.str());
70 71 72
}

void
73
Element::toWire(std::ostream& ss) const {
74 75 76
    toJSON(ss);
}

77
bool
78
Element::getValue(int64_t&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
79
    return (false);
80 81 82
}

bool
83
Element::getValue(double&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
84
    return (false);
85 86 87
}

bool
88
Element::getValue(bool&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
89
    return (false);
90 91 92
}

bool
93
Element::getValue(std::string&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
94
    return (false);
95 96 97
}

bool
98
Element::getValue(std::vector<ConstElementPtr>&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
99
    return (false);
100 101 102
}

bool
103
Element::getValue(std::map<std::string, ConstElementPtr>&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
104
    return (false);
105 106 107
}

bool
108
Element::setValue(const long long int) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
109
    return (false);
110 111 112
}

bool
113
Element::setValue(const double) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
114
    return (false);
115 116 117
}

bool
118
Element::setValue(const bool) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
119
    return (false);
120 121 122
}

bool
123
Element::setValue(const std::string&) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
124
    return (false);
125 126 127
}

bool
128
Element::setValue(const std::vector<ConstElementPtr>&) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
129
    return (false);
130 131 132
}

bool
133
Element::setValue(const std::map<std::string, ConstElementPtr>&) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
134
    return (false);
135 136
}

137
ConstElementPtr
138
Element::get(const int) const {
139 140 141 142
    isc_throw(TypeError, "get(int) called on a non-list Element");
}

void
143
Element::set(const size_t, ConstElementPtr) {
144 145 146 147
    isc_throw(TypeError, "set(int, element) called on a non-list Element");
}

void
148
Element::add(ConstElementPtr) {
149 150 151 152
    isc_throw(TypeError, "add() called on a non-list Element");
}

void
153
Element::remove(const int) {
154 155 156 157
    isc_throw(TypeError, "remove(int) called on a non-list Element");
}

size_t
158
Element::size() const {
159 160 161
    isc_throw(TypeError, "size() called on a non-list Element");
}

162 163 164 165 166
bool
Element::empty() const {
    isc_throw(TypeError, "empty() called on a non-list Element");
}

167
ConstElementPtr
168
Element::get(const std::string&) const {
169 170 171 172
    isc_throw(TypeError, "get(string) called on a non-map Element");
}

void
173
Element::set(const std::string&, ConstElementPtr) {
174 175 176 177
    isc_throw(TypeError, "set(name, element) called on a non-map Element");
}

void
178
Element::remove(const std::string&) {
179 180 181 182
    isc_throw(TypeError, "remove(string) called on a non-map Element");
}

bool
183
Element::contains(const std::string&) const {
184 185 186
    isc_throw(TypeError, "contains(string) called on a non-map Element");
}

187
ConstElementPtr
188
Element::find(const std::string&) const {
189 190 191 192
    isc_throw(TypeError, "find(string) called on a non-map Element");
}

bool
193
Element::find(const std::string&, ConstElementPtr&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
194
    return (false);
195 196
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
197 198
namespace {
inline void
199 200
throwJSONError(const std::string& error, const std::string& file, int line,
               int pos)
Jelte Jansen's avatar
Jelte Jansen committed
201
{
Jelte Jansen's avatar
Jelte Jansen committed
202 203 204
    std::stringstream ss;
    ss << error << " in " + file + ":" << line << ":" << pos;
    isc_throw(JSONError, ss.str());
205
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
206
}
207

208
std::ostream&
209
operator<<(std::ostream& out, const Element& e) {
210
    return (out << e.str());
211 212
}

213 214 215 216 217 218 219
bool
operator==(const Element& a, const Element& b) {
    return (a.equals(b));
}

bool operator!=(const Element& a, const Element& b) {
    return (!a.equals(b));
220 221
};

222 223 224
//
// factory functions
//
225
ElementPtr
226 227
Element::create(const Position& pos) {
    return (ElementPtr(new NullElement(pos)));
228 229
}

230
ElementPtr
231 232
Element::create(const long long int i, const Position& pos) {
    return (ElementPtr(new IntElement(static_cast<int64_t>(i), pos)));
233 234
}

235 236 237 238 239 240 241 242 243 244
ElementPtr
Element::create(const int i, const Position& pos) {
    return (create(static_cast<long long int>(i), pos));
};

ElementPtr
Element::create(const long int i, const Position& pos) {
    return (create(static_cast<long long int>(i), pos));
};

245
ElementPtr
246 247
Element::create(const double d, const Position& pos) {
    return (ElementPtr(new DoubleElement(d, pos)));
248 249
}

250 251 252 253 254
ElementPtr
Element::create(const bool b, const Position& pos) {
    return (ElementPtr(new BoolElement(b, pos)));
}

255
ElementPtr
256 257
Element::create(const std::string& s, const Position& pos) {
    return (ElementPtr(new StringElement(s, pos)));
258 259 260
}

ElementPtr
261 262
Element::create(const char *s, const Position& pos) {
    return (create(std::string(s), pos));
263 264 265
}

ElementPtr
266 267
Element::createList(const Position& pos) {
    return (ElementPtr(new ListElement(pos)));
268 269 270
}

ElementPtr
271 272
Element::createMap(const Position& pos) {
    return (ElementPtr(new MapElement(pos)));
273 274 275 276
}


//
277
// helper functions for fromJSON factory
278
//
JINMEI Tatuya's avatar
JINMEI Tatuya committed
279 280
namespace {
bool
281
charIn(const int c, const char* chars) {
282 283
    const size_t chars_len = std::strlen(chars);
    for (size_t i = 0; i < chars_len; ++i) {
284
        if (chars[i] == c) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
285
            return (true);
286 287
        }
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
288
    return (false);
289 290
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
291
void
292
skipChars(std::istream& in, const char* chars, int& line, int& pos) {
293
    int c = in.peek();
294
    while (charIn(c, chars) && c != EOF) {
295
        if (c == '\n') {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
296
            ++line;
297 298
            pos = 1;
        } else {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
299
            ++pos;
300
        }
301
        in.ignore();
302 303 304 305 306
        c = in.peek();
    }
}

// skip on the input stream to one of the characters in chars
307
// if another character is found this function throws JSONError
308
// unless that character is specified in the optional may_skip
309
//
310 311
// It returns the found character (as an int value).
int
312 313
skipTo(std::istream& in, const std::string& file, int& line,
       int& pos, const char* chars, const char* may_skip="")
314
{
315
    int c = in.get();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
316
    ++pos;
317
    while (c != EOF) {
318 319
        if (c == '\n') {
            pos = 1;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
320
            ++line;
321
        }
322
        if (charIn(c, may_skip)) {
323
            c = in.get();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
324
            ++pos;
325 326
        } else if (charIn(c, chars)) {
            while (charIn(in.peek(), may_skip)) {
327 328
                if (in.peek() == '\n') {
                    pos = 1;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
329
                    ++line;
330 331
                } else {
                    ++pos;
332
                }
333
                in.ignore();
334
            }
335
            return (c);
336
        } else {
337
            throwJSONError(std::string("'") + std::string(1, c) + "' read, one of \"" + chars + "\" expected", file, line, pos);
338 339
        }
    }
Jelte Jansen's avatar
Jelte Jansen committed
340
    throwJSONError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
341
    return (c); // shouldn't reach here, but some compilers require it
342 343
}

344 345
// TODO: Should we check for all other official escapes here (and
// error on the rest)?
JINMEI Tatuya's avatar
JINMEI Tatuya committed
346
std::string
347 348
strFromStringstream(std::istream& in, const std::string& file,
                    const int line, int& pos) throw (JSONError)
349 350
{
    std::stringstream ss;
351
    int c = in.get();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
352
    ++pos;
353 354
    if (c == '"') {
        c = in.get();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
355
        ++pos;
356
    } else {
Jelte Jansen's avatar
Jelte Jansen committed
357
        throwJSONError("String expected", file, line, pos);
358
    }
359

360
    while (c != EOF && c != '"') {
361 362
        if (c == '\\') {
            // see the spec for allowed escape characters
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
            switch (in.peek()) {
            case '"':
                c = '"';
                break;
            case '/':
                c = '/';
                break;
            case '\\':
                c = '\\';
                break;
            case 'b':
                c = '\b';
                break;
            case 'f':
                c = '\f';
                break;
            case 'n':
                c = '\n';
                break;
            case 'r':
                c = '\r';
                break;
            case 't':
                c = '\t';
                break;
            default:
389
                throwJSONError("Bad escape", file, line, pos);
390
            }
391
            // drop the escaped char
392
            in.ignore();
393
            ++pos;
394
        }
395
        ss.put(c);
396
        c = in.get();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
397
        ++pos;
398
    }
399 400 401
    if (c == EOF) {
        throwJSONError("Unterminated string", file, line, pos);
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
402
    return (ss.str());
403 404
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
405
std::string
406
wordFromStringstream(std::istream& in, int& pos) {
407 408 409 410
    std::stringstream ss;
    while (isalpha(in.peek())) {
        ss << (char) in.get();
    }
411
    pos += ss.str().size();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
412
    return (ss.str());
413 414
}

415 416
std::string
numberFromStringstream(std::istream& in, int& pos) {
Jelte Jansen's avatar
Jelte Jansen committed
417 418 419 420
    std::stringstream ss;
    while (isdigit(in.peek()) || in.peek() == '+' || in.peek() == '-' ||
           in.peek() == '.' || in.peek() == 'e' || in.peek() == 'E') {
        ss << (char) in.get();
421
    }
Jelte Jansen's avatar
Jelte Jansen committed
422
    pos += ss.str().size();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
423
    return (ss.str());
424 425
}

Jelte Jansen's avatar
Jelte Jansen committed
426 427 428
// Should we change from IntElement and DoubleElement to NumberElement
// that can also hold an e value? (and have specific getters if the
// value is larger than an int can handle)
429
//
JINMEI Tatuya's avatar
JINMEI Tatuya committed
430
ElementPtr
431 432
fromStringstreamNumber(std::istream& in, const std::string& file,
                       const int& line, int& pos) {
433 434
    // Remember position where the value starts. It will be set in the
    // Position structure of the Element to be created.
435
    const uint32_t start_pos = pos;
436
    // This will move the pos to the end of the value.
437
    const std::string number = numberFromStringstream(in, pos);
Jelte Jansen's avatar
Jelte Jansen committed
438

439 440
    if (number.find_first_of(".eE") < number.size()) {
        try {
441
            return (Element::create(boost::lexical_cast<double>(number),
442
                                    Element::Position(file, line, start_pos)));
443
        } catch (const boost::bad_lexical_cast&) {
444 445
            throwJSONError(std::string("Number overflow: ") + number,
                           file, line, start_pos);
446
        }
Jelte Jansen's avatar
Jelte Jansen committed
447
    } else {
448
        try {
449
            return (Element::create(boost::lexical_cast<int64_t>(number),
450
                                    Element::Position(file, line, start_pos)));
451
        } catch (const boost::bad_lexical_cast&) {
452 453
            throwJSONError(std::string("Number overflow: ") + number, file,
                           line, start_pos);
Jelte Jansen's avatar
Jelte Jansen committed
454
        }
455
    }
456
    return (ElementPtr());
457 458
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
459
ElementPtr
460 461
fromStringstreamBool(std::istream& in, const std::string& file,
                     const int line, int& pos)
462
{
463 464
    // Remember position where the value starts. It will be set in the
    // Position structure of the Element to be created.
465
    const uint32_t start_pos = pos;
466
    // This will move the pos to the end of the value.
467
    const std::string word = wordFromStringstream(in, pos);
468

469
    if (boost::iequals(word, "True")) {
470 471
        return (Element::create(true, Element::Position(file, line,
                                                        start_pos)));
472
    } else if (boost::iequals(word, "False")) {
473 474
        return (Element::create(false, Element::Position(file, line,
                                                         start_pos)));
475
    } else {
476 477
        throwJSONError(std::string("Bad boolean value: ") + word, file,
                       line, start_pos);
478
    }
479
    return (ElementPtr());
480 481
}

482
ElementPtr
483 484
fromStringstreamNull(std::istream& in, const std::string& file,
                     const int line, int& pos)
485
{
486 487
    // Remember position where the value starts. It will be set in the
    // Position structure of the Element to be created.
488
    const uint32_t start_pos = pos;
489
    // This will move the pos to the end of the value.
490
    const std::string word = wordFromStringstream(in, pos);
491
    if (boost::iequals(word, "null")) {
492
        return (Element::create(Element::Position(file, line, start_pos)));
493
    } else {
494 495
        throwJSONError(std::string("Bad null value: ") + word, file,
                       line, start_pos);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
496
        return (ElementPtr());
497 498 499
    }
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
500
ElementPtr
501 502
fromStringstreamString(std::istream& in, const std::string& file, int& line,
                       int& pos)
503
{
504 505
    // Remember position where the value starts. It will be set in the
    // Position structure of the Element to be created.
506
    const uint32_t start_pos = pos;
507
    // This will move the pos to the end of the value.
508
    const std::string string_value = strFromStringstream(in, file, line, pos);
509 510
    return (Element::create(string_value, Element::Position(file, line,
                                                            start_pos)));
511 512
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
513
ElementPtr
514 515
fromStringstreamList(std::istream& in, const std::string& file, int& line,
                     int& pos)
516
{
517
    int c = 0;
518
    ElementPtr list = Element::createList(Element::Position(file, line, pos));
519
    ConstElementPtr cur_list_element;
520

521
    skipChars(in, WHITESPACE, line, pos);
522
    while (c != EOF && c != ']') {
523
        if (in.peek() != ']') {
524
            cur_list_element = Element::fromJSON(in, file, line, pos);
525
            list->add(cur_list_element);
526 527 528 529
            c = skipTo(in, file, line, pos, ",]", WHITESPACE);
        } else {
            c = in.get();
            ++pos;
530 531
        }
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
532
    return (list);
533 534
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
535
ElementPtr
536 537
fromStringstreamMap(std::istream& in, const std::string& file, int& line,
                    int& pos)
538
{
539
    ElementPtr map = Element::createMap(Element::Position(file, line, pos));
540
    skipChars(in, WHITESPACE, line, pos);
541
    int c = in.peek();
542 543
    if (c == EOF) {
        throwJSONError(std::string("Unterminated map, <string> or } expected"), file, line, pos);
Jelte Jansen's avatar
Jelte Jansen committed
544
    } else if (c == '}') {
545
        // empty map, skip closing curly
546
        in.ignore();
547 548
    } else {
        while (c != EOF && c != '}') {
549
            std::string key = strFromStringstream(in, file, line, pos);
550

551
            skipTo(in, file, line, pos, ":", WHITESPACE);
552
            // skip the :
553

554
            ConstElementPtr value = Element::fromJSON(in, file, line, pos);
555
            map->set(key, value);
556

557
            c = skipTo(in, file, line, pos, ",}", WHITESPACE);
558
        }
559
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
560
    return (map);
561
}
562
} // unnamed namespace
563

564
std::string
565
Element::typeToName(Element::types type) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
566
    switch (type) {
567
    case Element::integer:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
568
        return (std::string("integer"));
569
    case Element::real:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
570
        return (std::string("real"));
571
    case Element::boolean:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
572
        return (std::string("boolean"));
573
    case Element::string:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
574
        return (std::string("string"));
575
    case Element::list:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
576
        return (std::string("list"));
577
    case Element::map:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
578
        return (std::string("map"));
579
    case Element::null:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
580
        return (std::string("null"));
581
    case Element::any:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
582
        return (std::string("any"));
583
    default:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
584
        return (std::string("unknown"));
585 586 587 588 589 590
    }
}

Element::types
Element::nameToType(const std::string& type_name) {
    if (type_name == "integer") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
591
        return (Element::integer);
592
    } else if (type_name == "real") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
593
        return (Element::real);
594
    } else if (type_name == "boolean") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
595
        return (Element::boolean);
596
    } else if (type_name == "string") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
597
        return (Element::string);
598
    } else if (type_name == "list") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
599
        return (Element::list);
600
    } else if (type_name == "map") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
601
        return (Element::map);
602
    } else if (type_name == "named_set") {
603
        return (Element::map);
604
    } else if (type_name == "null") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
605
        return (Element::null);
606
    } else if (type_name == "any") {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
607
        return (Element::any);
608 609 610 611 612
    } else {
        isc_throw(TypeError, type_name + " is not a valid type name");
    }
}

613
ElementPtr
614 615
Element::fromJSON(std::istream& in, bool preproc) throw(JSONError) {

616
    int line = 1, pos = 1;
617 618 619 620 621
    stringstream filtered;
    if (preproc) {
        preprocess(in, filtered);
    }

622
    ElementPtr value = fromJSON(preproc ? filtered : in, "<istream>", line, pos);
623 624

    return (value);
625 626 627
}

ElementPtr
628
Element::fromJSON(std::istream& in, const std::string& file_name, bool preproc)
629
    throw(JSONError)
630 631
{
    int line = 1, pos = 1;
632 633 634 635
    stringstream filtered;
    if (preproc) {
        preprocess(in, filtered);
    }
636
    return (fromJSON(preproc ? filtered : in, file_name, line, pos));
637 638 639
}

ElementPtr
640
Element::fromJSON(std::istream& in, const std::string& file, int& line,
641
                  int& pos) throw(JSONError)
642
{
643
    int c = 0;
644 645
    ElementPtr element;
    bool el_read = false;
646
    skipChars(in, WHITESPACE, line, pos);
647 648
    while (c != EOF && !el_read) {
        c = in.get();
649
        pos++;
650 651 652 653 654 655 656 657 658 659 660
        switch(c) {
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
            case '0':
661 662
            case '-':
            case '+':
Jelte Jansen's avatar
Jelte Jansen committed
663 664
            case '.':
                in.putback(c);
665
                --pos;
666
                element = fromStringstreamNumber(in, file, line, pos);
667 668
                el_read = true;
                break;
669 670 671 672 673
            case 't':
            case 'T':
            case 'f':
            case 'F':
                in.putback(c);
674
                --pos;
675
                element = fromStringstreamBool(in, file, line, pos);
676 677
                el_read = true;
                break;
678
            case 'n':
679
            case 'N':
680
                in.putback(c);
681
                --pos;
682
                element = fromStringstreamNull(in, file, line, pos);
683 684
                el_read = true;
                break;
685 686
            case '"':
                in.putback('"');
687
                --pos;
688
                element = fromStringstreamString(in, file, line, pos);
689 690 691
                el_read = true;
                break;
            case '[':
692
                element = fromStringstreamList(in, file, line, pos);
693 694 695
                el_read = true;
                break;
            case '{':
696
                element = fromStringstreamMap(in, file, line, pos);
697 698
                el_read = true;
                break;
699 700
            case EOF:
                break;
701
            default:
702
                throwJSONError(std::string("error: unexpected character ") + std::string(1, c), file, line, pos);
703 704 705 706
                break;
        }
    }
    if (el_read) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
707
        return (element);
708
    } else {
709
        isc_throw(JSONError, "nothing read");
710 711 712
    }
}

713
ElementPtr
714
Element::fromJSON(const std::string& in, bool preproc) {
715 716
    std::stringstream ss;
    ss << in;
717