LCOV - code coverage report
Current view: top level - cc - data.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 421 431 97.7 %
Date: 2012-05-15 Functions: 78 79 98.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 424 632 67.1 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <config.h>
      16                 :            : 
      17                 :            : #include <cc/data.h>
      18                 :            : 
      19                 :            : #include <cassert>
      20                 :            : #include <climits>
      21                 :            : #include <map>
      22                 :            : #include <cstdio>
      23                 :            : #include <iostream>
      24                 :            : #include <string>
      25                 :            : #include <sstream>
      26                 :            : 
      27                 :            : #include <boost/algorithm/string.hpp> // for iequals
      28                 :            : 
      29                 :            : #include <cmath>
      30                 :            : 
      31                 :            : using namespace std;
      32                 :            : 
      33                 :            : namespace {
      34                 :            : const char* WHITESPACE = " \b\f\n\r\t";
      35                 :            : } // end anonymous namespace
      36                 :            : 
      37                 :            : namespace isc {
      38                 :            : namespace data {
      39                 :            : 
      40                 :            : std::string
      41                 :        253 : Element::str() const {
      42                 :        506 :     std::stringstream ss;
      43         [ +  - ]:        253 :     toJSON(ss);
      44                 :        253 :     return (ss.str());
      45                 :            : }
      46                 :            : 
      47                 :            : std::string
      48                 :         60 : Element::toWire() const {
      49                 :        120 :     std::stringstream ss;
      50         [ +  - ]:         60 :     toJSON(ss);
      51                 :         60 :     return (ss.str());
      52                 :            : }
      53                 :            : 
      54                 :            : void
      55                 :         15 : Element::toWire(std::ostream& ss) const {
      56                 :         15 :     toJSON(ss);
      57                 :         15 : }
      58                 :            : 
      59                 :            : bool
      60                 :          5 : Element::getValue(long int&) {
      61                 :          5 :     return (false);
      62                 :            : }
      63                 :            : 
      64                 :            : bool
      65                 :          5 : Element::getValue(double&) {
      66                 :          5 :     return (false);
      67                 :            : }
      68                 :            : 
      69                 :            : bool
      70                 :          5 : Element::getValue(bool&) {
      71                 :          5 :     return (false);
      72                 :            : }
      73                 :            : 
      74                 :            : bool
      75                 :          5 : Element::getValue(std::string&) {
      76                 :          5 :     return (false);
      77                 :            : }
      78                 :            : 
      79                 :            : bool
      80                 :          5 : Element::getValue(std::vector<ConstElementPtr>&) {
      81                 :          5 :     return (false);
      82                 :            : }
      83                 :            : 
      84                 :            : bool
      85                 :          5 : Element::getValue(std::map<std::string, ConstElementPtr>&) {
      86                 :          5 :     return (false);
      87                 :            : }
      88                 :            : 
      89                 :            : bool
      90                 :          1 : Element::setValue(const long int) {
      91                 :          1 :     return (false);
      92                 :            : }
      93                 :            : 
      94                 :            : bool
      95                 :          1 : Element::setValue(const double) {
      96                 :          1 :     return (false);
      97                 :            : }
      98                 :            : 
      99                 :            : bool
     100                 :          2 : Element::setValue(const bool) {
     101                 :          2 :     return (false);
     102                 :            : }
     103                 :            : 
     104                 :            : bool
     105                 :          2 : Element::setValue(const std::string&) {
     106                 :          2 :     return (false);
     107                 :            : }
     108                 :            : 
     109                 :            : bool
     110                 :          2 : Element::setValue(const std::vector<ConstElementPtr>&) {
     111                 :          2 :     return (false);
     112                 :            : }
     113                 :            : 
     114                 :            : bool
     115                 :          2 : Element::setValue(const std::map<std::string, ConstElementPtr>&) {
     116                 :          2 :     return (false);
     117                 :            : }
     118                 :            : 
     119                 :            : ConstElementPtr
     120                 :          1 : Element::get(const int) const {
     121 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "get(int) called on a non-list Element");
     122                 :            : }
     123                 :            : 
     124                 :            : void
     125                 :          1 : Element::set(const size_t, ConstElementPtr) {
     126 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "set(int, element) called on a non-list Element");
     127                 :            : }
     128                 :            : 
     129                 :            : void
     130                 :          1 : Element::add(ConstElementPtr) {
     131 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "add() called on a non-list Element");
     132                 :            : }
     133                 :            : 
     134                 :            : void
     135                 :          1 : Element::remove(const int) {
     136 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "remove(int) called on a non-list Element");
     137                 :            : }
     138                 :            : 
     139                 :            : size_t
     140                 :          1 : Element::size() const {
     141 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "size() called on a non-list Element");
     142                 :            : }
     143                 :            : 
     144                 :            : ConstElementPtr
     145                 :          1 : Element::get(const std::string&) const {
     146 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "get(string) called on a non-map Element");
     147                 :            : }
     148                 :            : 
     149                 :            : void
     150                 :          1 : Element::set(const std::string&, ConstElementPtr) {
     151 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "set(name, element) called on a non-map Element");
     152                 :            : }
     153                 :            : 
     154                 :            : void
     155                 :          1 : Element::remove(const std::string&) {
     156 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "remove(string) called on a non-map Element");
     157                 :            : }
     158                 :            : 
     159                 :            : bool
     160                 :          1 : Element::contains(const std::string&) const {
     161 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "contains(string) called on a non-map Element");
     162                 :            : }
     163                 :            : 
     164                 :            : ConstElementPtr
     165                 :          1 : Element::find(const std::string&) const {
     166 [ +  - ][ +  - ]:          2 :     isc_throw(TypeError, "find(string) called on a non-map Element");
     167                 :            : }
     168                 :            : 
     169                 :            : bool
     170                 :          1 : Element::find(const std::string&, ConstElementPtr) const {
     171                 :          1 :     return (false);
     172                 :            : }
     173                 :            : 
     174                 :            : namespace {
     175                 :            : inline void
     176                 :         35 : throwJSONError(const std::string& error, const std::string& file, int line,
     177                 :            :                int pos)
     178                 :            : {
     179                 :         70 :     std::stringstream ss;
     180 [ +  - ][ +  - ]:         35 :     ss << error << " in " + file + ":" << line << ":" << pos;
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     181 [ +  - ][ +  - ]:        105 :     isc_throw(JSONError, ss.str());
                 [ +  - ]
     182                 :            : }
     183                 :            : }
     184                 :            : 
     185                 :            : std::ostream&
     186                 :         71 : operator<<(std::ostream &out, const Element& e) {
     187         [ +  - ]:         71 :     return (out << e.str());
     188                 :            : }
     189                 :            : 
     190                 :            : bool
     191                 :        280 : operator==(const Element& a, const Element& b) {
     192                 :        280 :     return (a.equals(b));
     193                 :            : }
     194                 :            : 
     195                 :         33 : bool operator!=(const Element& a, const Element& b) {
     196                 :         33 :     return (!a.equals(b));
     197                 :            : };
     198                 :            : 
     199                 :            : //
     200                 :            : // factory functions
     201                 :            : //
     202                 :            : ElementPtr
     203                 :         34 : Element::create() {
     204                 :         68 :     return (ElementPtr(new NullElement()));
     205                 :            : }
     206                 :            : 
     207                 :            : ElementPtr
     208                 :       1761 : Element::create(const long int i) {
     209                 :       3522 :     return (ElementPtr(new IntElement(i)));
     210                 :            : }
     211                 :            : 
     212                 :            : ElementPtr
     213                 :         77 : Element::create(const double d) {
     214                 :        154 :     return (ElementPtr(new DoubleElement(d)));
     215                 :            : }
     216                 :            : 
     217                 :            : ElementPtr
     218                 :       9629 : Element::create(const std::string& s) {
     219         [ +  - ]:      19258 :     return (ElementPtr(new StringElement(s)));
     220                 :            : }
     221                 :            : 
     222                 :            : ElementPtr
     223                 :       2836 : Element::create(const bool b) {
     224                 :       5672 :     return (ElementPtr(new BoolElement(b)));
     225                 :            : }
     226                 :            : 
     227                 :            : ElementPtr
     228                 :       3382 : Element::createList() {
     229                 :       6764 :     return (ElementPtr(new ListElement()));
     230                 :            : }
     231                 :            : 
     232                 :            : ElementPtr
     233                 :       5660 : Element::createMap() {
     234                 :      11320 :     return (ElementPtr(new MapElement()));
     235                 :            : }
     236                 :            : 
     237                 :            : 
     238                 :            : //
     239                 :            : // helper functions for fromJSON factory
     240                 :            : //
     241                 :            : namespace {
     242                 :            : bool
     243                 :     198662 : char_in(const char c, const char *chars) {
     244         [ +  + ]:     887424 :     for (size_t i = 0; i < strlen(chars); ++i) {
     245         [ +  + ]:     688762 :         if (chars[i] == c) {
     246                 :            :             return (true);
     247                 :            :         }
     248                 :            :     }
     249                 :            :     return (false);
     250                 :            : }
     251                 :            : 
     252                 :            : void
     253                 :      29117 : skip_chars(std::istream &in, const char *chars, int& line, int& pos) {
     254                 :      29117 :     char c = in.peek();
     255 [ +  + ][ -  + ]:      37856 :     while (char_in(c, chars) && c != EOF) {
                 [ +  + ]
     256         [ +  + ]:       8739 :         if (c == '\n') {
     257                 :        878 :             ++line;
     258                 :        878 :             pos = 1;
     259                 :            :         } else {
     260                 :       7861 :             ++pos;
     261                 :            :         }
     262                 :       8739 :         in.get();
     263                 :       8739 :         c = in.peek();
     264                 :            :     }
     265                 :      29117 : }
     266                 :            : 
     267                 :            : // skip on the input stream to one of the characters in chars
     268                 :            : // if another character is found this function returns false
     269                 :            : // unless that character is specified in the optional may_skip
     270                 :            : //
     271                 :            : // the character found is left on the stream
     272                 :            : void
     273                 :      32205 : skip_to(std::istream &in, const std::string& file, int& line,
     274                 :            :         int& pos, const char* chars, const char* may_skip="")
     275                 :            : {
     276                 :      32205 :     char c = in.get();
     277                 :      32205 :     ++pos;
     278         [ +  + ]:      37999 :     while (c != EOF) {
     279         [ +  + ]:      37994 :         if (c == '\n') {
     280                 :        611 :             pos = 1;
     281                 :        611 :             ++line;
     282                 :            :         }
     283         [ +  + ]:      37994 :         if (char_in(c, may_skip)) {
     284                 :       5794 :             c = in.get();
     285                 :       5794 :             ++pos;
     286         [ +  + ]:      32200 :         } else if (char_in(c, chars)) {
     287         [ +  + ]:      90612 :             while(char_in(in.peek(), may_skip)) {
     288         [ +  + ]:      58415 :                 if (in.peek() == '\n') {
     289                 :       3976 :                     pos = 1;
     290                 :       3976 :                     ++line;
     291                 :            :                 }
     292                 :      58415 :                 in.get();
     293                 :      58415 :                 ++pos;
     294                 :            :             }
     295                 :      32197 :             in.putback(c);
     296                 :      32197 :             --pos;
     297                 :      32197 :             return;
     298                 :            :         } else {
     299 [ +  - ][ +  - ]:          3 :             throwJSONError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", file, line, pos);
         [ +  - ][ +  - ]
     300                 :            :         }
     301                 :            :     }
     302 [ +  - ][ +  - ]:          5 :     throwJSONError(std::string("EOF read, one of \"") + chars + "\" expected", file, line, pos);
     303                 :            : }
     304                 :            : 
     305                 :            : // TODO: Should we check for all other official escapes here (and
     306                 :            : // error on the rest)?
     307                 :            : std::string
     308                 :      22548 : str_from_stringstream(std::istream &in, const std::string& file, const int line,
     309                 :          0 :                       int& pos) throw (JSONError)
     310                 :            : {
     311                 :      22548 :     char c = 0;
     312 [ +  - ][ +  - ]:      45096 :     std::stringstream ss;
                 [ +  - ]
     313         [ +  - ]:      22548 :     c = in.get();
     314                 :      22548 :     ++pos;
     315         [ +  + ]:      22548 :     if (c == '"') {
     316         [ +  - ]:      22542 :         c = in.get();
     317                 :      22542 :         ++pos;
     318                 :            :     } else {
     319         [ +  - ]:          6 :         throwJSONError("String expected", file, line, pos);
     320                 :            :     }
     321                 :            : 
     322         [ +  + ]:     251914 :     while (c != EOF && c != '"') {
     323         [ +  + ]:     229372 :         if (c == '\\') {
     324                 :            :             // see the spec for allowed escape characters
     325 [ +  - ][ -  +  :         10 :             switch (in.peek()) {
          +  +  +  +  +  
                   -  + ]
     326                 :            :             case '"':
     327                 :            :                 c = '"';
     328                 :            :                 break;
     329                 :            :             case '/':
     330                 :          0 :                 c = '/';
     331                 :          0 :                 break;
     332                 :            :             case '\\':
     333                 :          1 :                 c = '\\';
     334                 :          1 :                 break;
     335                 :            :             case 'b':
     336                 :          1 :                 c = '\b';
     337                 :          1 :                 break;
     338                 :            :             case 'f':
     339                 :          1 :                 c = '\f';
     340                 :          1 :                 break;
     341                 :            :             case 'n':
     342                 :          1 :                 c = '\n';
     343                 :          1 :                 break;
     344                 :            :             case 'r':
     345                 :          1 :                 c = '\r';
     346                 :          1 :                 break;
     347                 :            :             case 't':
     348                 :          1 :                 c = '\t';
     349                 :          1 :                 break;
     350                 :            :             default:
     351         [ #  # ]:          0 :                 throwJSONError("Bad escape", file, line, pos);
     352                 :            :             }
     353                 :            :             // drop the escaped char
     354         [ +  - ]:         10 :             in.get();
     355                 :         10 :             ++pos;
     356                 :            :         }
     357         [ +  - ]:     229372 :         ss << c;
     358         [ +  - ]:     229372 :         c = in.get();
     359                 :     229372 :         ++pos;
     360                 :            :     }
     361         [ +  + ]:      22542 :     if (c == EOF) {
     362         [ +  - ]:          3 :         throwJSONError("Unterminated string", file, line, pos);
     363                 :            :     }
     364                 :      22539 :     return (ss.str());
     365                 :            : }
     366                 :            : 
     367                 :            : std::string
     368                 :       2869 : word_from_stringstream(std::istream &in, int& pos) {
     369                 :       5738 :     std::stringstream ss;
     370 [ +  - ][ +  + ]:      16683 :     while (isalpha(in.peek())) {
     371 [ +  - ][ +  - ]:      13814 :         ss << (char) in.get();
     372                 :            :     }
     373                 :       2869 :     pos += ss.str().size();
     374                 :       2869 :     return (ss.str());
     375                 :            : }
     376                 :            : 
     377                 :            : static std::string
     378                 :       1472 : number_from_stringstream(std::istream &in, int& pos) {
     379                 :       2944 :     std::stringstream ss;
     380 [ +  - ][ +  + ]:       7957 :     while (isdigit(in.peek()) || in.peek() == '+' || in.peek() == '-' ||
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     381 [ +  - ][ +  - ]:       4520 :            in.peek() == '.' || in.peek() == 'e' || in.peek() == 'E') {
                 [ +  - ]
     382 [ +  - ][ +  - ]:       1965 :         ss << (char) in.get();
     383                 :            :     }
     384                 :       1472 :     pos += ss.str().size();
     385                 :       1472 :     return (ss.str());
     386                 :            : }
     387                 :            : 
     388                 :            : // Should we change from IntElement and DoubleElement to NumberElement
     389                 :            : // that can also hold an e value? (and have specific getters if the
     390                 :            : // value is larger than an int can handle)
     391                 :            : ElementPtr
     392                 :       1472 : from_stringstream_number(std::istream &in, int &pos) {
     393                 :       1472 :     long int i = 0;
     394                 :       1472 :     double d = 0.0;
     395                 :       1472 :     bool is_double = false;
     396                 :            :     char *endptr;
     397                 :            : 
     398                 :       2944 :     std::string number = number_from_stringstream(in, pos);
     399                 :            : 
     400                 :       1472 :     i = strtol(number.c_str(), &endptr, 10);
     401         [ +  + ]:       1472 :     if (*endptr != '\0') {
     402                 :         79 :         d = strtod(number.c_str(), &endptr);
     403                 :         79 :         is_double = true;
     404         [ -  + ]:         79 :         if (*endptr != '\0') {
     405 [ #  # ][ #  # ]:          0 :             isc_throw(JSONError, std::string("Bad number: ") + number);
         [ #  # ][ #  # ]
                 [ #  # ]
     406                 :            :         } else {
     407 [ +  + ][ +  + ]:         79 :             if (d == HUGE_VAL || d == -HUGE_VAL) {
     408 [ +  - ][ +  - ]:          8 :                 isc_throw(JSONError, std::string("Number overflow: ") + number);
         [ +  - ][ +  - ]
                 [ +  - ]
     409                 :            :             }
     410                 :            :         }
     411                 :            :     } else {
     412         [ +  + ]:       1393 :         if (i == LONG_MAX || i == LONG_MIN) {
     413 [ +  - ][ +  - ]:          2 :             isc_throw(JSONError, std::string("Number overflow: ") + number);
         [ +  - ][ +  - ]
                 [ +  - ]
     414                 :            :         }
     415                 :            :     }
     416                 :            :     
     417         [ +  + ]:       1467 :     if (is_double) {
     418         [ +  - ]:         75 :         return (Element::create(d));
     419                 :            :     } else {
     420         [ +  - ]:       1392 :         return (Element::create(i));
     421                 :            :     }
     422                 :            : }
     423                 :            : 
     424                 :            : ElementPtr
     425                 :       2835 : from_stringstream_bool(std::istream &in, const std::string& file,
     426                 :            :                        const int line, int& pos)
     427                 :            : {
     428                 :       5670 :     const std::string word = word_from_stringstream(in, pos);
     429 [ +  - ][ +  + ]:       2835 :     if (boost::iequals(word, "True")) {
     430         [ +  - ]:        492 :         return (Element::create(true));
     431         [ +  + ]:       4686 :     } else if (boost::iequals(word, "False")) {
     432         [ +  - ]:       2341 :         return (Element::create(false));
     433                 :            :     } else {
     434 [ +  - ][ +  - ]:          2 :         throwJSONError(std::string("Bad boolean value: ") + word, file, line, pos);
     435                 :            :         // above is a throw shortcurt, return empty is never reached
     436                 :            :         return (ElementPtr());
     437                 :            :     }
     438                 :            : }
     439                 :            : 
     440                 :            : ElementPtr
     441                 :         34 : from_stringstream_null(std::istream &in, const std::string& file,
     442                 :            :                        const int line, int& pos)
     443                 :            : {
     444                 :         68 :     const std::string word = word_from_stringstream(in, pos);
     445 [ +  - ][ +  + ]:         34 :     if (boost::iequals(word, "null")) {
     446         [ +  - ]:         32 :         return (Element::create());
     447                 :            :     } else {
     448 [ +  - ][ +  - ]:          2 :         throwJSONError(std::string("Bad null value: ") + word, file, line, pos);
     449                 :            :         return (ElementPtr());
     450                 :            :     }
     451                 :            : }
     452                 :            : 
     453                 :            : ElementPtr
     454                 :          0 : from_stringstream_string(std::istream& in, const std::string& file, int& line,
     455                 :            :                          int& pos)
     456                 :            : {
     457 [ +  + ][ +  - ]:       8089 :     return (Element::create(str_from_stringstream(in, file, line, pos)));
                 [ #  # ]
     458                 :            : }
     459                 :            : 
     460                 :            : ElementPtr
     461                 :       2322 : from_stringstream_list(std::istream &in, const std::string& file, int& line,
     462                 :            :                        int& pos)
     463                 :            : {
     464                 :       2322 :     char c = 0;
     465                 :       2322 :     ElementPtr list = Element::createList();
     466                 :            :     ConstElementPtr cur_list_element;
     467                 :            : 
     468         [ +  - ]:       2322 :     skip_chars(in, WHITESPACE, line, pos);
     469         [ +  + ]:       6551 :     while (c != EOF && c != ']') {
     470 [ +  - ][ +  + ]:       4235 :         if (in.peek() != ']') {
     471         [ +  + ]:       3314 :             cur_list_element = Element::fromJSON(in, file, line, pos);
     472         [ +  - ]:       6620 :             list->add(cur_list_element);
     473         [ +  + ]:       3310 :             skip_to(in, file, line, pos, ",]", WHITESPACE);
     474                 :            :         }
     475         [ +  - ]:       4229 :         c = in.get();
     476                 :       4229 :         pos++;
     477                 :            :     }
     478                 :       2316 :     return (list);
     479                 :            : }
     480                 :            : 
     481                 :            : ElementPtr
     482                 :       5081 : from_stringstream_map(std::istream &in, const std::string& file, int& line,
     483                 :            :                       int& pos)
     484                 :            : {
     485                 :       5081 :     ElementPtr map = Element::createMap();
     486         [ +  - ]:       5081 :     skip_chars(in, WHITESPACE, line, pos);
     487         [ +  - ]:       5081 :     char c = in.peek();
     488         [ +  + ]:       5081 :     if (c == EOF) {
     489         [ +  - ]:          2 :         throwJSONError(std::string("Unterminated map, <string> or } expected"), file, line, pos);
     490         [ +  + ]:       5079 :     } else if (c == '}') {
     491                 :            :         // empty map, skip closing curly
     492         [ +  - ]:        420 :         c = in.get();
     493                 :            :     } else {
     494         [ +  + ]:      19100 :         while (c != EOF && c != '}') {
     495         [ +  + ]:      28910 :             std::string key = str_from_stringstream(in, file, line, pos);
     496                 :            : 
     497         [ +  + ]:      14451 :             skip_to(in, file, line, pos, ":", WHITESPACE);
     498                 :            :             // skip the :
     499         [ +  - ]:      14448 :             in.get();
     500                 :      14448 :             pos++;
     501                 :            : 
     502         [ +  + ]:      14448 :             ConstElementPtr value = Element::fromJSON(in, file, line, pos);
     503         [ +  - ]:      28888 :             map->set(key, value);
     504                 :            :             
     505         [ +  + ]:      14444 :             skip_to(in, file, line, pos, ",}", WHITESPACE);
     506         [ +  - ]:      14441 :             c = in.get();
     507                 :      14441 :             pos++;
     508                 :            :         }
     509                 :            :     }
     510                 :       5061 :     return (map);
     511                 :            : }
     512                 :            : }
     513                 :            : 
     514                 :            : std::string
     515                 :         24 : Element::typeToName(Element::types type) {
     516   [ +  +  +  +  :         24 :     switch (type) {
             +  +  +  +  
                      + ]
     517                 :            :     case Element::integer:
     518                 :          3 :         return (std::string("integer"));
     519                 :            :     case Element::real:
     520                 :          3 :         return (std::string("real"));
     521                 :            :     case Element::boolean:
     522                 :          3 :         return (std::string("boolean"));
     523                 :            :     case Element::string:
     524                 :          4 :         return (std::string("string"));
     525                 :            :     case Element::list:
     526                 :          5 :         return (std::string("list"));
     527                 :            :     case Element::map:
     528                 :          3 :         return (std::string("map"));
     529                 :            :     case Element::null:
     530                 :          1 :         return (std::string("null"));
     531                 :            :     case Element::any:
     532                 :          1 :         return (std::string("any"));
     533                 :            :     default:
     534                 :         24 :         return (std::string("unknown"));
     535                 :            :     }
     536                 :            : }
     537                 :            : 
     538                 :            : Element::types
     539                 :       4971 : Element::nameToType(const std::string& type_name) {
     540         [ +  + ]:       4971 :     if (type_name == "integer") {
     541                 :            :         return (Element::integer);
     542         [ +  + ]:       3668 :     } else if (type_name == "real") {
     543                 :            :         return (Element::real);
     544         [ +  + ]:       3609 :     } else if (type_name == "boolean") {
     545                 :            :         return (Element::boolean);
     546         [ +  + ]:       2984 :     } else if (type_name == "string") {
     547                 :            :         return (Element::string);
     548         [ +  + ]:       1385 :     } else if (type_name == "list") {
     549                 :            :         return (Element::list);
     550         [ +  + ]:        686 :     } else if (type_name == "map") {
     551                 :            :         return (Element::map);
     552         [ +  + ]:         17 :     } else if (type_name == "named_set") {
     553                 :            :         return (Element::map);
     554         [ +  + ]:         13 :     } else if (type_name == "null") {
     555                 :            :         return (Element::null);
     556         [ +  + ]:         12 :     } else if (type_name == "any") {
     557                 :            :         return (Element::any);
     558                 :            :     } else {
     559 [ +  - ][ +  - ]:       4976 :         isc_throw(TypeError, type_name + " is not a valid type name");
                 [ +  - ]
     560                 :            :     }
     561                 :            : }
     562                 :            : 
     563                 :            : ElementPtr
     564                 :          0 : Element::fromJSON(std::istream& in) throw(JSONError) {
     565                 :         50 :     int line = 1, pos = 1;
     566 [ +  - ][ +  - ]:         50 :     return (fromJSON(in, "<istream>", line, pos));
                 [ #  # ]
     567                 :            : }
     568                 :            : 
     569                 :            : ElementPtr
     570                 :         99 : Element::fromJSON(std::istream& in, const std::string& file_name)
     571                 :          0 :     throw(JSONError)
     572                 :            : {
     573                 :         99 :     int line = 1, pos = 1;
     574 [ +  - ][ #  # ]:         99 :     return (fromJSON(in, file_name, line, pos));
     575                 :            : }
     576                 :            : 
     577                 :            : ElementPtr
     578                 :      19846 : Element::fromJSON(std::istream &in, const std::string& file, int& line,
     579                 :          0 :                   int& pos) throw(JSONError)
     580                 :            : {
     581                 :      19846 :     char c = 0;
     582                 :            :     ElementPtr element;
     583                 :      19846 :     bool el_read = false;
     584         [ +  - ]:      19846 :     skip_chars(in, WHITESPACE, line, pos);
     585 [ +  + ][ +  + ]:      39647 :     while (c != EOF && !el_read) {
                 [ +  + ]
     586         [ +  - ]:      19846 :         c = in.get();
     587                 :      19846 :         pos++;
     588   [ +  +  +  +  :      19846 :         switch(c) {
             +  +  +  + ]
     589                 :            :             case '1':
     590                 :            :             case '2':
     591                 :            :             case '3':
     592                 :            :             case '4':
     593                 :            :             case '5':
     594                 :            :             case '6':
     595                 :            :             case '7':
     596                 :            :             case '8':
     597                 :            :             case '9':
     598                 :            :             case '0':
     599                 :            :             case '-':
     600                 :            :             case '+':
     601                 :            :             case '.':
     602         [ +  - ]:       1472 :                 in.putback(c);
     603 [ +  + ][ +  - ]:       1472 :                 element = from_stringstream_number(in, pos);
     604                 :            :                 el_read = true;
     605                 :            :                 break;
     606                 :            :             case 't':
     607                 :            :             case 'T':
     608                 :            :             case 'f':
     609                 :            :             case 'F':
     610         [ +  - ]:       2835 :                 in.putback(c);
     611 [ +  + ][ +  - ]:       2835 :                 element = from_stringstream_bool(in, file, line, pos);
     612                 :            :                 el_read = true;
     613                 :            :                 break;
     614                 :            :             case 'n':
     615                 :            :             case 'N':
     616         [ +  - ]:         34 :                 in.putback(c);
     617 [ +  + ][ +  - ]:         34 :                 element = from_stringstream_null(in, file, line, pos);
     618                 :            :                 el_read = true;
     619                 :            :                 break;
     620                 :            :             case '"':
     621         [ +  - ]:       8089 :                 in.putback('"');
     622         [ +  - ]:       8088 :                 element = from_stringstream_string(in, file, line, pos);
     623                 :            :                 el_read = true;
     624                 :            :                 break;
     625                 :            :             case '[':
     626 [ +  + ][ +  - ]:       2322 :                 element = from_stringstream_list(in, file, line, pos);
     627                 :            :                 el_read = true;
     628                 :            :                 break;
     629                 :            :             case '{':
     630 [ +  + ][ +  - ]:       5081 :                 element = from_stringstream_map(in, file, line, pos);
     631                 :            :                 el_read = true;
     632                 :            :                 break;
     633                 :            :             case EOF:
     634                 :            :                 break;
     635                 :            :             default:
     636 [ +  - ][ +  - ]:      19810 :                 throwJSONError(std::string("error: unexpected character ") + c, file, line, pos);
     637                 :            :                 break;
     638                 :            :         }
     639                 :            :     }
     640         [ +  + ]:      19801 :     if (el_read) {
     641                 :      19797 :         return (element);
     642                 :            :     } else {
     643 [ +  - ][ +  - ]:          8 :         isc_throw(JSONError, "nothing read");
                 [ +  - ]
     644                 :            :     }
     645                 :            : }
     646                 :            : 
     647                 :            : ElementPtr
     648                 :       1909 : Element::fromJSON(const std::string &in) {
     649                 :       3818 :     std::stringstream ss;
     650         [ +  - ]:       1909 :     ss << in;
     651                 :       1909 :     int line = 1, pos = 1;
     652 [ +  - ][ +  + ]:       1909 :     ElementPtr result(fromJSON(ss, "<string>", line, pos));
     653         [ +  - ]:       1868 :     skip_chars(ss, WHITESPACE, line, pos);
     654                 :            :     // ss must now be at end
     655 [ +  - ][ +  + ]:       1868 :     if (ss.peek() != EOF) {
     656 [ +  - ][ +  - ]:          3 :         throwJSONError("Extra data", "<string>", line, pos);
     657                 :            :     }
     658                 :       1865 :     return result;
     659                 :            : }
     660                 :            : 
     661                 :            : // to JSON format
     662                 :            : 
     663                 :            : void
     664                 :        116 : IntElement::toJSON(std::ostream& ss) const {
     665                 :        116 :     ss << intValue();
     666                 :        116 : }
     667                 :            : 
     668                 :            : void
     669                 :         38 : DoubleElement::toJSON(std::ostream& ss) const {
     670                 :         38 :     ss << doubleValue();
     671                 :         38 : }
     672                 :            : 
     673                 :            : void
     674                 :         50 : BoolElement::toJSON(std::ostream& ss) const {
     675         [ +  + ]:         50 :     if (boolValue()) {
     676                 :         14 :         ss << "true";
     677                 :            :     } else {
     678                 :         36 :         ss << "false";
     679                 :            :     }
     680                 :         50 : }
     681                 :            : 
     682                 :            : void
     683                 :          9 : NullElement::toJSON(std::ostream& ss) const {
     684                 :          9 :     ss << "null";
     685                 :          9 : }
     686                 :            : 
     687                 :            : void
     688                 :        401 : StringElement::toJSON(std::ostream& ss) const {
     689                 :        401 :     ss << "\"";
     690                 :            :     char c;
     691                 :        401 :     const std::string& str = stringValue();
     692         [ +  + ]:       5494 :     for (size_t i = 0; i < str.size(); ++i) {
     693                 :       5093 :         c = str[i];
     694                 :            :         // Escape characters as defined in JSON spec
     695                 :            :         // Note that we do not escape forward slash; this
     696                 :            :         // is allowed, but not mandatory.
     697   [ +  +  +  +  :       5093 :         switch (c) {
             +  +  +  + ]
     698                 :            :         case '"':
     699 [ +  - ][ +  - ]:          3 :             ss << '\\' << c;
     700                 :            :             break;
     701                 :            :         case '\\':
     702 [ +  - ][ +  - ]:          1 :             ss << '\\' << c;
     703                 :            :             break;
     704                 :            :         case '\b':
     705 [ +  - ][ +  - ]:          1 :             ss << '\\' << 'b';
     706                 :            :             break;
     707                 :            :         case '\f':
     708 [ +  - ][ +  - ]:          1 :             ss << '\\' << 'f';
     709                 :            :             break;
     710                 :            :         case '\n':
     711 [ +  - ][ +  - ]:          1 :             ss << '\\' << 'n';
     712                 :            :             break;
     713                 :            :         case '\r':
     714 [ +  - ][ +  - ]:          1 :             ss << '\\' << 'r';
     715                 :            :             break;
     716                 :            :         case '\t':
     717 [ +  - ][ +  - ]:          1 :             ss << '\\' << 't';
     718                 :            :             break;
     719                 :            :         default:
     720         [ +  - ]:       5084 :             ss << c;
     721                 :            :         }
     722                 :            :     }
     723         [ +  - ]:        401 :     ss << "\"";
     724                 :        401 : }
     725                 :            : 
     726                 :            : void
     727                 :        164 : ListElement::toJSON(std::ostream& ss) const {
     728                 :        164 :     ss << "[ ";
     729                 :            : 
     730                 :        164 :     const std::vector<ConstElementPtr>& v = listValue();
     731         [ +  + ]:        406 :     for (std::vector<ConstElementPtr>::const_iterator it = v.begin();
     732                 :        406 :          it != v.end(); ++it) {
     733         [ +  + ]:        242 :         if (it != v.begin()) {
     734                 :         89 :             ss << ", ";
     735                 :            :         }
     736                 :        242 :         (*it)->toJSON(ss);
     737                 :            :     }
     738                 :        164 :     ss << " ]";
     739                 :        164 : }
     740                 :            : 
     741                 :            : void
     742                 :        296 : MapElement::toJSON(std::ostream& ss) const {
     743                 :        296 :     ss << "{ ";
     744                 :            : 
     745                 :        296 :     const std::map<std::string, ConstElementPtr>& m = mapValue();
     746         [ +  + ]:        796 :     for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
     747                 :        796 :          it != m.end(); ++it) {
     748         [ +  + ]:        500 :         if (it != m.begin()) {
     749                 :        225 :             ss << ", ";
     750                 :            :         }
     751                 :        500 :         ss << "\"" << (*it).first << "\": ";
     752         [ +  + ]:        500 :         if ((*it).second) {
     753                 :        497 :             (*it).second->toJSON(ss);
     754                 :            :         } else {
     755                 :          3 :             ss << "None";
     756                 :            :         }
     757                 :            :     }
     758                 :        296 :     ss << " }";
     759                 :        296 : }
     760                 :            : 
     761                 :            : // throws when one of the types in the path (except the one
     762                 :            : // we're looking for) is not a MapElement
     763                 :            : // returns 0 if it could simply not be found
     764                 :            : // should that also be an exception?
     765                 :            : ConstElementPtr
     766                 :        258 : MapElement::find(const std::string& id) const {
     767                 :        258 :     const size_t sep = id.find('/');
     768         [ +  + ]:        258 :     if (sep == std::string::npos) {
     769                 :        240 :         return (get(id));
     770                 :            :     } else {
     771         [ +  - ]:         18 :         ConstElementPtr ce = get(id.substr(0, sep));
     772         [ +  + ]:         18 :         if (ce) {
     773                 :            :             // ignore trailing slash
     774         [ +  + ]:          6 :             if  (sep + 1 != id.size()) {
     775 [ +  - ][ +  + ]:          5 :                 return (ce->find(id.substr(sep + 1)));
     776                 :            :             } else {
     777                 :            :                 return (ce);
     778                 :            :             }
     779                 :            :         } else {
     780                 :            :             return (ElementPtr());
     781                 :            :         }
     782                 :            :     }
     783                 :            : }
     784                 :            : 
     785                 :            : ElementPtr
     786                 :          1 : Element::fromWire(const std::string& s) {
     787                 :          2 :     std::stringstream ss;
     788         [ +  - ]:          1 :     ss << s;
     789                 :          1 :     int line = 0, pos = 0;
     790 [ +  - ][ +  - ]:          2 :     return (fromJSON(ss, "<wire>", line, pos));
     791                 :            : }
     792                 :            : 
     793                 :            : ElementPtr
     794                 :         25 : Element::fromWire(std::stringstream& in, int) {
     795                 :            :     //
     796                 :            :     // Check protocol version
     797                 :            :     //
     798                 :            :     //for (int i = 0 ; i < 4 ; ++i) {
     799                 :            :     //    const unsigned char version_byte = get_byte(in);
     800                 :            :     //    if (PROTOCOL_VERSION[i] != version_byte) {
     801                 :            :     //        throw DecodeError("Protocol version incorrect");
     802                 :            :     //    }
     803                 :            :     //}
     804                 :            :     //length -= 4;
     805                 :         25 :     int line = 0, pos = 0;
     806         [ +  - ]:         25 :     return (fromJSON(in, "<wire>", line, pos));
     807                 :            : }
     808                 :            : 
     809                 :            : void
     810                 :      15428 : MapElement::set(const std::string& key, ConstElementPtr value) {
     811                 :      15428 :     m[key] = value;
     812                 :      15428 : }
     813                 :            : 
     814                 :            : bool
     815                 :          2 : MapElement::find(const std::string& id, ConstElementPtr t) const {
     816                 :            :     try {
     817         [ +  + ]:          2 :         ConstElementPtr p = find(id);
     818         [ +  - ]:          1 :         if (p) {
     819         [ +  - ]:          1 :             t = p;
     820                 :          1 :             return (true);
     821                 :            :         }
     822                 :          1 :     } catch (const TypeError&) {
     823                 :            :         // ignore
     824                 :            :     }
     825                 :            :     return (false);
     826                 :            : }
     827                 :            : 
     828                 :            : bool
     829                 :         88 : IntElement::equals(const Element& other) const {
     830                 :            :     return (other.getType() == Element::integer) &&
     831 [ +  + ][ +  + ]:         88 :            (i == other.intValue());
     832                 :            : }
     833                 :            : 
     834                 :            : bool
     835                 :          7 : DoubleElement::equals(const Element& other) const {
     836                 :            :     return (other.getType() == Element::real) &&
     837 [ +  + ][ -  + ]:          7 :            (d == other.doubleValue());
     838                 :            : }
     839                 :            : 
     840                 :            : bool
     841                 :          9 : BoolElement::equals(const Element& other) const {
     842                 :            :     return (other.getType() == Element::boolean) &&
     843 [ +  + ][ +  + ]:          9 :            (b == other.boolValue());
     844                 :            : }
     845                 :            : 
     846                 :            : bool
     847                 :          1 : NullElement::equals(const Element& other) const {
     848                 :          1 :     return (other.getType() == Element::null);
     849                 :            : }
     850                 :            : 
     851                 :            : bool
     852                 :        443 : StringElement::equals(const Element& other) const {
     853                 :            :     return (other.getType() == Element::string) &&
     854 [ +  + ][ +  + ]:        882 :            (s == other.stringValue());
                 [ +  + ]
     855                 :            : }
     856                 :            : 
     857                 :            : bool
     858                 :        327 : ListElement::equals(const Element& other) const {
     859         [ +  + ]:        327 :     if (other.getType() == Element::list) {
     860                 :        324 :         const size_t s = size();
     861         [ +  + ]:        324 :         if (s != other.size()) {
     862                 :            :             return (false);
     863                 :            :         }
     864         [ +  + ]:        783 :         for (size_t i = 0; i < s; ++i) {
     865         [ +  - ]:        912 :             if (!get(i)->equals(*other.get(i))) {
           [ +  -  +  + ]
     866                 :            :                 return (false);
     867                 :            :             }
     868                 :            :         }
     869                 :            :         return (true);
     870                 :            :     } else {
     871                 :            :         return (false);
     872                 :            :     }
     873                 :            : }
     874                 :            : 
     875                 :            : bool
     876                 :        159 : MapElement::equals(const Element& other) const {
     877         [ +  + ]:        159 :     if (other.getType() == Element::map) {
     878                 :        156 :         const std::map<std::string, ConstElementPtr>& m = mapValue();
     879         [ +  + ]:        329 :         for (std::map<std::string, ConstElementPtr>::const_iterator it =
     880                 :        156 :                  m.begin();
     881                 :        329 :              it != m.end() ; ++it) {
     882         [ +  + ]:        207 :             if (other.contains((*it).first)) {
     883         [ +  - ]:        410 :                 if (!get((*it).first)->equals(*other.get((*it).first))) {
           [ +  -  +  + ]
     884                 :            :                     return (false);
     885                 :            :                 }
     886                 :            :             } else {
     887                 :            :                 return (false);
     888                 :            :             }
     889                 :            :         }
     890                 :            :         // quickly walk through the other map too, to see if there's
     891                 :            :         // anything in there that we don't have. We don't need to
     892                 :            :         // compare those elements; if one of them is missing we
     893                 :            :         // differ (and if it's not missing the loop above has checked
     894                 :            :         // it)
     895                 :            :         std::map<std::string, ConstElementPtr>::const_iterator it;
     896         [ +  + ]:        621 :         for (it = other.mapValue().begin();
     897                 :        292 :              it != other.mapValue().end();
     898                 :            :              ++it) {
     899         [ +  - ]:        170 :             if (!contains((*it).first)) {
     900                 :            :                 return (false);
     901                 :            :             }
     902                 :            :         }
     903                 :            :         return (true);
     904                 :            :     } else {
     905                 :            :         return (false);
     906                 :            :     }
     907                 :            : }
     908                 :            : 
     909                 :            : bool
     910                 :         23 : isNull(ConstElementPtr p) {
     911                 :         23 :     return (!p);
     912                 :            : }
     913                 :            : 
     914                 :            : void
     915                 :         11 : removeIdentical(ElementPtr a, ConstElementPtr b) {
     916         [ +  - ]:         11 :     if (!b) {
     917                 :          9 :         return;
     918                 :            :     }
     919 [ +  + ][ +  - ]:         11 :     if (a->getType() != Element::map || b->getType() != Element::map) {
                 [ +  + ]
     920 [ +  - ][ +  - ]:          4 :         isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
     921                 :            :     }
     922                 :            : 
     923                 :            :     // As maps do not allow entries with multiple keys, we can either iterate
     924                 :            :     // over a checking for identical entries in b or vice-versa.  As elements
     925                 :            :     // are removed from a if a match is found, we choose to iterate over b to
     926                 :            :     // avoid problems with element removal affecting the iterator.
     927                 :          9 :     const std::map<std::string, ConstElementPtr>& m = b->mapValue();
     928         [ +  + ]:         18 :     for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
     929                 :         18 :          it != m.end() ; ++it) {
     930         [ +  - ]:          9 :         if (a->contains((*it).first)) {
     931         [ +  - ]:         18 :             if (a->get((*it).first)->equals(*b->get((*it).first))) {
           [ +  -  +  + ]
     932                 :          7 :                 a->remove((*it).first);
     933                 :            :             }
     934                 :            :         }
     935                 :            :     }
     936                 :            : }
     937                 :            : 
     938                 :            : ConstElementPtr
     939                 :         15 : removeIdentical(ConstElementPtr a, ConstElementPtr b) {
     940                 :         15 :     ElementPtr result = Element::createMap();
     941                 :            : 
     942         [ -  + ]:         15 :     if (!b) {
     943                 :            :         return (result);
     944                 :            :     }
     945                 :            :     
     946 [ +  - ][ +  - ]:         15 :     if (a->getType() != Element::map || b->getType() != Element::map) {
                 [ -  + ]
     947 [ #  # ][ #  # ]:          0 :         isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
                 [ #  # ]
     948                 :            :     }
     949                 :            : 
     950         [ +  - ]:         15 :     const std::map<std::string, ConstElementPtr>& m = a->mapValue();
     951         [ +  + ]:         30 :     for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
     952                 :         30 :          it != m.end() ; ++it) {
     953 [ +  - ][ +  + ]:         40 :         if (!b->contains((*it).first) ||
         [ +  + ][ +  + ]
     954 [ +  - ][ +  - ]:         35 :             !a->get((*it).first)->equals(*b->get((*it).first))) {
         [ +  - ][ +  + ]
         [ +  + ][ #  # ]
                 [ #  # ]
     955         [ +  - ]:         16 :             result->set((*it).first, (*it).second);
     956                 :            :         }
     957                 :            :     }
     958                 :            : 
     959                 :            :     return (result);
     960                 :            : }
     961                 :            : 
     962                 :            : void
     963                 :         39 : merge(ElementPtr element, ConstElementPtr other) {
     964   [ +  +  +  - ]:         77 :     if (element->getType() != Element::map ||
                 [ +  + ]
     965                 :         38 :         other->getType() != Element::map) {
     966 [ +  - ][ +  - ]:          2 :         isc_throw(TypeError, "merge arguments not MapElements");
     967                 :            :     }
     968                 :            :     
     969                 :         38 :     const std::map<std::string, ConstElementPtr>& m = other->mapValue();
     970         [ +  + ]:         71 :     for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
     971                 :         71 :          it != m.end() ; ++it) {
     972 [ +  - ][ +  + ]:         33 :         if ((*it).second && (*it).second->getType() != Element::null) {
                 [ +  + ]
     973         [ +  - ]:         60 :             element->set((*it).first, (*it).second);
     974         [ +  - ]:          3 :         } else if (element->contains((*it).first)) {
     975                 :          3 :             element->remove((*it).first);
     976                 :            :         }
     977                 :            :     }
     978                 :         38 : }
     979                 :            : 
     980                 :            : }
     981                 :        139 : }

Generated by: LCOV version 1.9