data.cc 35.2 KB
Newer Older
1
// Copyright (C) 2010-2017 Internet Systems Consortium, Inc. ("ISC")
Jelte Jansen's avatar
Jelte Jansen committed
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
Jelte Jansen's avatar
Jelte Jansen committed
6

7
#include <config.h>
8

9
#include <cc/data.h>
10

11
#include <cstring>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
12
#include <cassert>
Jeremy C. Reed's avatar
Jeremy C. Reed committed
13
#include <climits>
14
#include <list>
15
#include <map>
16 17
#include <cstdio>
#include <iostream>
18
#include <iomanip>
19
#include <string>
20
#include <sstream>
21
#include <fstream>
22
#include <cerrno>
23

24
#include <boost/lexical_cast.hpp>
25

Jelte Jansen's avatar
Jelte Jansen committed
26 27
#include <cmath>

28 29
using namespace std;

30
namespace {
31
const char* const WHITESPACE = " \b\f\n\r\t";
32 33
} // end anonymous namespace

JINMEI Tatuya's avatar
JINMEI Tatuya committed
34 35 36
namespace isc {
namespace data {

37 38 39 40 41 42 43 44 45 46 47 48 49
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);
}

50
std::string
51
Element::str() const {
52 53
    std::stringstream ss;
    toJSON(ss);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
54
    return (ss.str());
55 56 57
}

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

void
65
Element::toWire(std::ostream& ss) const {
66 67 68
    toJSON(ss);
}

69
bool
70
Element::getValue(int64_t&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
71
    return (false);
72 73 74
}

bool
75
Element::getValue(double&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
76
    return (false);
77 78 79
}

bool
80
Element::getValue(bool&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
81
    return (false);
82 83 84
}

bool
85
Element::getValue(std::string&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
86
    return (false);
87 88 89
}

bool
90
Element::getValue(std::vector<ElementPtr>&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
91
    return (false);
92 93 94
}

bool
95
Element::getValue(std::map<std::string, ConstElementPtr>&) const {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
96
    return (false);
97 98 99
}

bool
100
Element::setValue(const long long int) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
101
    return (false);
102 103 104
}

bool
105
Element::setValue(const double) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
106
    return (false);
107 108 109
}

bool
110
Element::setValue(const bool) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
111
    return (false);
112 113 114
}

bool
115
Element::setValue(const std::string&) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
116
    return (false);
117 118 119
}

bool
120
Element::setValue(const std::vector<ElementPtr>&) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
121
    return (false);
122 123 124
}

bool
125
Element::setValue(const std::map<std::string, ConstElementPtr>&) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
126
    return (false);
127 128
}

129
ConstElementPtr
130
Element::get(const int) const {
131
    throwTypeError("get(int) called on a non-list Element");
132 133
}

134
ElementPtr
135
Element::getNonConst(const int) const {
136 137 138
    throwTypeError("get(int) called on a non-list Element");
}

139
void
140
Element::set(const size_t, ElementPtr) {
141
    throwTypeError("set(int, element) called on a non-list Element");
142 143 144
}

void
145
Element::add(ElementPtr) {
146
    throwTypeError("add() called on a non-list Element");
147 148 149
}

void
150
Element::remove(const int) {
151
    throwTypeError("remove(int) called on a non-list Element");
152 153 154
}

size_t
155
Element::size() const {
156
    throwTypeError("size() called on a non-list Element");
157 158
}

159 160
bool
Element::empty() const {
161
    throwTypeError("empty() called on a non-list Element");
162 163
}

164
ConstElementPtr
165
Element::get(const std::string&) const {
166
    throwTypeError("get(string) called on a non-map Element");
167 168 169
}

void
170
Element::set(const std::string&, ConstElementPtr) {
171
    throwTypeError("set(name, element) called on a non-map Element");
172 173 174
}

void
175
Element::remove(const std::string&) {
176
    throwTypeError("remove(string) called on a non-map Element");
177 178 179
}

bool
180
Element::contains(const std::string&) const {
181
    throwTypeError("contains(string) called on a non-map Element");
182 183
}

184
ConstElementPtr
185
Element::find(const std::string&) const {
186
    throwTypeError("find(string) called on a non-map Element");
187 188 189
}

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

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

205
std::ostream&
206
operator<<(std::ostream& out, const Element& e) {
207
    return (out << e.str());
208 209
}

210 211 212 213 214 215 216
bool
operator==(const Element& a, const Element& b) {
    return (a.equals(b));
}

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

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

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

232 233 234 235 236 237 238 239 240 241
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));
};

242
ElementPtr
243 244
Element::create(const double d, const Position& pos) {
    return (ElementPtr(new DoubleElement(d, pos)));
245 246
}

