LCOV - code coverage report
Current view: top level - as2js/lib - json.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 266 266 100.0 %
Date: 2014-08-10 Functions: 29 29 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* json.cpp -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2014 */
       2             : 
       3             : /*
       4             : 
       5             : Copyright (c) 2005-2014 Made to Order Software Corp.
       6             : 
       7             : http://snapwebsites.org/project/as2js
       8             : 
       9             : Permission is hereby granted, free of charge, to any
      10             : person obtaining a copy of this software and
      11             : associated documentation files (the "Software"), to
      12             : deal in the Software without restriction, including
      13             : without limitation the rights to use, copy, modify,
      14             : merge, publish, distribute, sublicense, and/or sell
      15             : copies of the Software, and to permit persons to whom
      16             : the Software is furnished to do so, subject to the
      17             : following conditions:
      18             : 
      19             : The above copyright notice and this permission notice
      20             : shall be included in all copies or substantial
      21             : portions of the Software.
      22             : 
      23             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
      24             : ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
      25             : LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
      26             : FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
      27             : EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      28             : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      29             : WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      30             : ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      31             : SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      32             : SOFTWARE.
      33             : 
      34             : */
      35             : 
      36             : #include    "as2js/json.h"
      37             : 
      38             : #include    "as2js/exceptions.h"
      39             : #include    "as2js/message.h"
      40             : 
      41             : #include    <iomanip>
      42             : 
      43             : 
      44             : namespace as2js
      45             : {
      46             : 
      47             : namespace
      48             : {
      49             : 
      50             : /** \brief Append a raw string to a stringified string.
      51             :  *
      52             :  * This function appends a string (str) to a stringified
      53             :  * string (result). In the process, it adds quotes to the
      54             :  * resulting string.
      55             :  *
      56             :  * \param[in,out] result  Where the output string is appended with a
      57             :  *                        valid string for a JSON file.
      58             :  * \param[in] str  The raw input string which needs to be stringified.
      59             :  */
      60        4071 : void append_string(String& result, String const& str)
      61             : {
      62        4071 :     result += '"';
      63        4071 :     size_t const max_chars(str.length());
      64       72626 :     for(size_t idx(0); idx < max_chars; ++idx)
      65             :     {
      66       68555 :         switch(str[idx])
      67             :         {
      68             :         case '\b':
      69         501 :             result += '\\';
      70         501 :             result += 'b';
      71         501 :             break;
      72             : 
      73             :         case '\f':
      74         464 :             result += '\\';
      75         464 :             result += 'f';
      76         464 :             break;
      77             : 
      78             :         case '\n':
      79         582 :             result += '\\';
      80         582 :             result += 'n';
      81         582 :             break;
      82             : 
      83             :         case '\r':
      84         673 :             result += '\\';
      85         673 :             result += 'r';
      86         673 :             break;
      87             : 
      88             :         case '\t':
      89         508 :             result += '\\';
      90         508 :             result += 't';
      91         508 :             break;
      92             : 
      93             :         case '"':
      94        3765 :             result += '\\';
      95        3765 :             result += '"';
      96        3765 :             break;
      97             : 
      98             :         case '\'':
      99        3749 :             result += '\\';
     100        3749 :             result += '\'';
     101        3749 :             break;
     102             : 
     103             :         default:
     104       58313 :             if(str[idx] < 0x0020)
     105             :             {
     106             :                 // other controls must be escaped using Unicode
     107       14643 :                 std::stringstream ss;
     108       14643 :                 ss << std::hex << "\\u" << std::setfill('0') << std::setw(4) << static_cast<int>(str[idx]);
     109       14643 :                 result += ss.str().c_str();
     110             :             }
     111             :             else
     112             :             {
     113       43670 :                 result += str[idx];
     114             :             }
     115       58313 :             break;
     116             : 
     117             :         }
     118             :     }
     119        4071 :     result += '"';
     120        4071 : }
     121             : 
     122             : }
     123             : // no name namespace
     124             : 
     125             : 
     126         209 : JSON::JSONValue::saving_t::saving_t(JSONValue const& value)
     127         209 :     : f_value(const_cast<JSONValue&>(value))
     128             : {
     129         209 :     if(f_value.f_saving)
     130             :     {
     131          20 :         throw exception_cyclical_structure("JSON cannot stringify a set of objects and arrays which are cyclical");
     132             :     }
     133         189 :     f_value.f_saving = true;
     134         189 : }
     135             : 
     136             : 
     137         189 : JSON::JSONValue::saving_t::~saving_t()
     138             : {
     139         189 :     f_value.f_saving = false;
     140         189 : }
     141             : 
     142             : 
     143             : 
     144             : 
     145         203 : JSON::JSONValue::JSONValue(Position const &position)
     146             :     : f_type(type_t::JSON_TYPE_NULL)
     147         203 :     , f_position(position)
     148             : {
     149         203 : }
     150             : 
     151             : 
     152        3800 : JSON::JSONValue::JSONValue(Position const &position, Int64 integer)
     153             :     : f_type(type_t::JSON_TYPE_INT64)
     154             :     , f_position(position)
     155        3800 :     , f_integer(integer)
     156             : {
     157        3800 : }
     158             : 
     159             : 
     160         311 : JSON::JSONValue::JSONValue(Position const &position, Float64 floating_point)
     161             :     : f_type(type_t::JSON_TYPE_FLOAT64)
     162             :     , f_position(position)
     163         311 :     , f_float(floating_point)
     164             : {
     165         311 : }
     166             : 
     167             : 
     168       13042 : JSON::JSONValue::JSONValue(Position const &position, String const& string)
     169             :     : f_type(type_t::JSON_TYPE_STRING)
     170             :     , f_position(position)
     171       13042 :     , f_string(string)
     172             : {
     173       13042 : }
     174             : 
     175             : 
     176         426 : JSON::JSONValue::JSONValue(Position const &position, bool boolean)
     177             :     : f_type(boolean ? type_t::JSON_TYPE_TRUE : type_t::JSON_TYPE_FALSE)
     178         426 :     , f_position(position)
     179             : {
     180         426 : }
     181             : 
     182             : 
     183        3525 : JSON::JSONValue::JSONValue(Position const &position, array_t const& array)
     184             :     : f_type(type_t::JSON_TYPE_ARRAY)
     185             :     , f_position(position)
     186        3525 :     , f_array(array)
     187             : {
     188        3525 : }
     189             : 
     190             : 
     191        8670 : JSON::JSONValue::JSONValue(Position const &position, object_t const& object)
     192             :     : f_type(type_t::JSON_TYPE_OBJECT)
     193             :     , f_position(position)
     194        8670 :     , f_object(object)
     195             : {
     196        8670 : }
     197             : 
     198             : 
     199    20584560 : JSON::JSONValue::type_t JSON::JSONValue::get_type() const
     200             : {
     201    20584560 :     return f_type;
     202             : }
     203             : 
     204             : 
     205     8109812 : Int64 JSON::JSONValue::get_int64() const
     206             : {
     207     8109812 :     if(f_type != type_t::JSON_TYPE_INT64)
     208             :     {
     209         450 :         throw exception_internal_error("get_int64() called with a non-int64 value type");
     210             :     }
     211     8109362 :     return f_integer;
     212             : }
     213             : 
     214             : 
     215      262874 : Float64 JSON::JSONValue::get_float64() const
     216             : {
     217      262874 :     if(f_type != type_t::JSON_TYPE_FLOAT64)
     218             :     {
     219         450 :         throw exception_internal_error("get_float64() called with a non-float64 value type");
     220             :     }
     221      262424 :     return f_float;
     222             : }
     223             : 
     224             : 
     225    38639151 : String const& JSON::JSONValue::get_string() const
     226             : {
     227    38639151 :     if(f_type != type_t::JSON_TYPE_STRING)
     228             :     {
     229         450 :         throw exception_internal_error("get_string() called with a non-string value type");
     230             :     }
     231    38638701 :     return f_string;
     232             : }
     233             : 
     234             : 
     235    13560193 : JSON::JSONValue::array_t const& JSON::JSONValue::get_array() const
     236             : {
     237    13560193 :     if(f_type != type_t::JSON_TYPE_ARRAY)
     238             :     {
     239         628 :         throw exception_internal_error("get_array() called with a non-array value type");
     240             :     }
     241    13559565 :     return f_array;
     242             : }
     243             : 
     244             : 
     245         762 : void JSON::JSONValue::set_item(size_t idx, JSONValue::pointer_t value)
     246             : {
     247         762 :     if(f_type != type_t::JSON_TYPE_ARRAY)
     248             :     {
     249         628 :         throw exception_internal_error("set_item() called with a non-array value type");
     250             :     }
     251         134 :     if(idx > f_array.size())
     252             :     {
     253          40 :         throw exception_index_out_of_range("JSON::JSONValue::set_item() called with an index out of bounds");
     254             :     }
     255          94 :     if(!value)
     256             :     {
     257           2 :         throw exception_invalid_data("JSON::JSONValue::set_item() called with a null pointer as the value");
     258             :     }
     259          92 :     if(idx == f_array.size())
     260             :     {
     261             :         // append value
     262          82 :         f_array.push_back(value);
     263             :     }
     264             :     else
     265             :     {
     266             :         // replace previous value
     267          10 :         f_array[idx] = value;
     268             :     }
     269          92 : }
     270             : 
     271             : 
     272    24517532 : JSON::JSONValue::object_t const& JSON::JSONValue::get_object() const
     273             : {
     274    24517532 :     if(f_type != type_t::JSON_TYPE_OBJECT)
     275             :     {
     276         628 :         throw exception_internal_error("get_object() called with a non-object value type");
     277             :     }
     278    24516904 :     return f_object;
     279             : }
     280             : 
     281             : 
     282        2033 : void JSON::JSONValue::set_member(String const& name, JSONValue::pointer_t value)
     283             : {
     284        2033 :     if(f_type != type_t::JSON_TYPE_OBJECT)
     285             :     {
     286         628 :         throw exception_internal_error("set_member() called with a non-object value type");
     287             :     }
     288        1405 :     if(name.empty())
     289             :     {
     290             :         // TBD: is that really not allowed?
     291           2 :         throw exception_invalid_index("JSON::JSONValue::set_member() called with an empty string as the member name");
     292             :     }
     293        1403 :     if(!value)
     294             :     {
     295           2 :         throw exception_invalid_data("JSON::JSONValue::set_member() called with a null pointer as the value");
     296             :     }
     297             : 
     298             :     // this one is easy enough
     299        1401 :     f_object[name] = value;
     300        1401 : }
     301             : 
     302             : 
     303        1986 : Position const& JSON::JSONValue::get_position() const
     304             : {
     305        1986 :     return f_position;
     306             : }
     307             : 
     308             : 
     309        8343 : String JSON::JSONValue::to_string() const
     310             : {
     311        8343 :     String result;
     312             : 
     313        8343 :     switch(f_type)
     314             :     {
     315             :     case type_t::JSON_TYPE_ARRAY:
     316        1085 :         result += "[";
     317        1085 :         if(f_array.size() > 0)
     318             :         {
     319         103 :             saving_t s(*this);
     320          93 :             result += f_array[0]->to_string(); // recursive
     321          93 :             size_t const max_elements(f_array.size());
     322        4630 :             for(size_t i(1); i < max_elements; ++i)
     323             :             {
     324        4547 :                 result += ",";
     325        4547 :                 result += f_array[i]->to_string(); // recursive
     326         103 :             }
     327             :         }
     328        1065 :         result += "]";
     329        1065 :         break;
     330             : 
     331             :     case type_t::JSON_TYPE_FALSE:
     332         967 :         return "false";
     333             : 
     334             :     case type_t::JSON_TYPE_FLOAT64:
     335        1077 :         return std::to_string(f_float.get());
     336             : 
     337             :     case type_t::JSON_TYPE_INT64:
     338        1279 :         return std::to_string(f_integer.get());
     339             : 
     340             :     case type_t::JSON_TYPE_NULL:
     341         972 :         return "null";
     342             : 
     343             :     case type_t::JSON_TYPE_OBJECT:
     344         899 :         result += "{";
     345         899 :         if(f_object.size() > 0)
     346             :         {
     347         106 :             saving_t s(*this);
     348          96 :             object_t::const_iterator obj(f_object.begin());
     349          96 :             append_string(result, obj->first);
     350          96 :             result += ":";
     351          96 :             result += obj->second->to_string(); // recursive
     352        2932 :             for(++obj; obj != f_object.end(); ++obj)
     353             :             {
     354        2846 :                 result += ",";
     355        2846 :                 append_string(result, obj->first);
     356        2846 :                 result += ":";
     357        2846 :                 result += obj->second->to_string(); // recursive
     358         106 :             }
     359             :         }
     360         879 :         result += "}";
     361         879 :         break;
     362             : 
     363             :     case type_t::JSON_TYPE_STRING:
     364        1129 :         append_string(result, f_string);
     365        1129 :         break;
     366             : 
     367             :     case type_t::JSON_TYPE_TRUE:
     368         935 :         return "true";
     369             : 
     370             :     case type_t::JSON_TYPE_UNKNOWN:
     371             :         throw exception_internal_error("JSON type \"Unknown\" is not valid and should never be used (it should not be possible to use it to create a JSONValue in the first place!)"); // LCOV_EXCL_LINE
     372             : 
     373             :     }
     374             : 
     375        8343 :     return result;
     376             : }
     377             : 
     378             : 
     379             : 
     380             : 
     381          13 : JSON::JSONValue::pointer_t JSON::load(String const& filename)
     382             : {
     383          13 :     Position pos;
     384          13 :     pos.set_filename(filename);
     385             : 
     386             :     // we could not find this module, try to load the it
     387          26 :     FileInput::pointer_t in(new FileInput());
     388          13 :     if(!in->open(filename))
     389             :     {
     390           1 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_NOT_FOUND, pos);
     391           1 :         msg << "cannot open JSON file \"" << filename << "\".";
     392             :         // should we throw here?
     393           1 :         return JSONValue::pointer_t();
     394             :     }
     395             : 
     396          25 :     return parse(in);
     397             : }
     398             : 
     399             : 
     400      102702 : JSON::JSONValue::pointer_t JSON::parse(Input::pointer_t in)
     401             : {
     402             :     // Parse the JSON file
     403             :     //
     404             :     // Note:
     405             :     // We do not allow external options because it does not make sense
     406             :     // (i.e. JSON is very simple and no additional options should affect
     407             :     // the lexer!)
     408      102702 :     Options::pointer_t options(new Options);
     409             :     // Make sure it is marked as JSON (line terminators change in this case)
     410      102702 :     options->set_option(Options::option_t::OPTION_JSON, 1);
     411      102702 :     f_lexer.reset(new Lexer(in, options));
     412      102702 :     f_value = read_json_value(f_lexer->get_next_token());
     413             : 
     414      102702 :     if(!f_value)
     415             :     {
     416      102666 :         Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_CANNOT_COMPILE, in->get_position());
     417      102666 :         msg << "could not interpret this JSON input \"" << in->get_position().get_filename() << "\".";
     418             :         // should we throw here?
     419             :     }
     420             : 
     421      102702 :     f_lexer.reset(); // release 'in' and 'options' pointers
     422             : 
     423      102702 :     return f_value;
     424             : }
     425             : 
     426             : 
     427      125076 : JSON::JSONValue::pointer_t JSON::read_json_value(Node::pointer_t n)
     428             : {
     429      125076 :     if(n->get_type() == Node::node_t::NODE_EOF)
     430             :     {
     431           1 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_UNEXPECTED_EOF, n->get_position());
     432           1 :         msg << "the end of the file was reached while reading JSON data.";
     433           1 :         return JSONValue::pointer_t();
     434             :     }
     435      125075 :     switch(n->get_type())
     436             :     {
     437             :     case Node::node_t::NODE_FALSE:
     438      125076 :         return JSONValue::pointer_t(new JSONValue(n->get_position(), false));
     439             : 
     440             :     case Node::node_t::NODE_FLOAT64:
     441          33 :         return JSONValue::pointer_t(new JSONValue(n->get_position(), n->get_float64()));
     442             : 
     443             :     case Node::node_t::NODE_INT64:
     444        2277 :         return JSONValue::pointer_t(new JSONValue(n->get_position(), n->get_int64()));
     445             : 
     446             :     case Node::node_t::NODE_NULL:
     447          23 :         return JSONValue::pointer_t(new JSONValue(n->get_position()));
     448             : 
     449             :     case Node::node_t::NODE_OPEN_CURVLY_BRACKET: // read an object
     450             :         {
     451        6304 :             JSONValue::object_t obj;
     452             : 
     453       12608 :             Position pos(n->get_position());
     454        6304 :             n = f_lexer->get_next_token();
     455        6304 :             if(n->get_type() != Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     456             :             {
     457             :                 for(;;)
     458             :                 {
     459       16307 :                     if(n->get_type() != Node::node_t::NODE_STRING)
     460             :                     {
     461           5 :                         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_STRING_EXPECTED, n->get_position());
     462           5 :                         msg << "expected a string as the JSON object member name.";
     463           5 :                         return JSONValue::pointer_t();
     464             :                     }
     465       16302 :                     String name(n->get_string());
     466       16302 :                     n = f_lexer->get_next_token();
     467       16302 :                     if(n->get_type() != Node::node_t::NODE_COLON)
     468             :                     {
     469           2 :                         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_COLON_EXPECTED, n->get_position());
     470           2 :                         msg << "expected a colon (:) as the JSON object member name and member value separator.";
     471           2 :                         return JSONValue::pointer_t();
     472             :                     }
     473             :                     // skip the colon
     474       16300 :                     n = f_lexer->get_next_token();
     475       32602 :                     JSONValue::pointer_t value(read_json_value(n)); // recursive
     476       16300 :                     if(!value)
     477             :                     {
     478             :                         // empty values mean we got an error, stop short!
     479           2 :                         return value;
     480             :                     }
     481       16298 :                     if(obj.find(name) != obj.end())
     482             :                     {
     483             :                         // TBD: we should verify that JSON indeed forbids such
     484             :                         //      nonsense; because we may have it wrong
     485           1 :                         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_OBJECT_MEMBER_DEFINED_TWICE, n->get_position());
     486           1 :                         msg << "the same object member \"" << name << "\" was defined twice, which is not allowed in JSON.";
     487             :                         // continue because (1) the existing element is valid
     488             :                         // and (2) the new element is valid
     489             :                     }
     490             :                     else
     491             :                     {
     492       16297 :                         obj[name] = value;
     493             :                     }
     494       16298 :                     n = f_lexer->get_next_token();
     495       16298 :                     if(n->get_type() == Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     496             :                     {
     497        6287 :                         break;
     498             :                     }
     499       10011 :                     if(n->get_type() != Node::node_t::NODE_COMMA)
     500             :                     {
     501           1 :                         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_COMMA_EXPECTED, n->get_position());
     502           1 :                         msg << "expected a comma (,) to separate two JSON object members.";
     503           1 :                         return JSONValue::pointer_t();
     504             :                     }
     505       16300 :                     n = f_lexer->get_next_token();
     506       16307 :                 }
     507             :             }
     508             : 
     509       12598 :             return JSONValue::pointer_t(new JSONValue(pos, obj));
     510             :         }
     511             :         break;
     512             : 
     513             :     case Node::node_t::NODE_OPEN_SQUARE_BRACKET: // read an array
     514             :         {
     515        3335 :             JSONValue::array_t array;
     516             : 
     517        6670 :             Position pos(n->get_position());
     518        3335 :             n = f_lexer->get_next_token();
     519        3335 :             if(n->get_type() != Node::node_t::NODE_CLOSE_SQUARE_BRACKET)
     520             :             {
     521             :                 for(;;)
     522             :                 {
     523        6074 :                     JSONValue::pointer_t value(read_json_value(n)); // recursive
     524        6074 :                     if(!value)
     525             :                     {
     526             :                         // empty values mean we got an error, stop short!
     527           3 :                         return value;
     528             :                     }
     529        6071 :                     array.push_back(value);
     530        6071 :                     n = f_lexer->get_next_token();
     531        6071 :                     if(n->get_type() == Node::node_t::NODE_CLOSE_SQUARE_BRACKET)
     532             :                     {
     533        3326 :                         break;
     534             :                     }
     535        2745 :                     if(n->get_type() != Node::node_t::NODE_COMMA)
     536             :                     {
     537           2 :                         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_COMMA_EXPECTED, n->get_position());
     538           2 :                         msg << "expected a comma (,) to separate two JSON array items.";
     539           2 :                         return JSONValue::pointer_t();
     540             :                     }
     541        6074 :                     n = f_lexer->get_next_token();
     542        6074 :                 }
     543             :             }
     544             : 
     545        6665 :             return JSONValue::pointer_t(new JSONValue(pos, array));
     546             :         }
     547             :         break;
     548             : 
     549             :     case Node::node_t::NODE_STRING:
     550       10341 :         return JSONValue::pointer_t(new JSONValue(n->get_position(), n->get_string()));
     551             : 
     552             :     case Node::node_t::NODE_SUBTRACT:
     553             :         // negative number...
     554          31 :         n = f_lexer->get_next_token();
     555          31 :         switch(n->get_type())
     556             :         {
     557             :         case Node::node_t::NODE_FLOAT64:
     558             :             {
     559          15 :                 Float64 f(n->get_float64());
     560          15 :                 f.set(-f.get());
     561          15 :                 n->set_float64(f);
     562             :             }
     563          15 :             return JSONValue::pointer_t(new JSONValue(n->get_position(), n->get_float64()));
     564             : 
     565             :         case Node::node_t::NODE_INT64:
     566             :             {
     567          15 :                 Int64 i(n->get_int64());
     568          15 :                 i.set(-i.get());
     569          15 :                 n->set_int64(i);
     570             :             }
     571          15 :             return JSONValue::pointer_t(new JSONValue(n->get_position(), n->get_int64()));
     572             : 
     573             :         default:
     574           1 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_UNEXPECTED_TOKEN, n->get_position());
     575           1 :             msg << "unexpected token (" << n->get_type_name() << ") found after a '-' sign, a number was expected.";
     576          31 :             return JSONValue::pointer_t();
     577             : 
     578             :         }
     579             :         /*NOT_REACHED*/
     580             :         break;
     581             : 
     582             :     case Node::node_t::NODE_TRUE:
     583          65 :         return JSONValue::pointer_t(new JSONValue(n->get_position(), true));
     584             : 
     585             :     default:
     586      102654 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_UNEXPECTED_TOKEN, n->get_position());
     587      102654 :         msg << "unexpected token (" << n->get_type_name() << ") found in a JSON input stream.";
     588      102654 :         return JSONValue::pointer_t();
     589             : 
     590             :     }
     591             : }
     592             : 
     593             : 
     594          12 : bool JSON::save(String const& filename, String const& header) const
     595             : {
     596          12 :     FileOutput::pointer_t out(new FileOutput());
     597          12 :     if(!out->open(filename))
     598             :     {
     599           1 :         Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_CANNOT_COMPILE, out->get_position());
     600           1 :         msg << "could not open output file \"" << filename << "\".";
     601           1 :         return false;
     602             :     }
     603             : 
     604          12 :     return output(out, header);
     605             : }
     606             : 
     607             : 
     608          32 : bool JSON::output(Output::pointer_t out, String const& header) const
     609             : {
     610          32 :     if(!f_value)
     611             :     {
     612             :         // should we instead output "null"?
     613           1 :         throw exception_invalid_data("this JSON has no value to output");
     614             :     }
     615             : 
     616             :     // start with a BOM so the file is clearly marked as being UTF-8
     617          31 :     as2js::String bom;
     618          31 :     bom += String::STRING_BOM;
     619          31 :     out->write(bom);
     620             : 
     621          31 :     if(!header.empty())
     622             :     {
     623          10 :         out->write(header);
     624          10 :         out->write("\n");
     625             :     }
     626             : 
     627          31 :     out->write(f_value->to_string());
     628             : 
     629          31 :     return true;
     630             : }
     631             : 
     632             : 
     633          12 : void JSON::set_value(JSON::JSONValue::pointer_t value)
     634             : {
     635          12 :     f_value = value;
     636          12 : }
     637             : 
     638             : 
     639          50 : JSON::JSONValue::pointer_t JSON::get_value() const
     640             : {
     641          50 :     return f_value;
     642             : }
     643             : 
     644             : 
     645          20 : }
     646             : // namespace as2js
     647             : 
     648             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.9