kazuho/picojson

Weird issues when using custom parse contexts

Closed this issue · 1 comments

exavi commented

Hi there,

I seem to be having some issues when trying to create parsing contexts and I was wondering what I might be missing.

This is my input data:

[
    {
        "entry": "blah"
    }, 
    {
        "nested": "{\"dict\": 1, \"some\": \"string\"}"
    }
]

I seem to get this error message when trying to parse it using a custom parsing context class, err is filled with:

syntax error at line 1 near: {

The class I'm using is pretty much copied from the streaming example:

class ParseCmdContext : public picojson::deny_parse_context
{
public:
    ParseCmdContext()
        : m_count(0)
    {}

    bool parse_array_start()
    {
        return true;
    }

    template <typename Iter>
    bool parse_array_item(picojson::input<Iter>& in, size_t)
    {
        picojson::value item;
        picojson::default_parse_context ctx(&item);
        if(!picojson::_parse(ctx, in))
            return false;
        if(!item.is<picojson::object>())
            return false;

        std::cout << item.serialize(false) << std::endl;
        m_count++;
        return true;
    }

    bool parse_array_stop(size_t)
    {
        return true;
    }

    inline uint32_t count()const { return m_count; }

private:
    uint32_t m_count;
};

void test(const std::string& str)
{
   ParseCmdContext ctx;
    std::string err;
    picojson::_parse(ctx, str.c_str(), str.c_str()+strlen(str.c_str()), &err);

    if(!err.empty())
    {
        //error is printed here <<<
        std::cerr <<"ParseCmdCtx "<< err << std::endl;
    }

     err.clear();
    picojson::value unused;
     picojson::default_parse_context ctx(&unused);
    picojson::_parse(ctx, str.c_str(), str.c_str()+strlen(str.c_str()), &err);

    if(!err.empty())
    {
        // but not here, this works! which suggests that I'm doing something wrong...
        std::cerr <<"default_parse_context "<< err << std::endl;
    }
}

I have tried making a "bypass" context that is literally a copy of default_parse_context with prints added and it seems to show the same error as the above one when called, strangely enough, the default_parse_context works fine again.

class ParseSceneContext
{
protected:
    picojson::value *out_;

public:
    ParseSceneContext(picojson::value *out)
        : out_(out)
    {}

    bool set_null() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      *out_ = picojson::value();
      return true;
    }
    bool set_bool(bool b) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      *out_ = picojson::value(b);
      return true;
    }
  #ifdef PICOJSON_USE_INT64
    bool set_int64(int64_t i) {
      *out_ = value(i);
      return true;
    }
  #endif
    bool set_number(double f) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      *out_ = picojson::value(f);
      return true;
    }
    template <typename Iter>
    bool parse_string(picojson::input<Iter> &in) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      *out_ = picojson::value(picojson::string_type, false);
      return picojson::_parse_string(out_->get<std::string>(), in);
    }
    bool parse_array_start() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      *out_ = picojson::value(picojson::array_type, false);
      return true;
    }
    template <typename Iter>
    bool parse_array_item(picojson::input<Iter> &in, size_t) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      picojson::array &a = out_->get<picojson::array>();
      a.push_back(picojson::value());
      ParseSceneContext ctx(&a.back());
      return picojson::_parse(ctx, in);
    }
    bool parse_array_stop(size_t) {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      return true;
    }
    bool parse_object_start() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      *out_ = picojson::value(picojson::object_type, false);
      return true;
    }
    template <typename Iter>
    bool parse_object_item(picojson::input<Iter> &in, const std::string &key)
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
        std::cout << key << std::endl;
      picojson::object &o = out_->get<picojson::object>();
      ParseSceneContext ctx(&o[key]);
      return picojson::_parse(ctx, in);
    }
};

What am I missing?

Another weird thing I find with the streaming example is that it shows that it inherits from picojson::deny_parse_context but none of its methods are ever declared as virtual.

exavi commented

Please ignore this, I did a straight copy of the streaming example which can leave things in a "bad" state but after implementing all methods and "consuming" the remaining bits that needed to be read it works well.