]> git.stg.codes - stg.git/blob - libs/json/parser.cpp
Install Boost in GitHub Actions.
[stg.git] / libs / json / parser.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
19  */
20
21 #include "stg/json_parser.h"
22
23 #include <yajl/yajl_parse.h>
24
25 using STG::JSON::Parser;
26 using STG::JSON::NodeParser;
27
28 class Parser::Impl
29 {
30     public:
31         Impl(NodeParser* topParser);
32         ~Impl()
33         {
34             yajl_free(m_handle);
35         }
36
37         bool append(const char* data, size_t size) { return yajl_parse(m_handle, reinterpret_cast<const unsigned char*>(data), size) == yajl_status_ok; }
38         bool last() { return yajl_complete_parse(m_handle) == yajl_status_ok; }
39
40         static int parseNull(void* ctx)
41         { return runParser(ctx, &NodeParser::parseNull); }
42         static int parseBoolean(void* ctx, int value)
43         { return runParser(ctx, &NodeParser::parseBoolean, value != 0); }
44         static int parseNumber(void* ctx, const char* value, size_t size)
45         { return runParser(ctx, &NodeParser::parseNumber, std::string(value, size)); }
46         static int parseString(void* ctx, const unsigned char* value, size_t size)
47         { return runParser(ctx, &NodeParser::parseString, std::string(reinterpret_cast<const char*>(value), size)); }
48         static int parseStartMap(void* ctx)
49         { return runParser(ctx, &NodeParser::parseStartMap); }
50         static int parseMapKey(void* ctx, const unsigned char* value, size_t size)
51         { return runParser(ctx, &NodeParser::parseMapKey, std::string(reinterpret_cast<const char*>(value), size)); }
52         static int parseEndMap(void* ctx)
53         { return runParser(ctx, &NodeParser::parseEndMap); }
54         static int parseStartArray(void* ctx)
55         { return runParser(ctx, &NodeParser::parseStartArray); }
56         static int parseEndArray(void* ctx)
57         { return runParser(ctx, &NodeParser::parseEndArray); }
58
59     private:
60         yajl_handle m_handle;
61         NodeParser* m_parser;
62
63         static yajl_callbacks callbacks;
64
65         static NodeParser& getParser(void* ctx) { return *static_cast<Impl*>(ctx)->m_parser; }
66         static bool runParser(void* ctx, NodeParser* (NodeParser::*func)())
67         {
68             Impl& p = *static_cast<Impl*>(ctx);
69             NodeParser* next = (p.m_parser->*func)();
70             if (next != NULL)
71                 p.m_parser = next;
72             return next != NULL;
73         }
74         template <typename T>
75         static bool runParser(void* ctx, NodeParser* (NodeParser::*func)(const T&), const T& value)
76         {
77             Impl& p = *static_cast<Impl*>(ctx);
78             NodeParser* next = (p.m_parser->*func)(value);
79             if (next != NULL)
80                 p.m_parser = next;
81             return next != NULL;
82         }
83 };
84
85 yajl_callbacks Parser::Impl::callbacks = {
86     Parser::Impl::parseNull,
87     Parser::Impl::parseBoolean,
88     NULL, // parsing of integer is done using parseNumber
89     NULL, // parsing of double is done using parseNumber
90     Parser::Impl::parseNumber,
91     Parser::Impl::parseString,
92     Parser::Impl::parseStartMap,
93     Parser::Impl::parseMapKey,
94     Parser::Impl::parseEndMap,
95     Parser::Impl::parseStartArray,
96     Parser::Impl::parseEndArray
97 };
98
99 Parser::Impl::Impl(NodeParser* topParser)
100     : m_handle(yajl_alloc(&callbacks, NULL, this)),
101       m_parser(topParser)
102 {
103     yajl_config(m_handle, yajl_allow_multiple_values, 1);
104 }
105
106 Parser::Parser(NodeParser* topParser)
107     : m_impl(new Impl(topParser))
108 {
109 }
110
111 Parser::~Parser()
112 {
113 }
114
115 bool Parser::append(const char* data, size_t size)
116 {
117     return m_impl->append(data, size);
118 }
119
120 bool Parser::last()
121 {
122     return m_impl->last();
123 }