247 248 249 250 251
ElementPtr
Element::create(const bool b, const Position& pos) {
    return (ElementPtr(new BoolElement(b, pos)));
}

252
ElementPtr
253 254
Element::create(const std::string& s, const Position& pos) {
    return (ElementPtr(new StringElement(s, pos)));
255 256 257
}

ElementPtr
258 259
Element::create(const char *s, const Position& pos) {
    return (create(std::string(s), pos));
260 261 262
}

ElementPtr
263 264
Element::createList(const Position& pos) {
    return (ElementPtr(new ListElement(pos)));
265 266 267
}

ElementPtr
268 269
Element::createMap(const Position& pos) {
    return (ElementPtr(new MapElement(pos)));
270 271 272 273
}


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

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

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

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

357
    while (c != EOF && c != '"') {
358 359
        if (c == '\\') {
            // see the spec for allowed escape characters
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
            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:
386
                throwJSONError("Bad escape", file, line, pos);
387
            }
388
            // drop the escaped char
389
            in.ignore();
390
            ++pos;
391
        }
392
        ss.put(c);
393
        c = in.get();
JINMEI Tatuya's avatar
JINMEI Tatuya committed
394
        ++pos;
395
    }
396 397 398
    if (c == EOF) {
        throwJSONError("Unterminated string", file, line, pos);
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
399
    return (ss.str());
400 401
}

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

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

Jelte Jansen's avatar
Jelte Jansen committed
423 424 425
// 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)
426
//
JINMEI Tatuya's avatar
JINMEI Tatuya committed
427
ElementPtr
428 429
fromStringstreamNumber(std::istream& in, const std::string& file,
                       const int& line, int& pos) {
430 431
    // Remember position where the value starts. It will be set in the
    // Position structure of the Element to be created.
432
    const uint32_t start_pos = pos;
433
    // This will move the pos to the end of the value.
434
    const std::string number = numberFromStringstream(in, pos);
Jelte Jansen's avatar
Jelte Jansen committed
435

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

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

466
    if (word == "true") {
467 468
        return (Element::create(true, Element::Position(file, line,
                                                        start_pos)));
469
    } else if (word == "false") {
470 471
        return (Element::create(false, Element::Position(file, line,
                                                         start_pos)));
472
    } else {
473 474
        throwJSONError(std::string("Bad boolean value: ") + word, file,
                       line, start_pos);
475
    }
476
    return (ElementPtr());
477 478
}

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

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

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

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

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

548
            skipTo(in, file, line, pos, ":", WHITESPACE);
549
            // skip the :
550

551
            ConstElementPtr value = Element::fromJSON(in, file, line, pos);
552
            map->set(key, value);
553

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

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

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

610
ElementPtr
611 612
Element::fromJSON(std::istream& in, bool preproc) throw(JSONError) {

613
    int line = 1, pos = 1;
614 615 616 617 618
    stringstream filtered;
    if (preproc) {
        preprocess(in, filtered);
    }

619
    ElementPtr value = fromJSON(preproc ? filtered : in, "<istream>", line, pos);
620 621

    return (value);
622 623 624
}

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

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

707
ElementPtr
708
Element::fromJSON(const std::string& in, bool preproc) {
709 710
    std::stringstream ss;
    ss << in;
711

712
    int line = 1, pos = 1;
713 714 715 716
    stringstream filtered;
    if (preproc) {
        preprocess(ss, filtered);
    }
717
    ElementPtr result(fromJSON(preproc ? filtered : ss, "<string>", line, pos));
718
    skipChars(ss, WHITESPACE, line, pos);
719 720 721 722 723
    // ss must now be at end
    if (ss.peek() != EOF) {
        throwJSONError("Extra data", "<string>", line, pos);
    }
    return result;
724
}
725

726 727 728
ElementPtr
Element::fromJSONFile(const std::string& file_name,
                      bool preproc) {
729 730 731
    // zero out the errno to be safe
    errno = 0;

732 733 734
    std::ifstream infile(file_name.c_str(), std::ios::in | std::ios::binary);
    if (!infile.is_open())
    {
735
        const char* error = strerror(errno);
736 737
        isc_throw(InvalidOperation, "failed to read file '" << file_name
                  << "': " << error);
738 739 740 741 742
    }

    return (fromJSON(infile, file_name, preproc));
}

743 744 745
// to JSON format

void
746
IntElement::toJSON(std::ostream& ss) const {
747
    ss << intValue();
748 749
}

750
void
751
DoubleElement::toJSON(std::ostream& ss) const {
752
    ss << doubleValue();
753 754
}

755
void
JINMEI Tatuya's avatar