Zserio C++17 runtime library 1.3.0
Built for Zserio 2.20.0
Loading...
Searching...
No Matches
JsonTokenizer.h
Go to the documentation of this file.
1#ifndef ZSERIO_JSON_TOKENIZER_H_INC
2#define ZSERIO_JSON_TOKENIZER_H_INC
3
4#include <array>
5#include <istream>
6#include <memory>
7#include <string_view>
8
9#include "zserio/Any.h"
11#include "zserio/JsonDecoder.h"
12#include "zserio/String.h"
13
14namespace zserio
15{
16
33
44
54
58template <typename ALLOC = std::allocator<uint8_t>>
60{
61public:
63
70 BasicJsonTokenizer(std::istream& in, const ALLOC& allocator) :
71 m_buffer(),
72 m_in(in),
73 m_decoder(allocator),
74 m_decoderResult(0, allocator),
75 m_content(readContent(allocator)),
76 m_value(allocator)
77 {
78 m_token = m_content.empty() ? JsonToken::END_OF_FILE : JsonToken::BEGIN_OF_FILE;
79 }
80
88
95 {
96 return m_token;
97 }
98
108 {
109 return m_value;
110 }
111
117 size_t getLine() const
118 {
119 return m_lineNumber;
120 }
121
127 size_t getColumn() const
128 {
129 return m_tokenColumnNumber;
130 }
131
132private:
134
135 bool decodeNext();
136 bool skipWhitespaces();
137
138 template <typename T>
139 void setToken(JsonToken token, T&& value);
140 void setToken(JsonToken token, BasicAny<ALLOC>&& value);
141 void setToken(JsonToken token);
142 void setPosition(size_t newPos, size_t newColumnNumber);
143 void setTokenValue();
144
145 static constexpr size_t BUFFER_SIZE = 64 * 1024;
146 std::array<char, BUFFER_SIZE> m_buffer;
147
148 std::istream& m_in;
149 BasicJsonDecoder<ALLOC> m_decoder;
150 typename BasicJsonDecoder<ALLOC>::DecoderResult m_decoderResult;
152 size_t m_lineNumber = 1;
153 size_t m_columnNumber = 1;
154 size_t m_tokenColumnNumber = 1;
155 size_t m_pos = 0;
156 JsonToken m_token;
157 BasicAny<ALLOC> m_value;
158};
159
160template <typename ALLOC>
162{
163 while (!decodeNext())
164 {
165 BasicString<RebindAlloc<ALLOC, char>> newContent = readContent(m_content.get_allocator());
166 if (newContent.empty())
167 {
168 if (m_token == JsonToken::END_OF_FILE)
169 {
170 m_tokenColumnNumber = m_columnNumber;
171 }
172 else
173 {
174 // stream is finished but last token is not EOF => value must be at the end
175 setTokenValue();
176 }
177
178 return m_token;
179 }
180
181 m_content = m_content.substr(m_pos) + newContent;
182 m_pos = 0;
183 }
184
185 return m_token;
186}
187
188template <typename ALLOC>
190{
191 const size_t count = static_cast<size_t>(m_in.rdbuf()->sgetn(m_buffer.data(), BUFFER_SIZE));
192
193 return BasicString<RebindAlloc<ALLOC, char>>(m_buffer.data(), count, allocator);
194}
195
196template <typename ALLOC>
197bool BasicJsonTokenizer<ALLOC>::decodeNext()
198{
199 if (!skipWhitespaces())
200 {
201 return false;
202 }
203
204 m_tokenColumnNumber = m_columnNumber;
205
206 const char nextChar = m_content[m_pos];
207 switch (nextChar)
208 {
209 case '{':
210 setToken(JsonToken::BEGIN_OBJECT, nextChar);
211 setPosition(m_pos + 1, m_columnNumber + 1);
212 break;
213 case '}':
214 setToken(JsonToken::END_OBJECT, nextChar);
215 setPosition(m_pos + 1, m_columnNumber + 1);
216 break;
217 case '[':
218 setToken(JsonToken::BEGIN_ARRAY, nextChar);
219 setPosition(m_pos + 1, m_columnNumber + 1);
220 break;
221 case ']':
222 setToken(JsonToken::END_ARRAY, nextChar);
223 setPosition(m_pos + 1, m_columnNumber + 1);
224 break;
225 case ':':
226 setToken(JsonToken::KEY_SEPARATOR, nextChar);
227 setPosition(m_pos + 1, m_columnNumber + 1);
228 break;
229 case ',':
230 setToken(JsonToken::ITEM_SEPARATOR, nextChar);
231 setPosition(m_pos + 1, m_columnNumber + 1);
232 break;
233 default:
234 m_decoderResult = m_decoder.decodeValue(std::string_view(m_content.data()).substr(m_pos));
235 if (m_pos + m_decoderResult.numReadChars >= m_content.size())
236 {
237 return false; // we are at the end of chunk => read more
238 }
239
240 setTokenValue();
241 break;
242 }
243
244 return true;
245}
246
247template <typename ALLOC>
248bool BasicJsonTokenizer<ALLOC>::skipWhitespaces()
249{
250 while (true)
251 {
252 if (m_pos >= m_content.size())
253 {
254 setToken(JsonToken::END_OF_FILE);
255 return false;
256 }
257
258 const char nextChar = m_content[m_pos];
259 switch (nextChar)
260 {
261 case ' ':
262 case '\t':
263 setPosition(m_pos + 1, m_columnNumber + 1);
264 break;
265 case '\n':
266 m_lineNumber++;
267 setPosition(m_pos + 1, 1);
268 break;
269 case '\r':
270 if (m_pos + 1 >= m_content.size())
271 {
272 setToken(JsonToken::END_OF_FILE);
273 return false;
274 }
275 m_lineNumber++;
276 setPosition(m_pos + (m_content[m_pos + 1] == '\n' ? 2 : 1), 1);
277 break;
278 default:
279 return true;
280 }
281 }
282}
283
284template <typename ALLOC>
285template <typename T>
286void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token, T&& value)
287{
288 m_token = token;
289 m_value.set(std::forward<T>(value));
290}
291
292template <typename ALLOC>
293void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token, BasicAny<ALLOC>&& value)
294{
295 m_token = token;
296 m_value = std::move(value);
297}
298
299template <typename ALLOC>
300void BasicJsonTokenizer<ALLOC>::setToken(JsonToken token)
301{
302 m_token = token;
303 m_value.reset();
304}
305
306template <typename ALLOC>
307void BasicJsonTokenizer<ALLOC>::setPosition(size_t newPos, size_t newColumnNumber)
308{
309 m_pos = newPos;
310 m_columnNumber = newColumnNumber;
311}
312
313template <typename ALLOC>
314void BasicJsonTokenizer<ALLOC>::setTokenValue()
315{
316 if (!m_decoderResult.value.hasValue())
317 {
318 throw JsonParserException("JsonTokenizer:")
319 << m_lineNumber << ":" << m_tokenColumnNumber << ": "
320 << (m_decoderResult.integerOverflow ? "Value is outside of the 64-bit integer range!"
321 : "Unknown token!");
322 }
323
324 setToken(JsonToken::VALUE, std::move(m_decoderResult.value));
325 setPosition(m_pos + m_decoderResult.numReadChars, m_columnNumber + m_decoderResult.numReadChars);
326}
327
328} // namespace zserio
329
330#endif // ZSERIO_JSON_TOKENIZER_H_INC
JsonToken getToken() const
const BasicAny< ALLOC > & getValue() const
BasicJsonTokenizer(std::istream &in, const ALLOC &allocator)
CppRuntimeException(const char *message="")
CppRuntimeException & operator<<(CppRuntimeException &exception, const BasicBitBuffer< ALLOC > &bitBuffer)
Definition BitBuffer.h:554