Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #include <array> // array
4 : : #include <cassert> // assert
5 : : #include <cstddef> // size_t
6 : : #include <cstdio> //FILE *
7 : : #include <cstring> // strlen
8 : : #include <istream> // istream
9 : : #include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
10 : : #include <memory> // shared_ptr, make_shared, addressof
11 : : #include <numeric> // accumulate
12 : : #include <string> // string, char_traits
13 : : #include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
14 : : #include <utility> // pair, declval
15 : :
16 : : #include <nlohmann/detail/iterators/iterator_traits.hpp>
17 : : #include <nlohmann/detail/macro_scope.hpp>
18 : :
19 : : namespace nlohmann
20 : : {
21 : : namespace detail
22 : : {
23 : : /// the supported input formats
24 : : enum class input_format_t { json, cbor, msgpack, ubjson, bson };
25 : :
26 : : ////////////////////
27 : : // input adapters //
28 : : ////////////////////
29 : :
30 : : /*!
31 : : @brief abstract input adapter interface
32 : :
33 : : Produces a stream of std::char_traits<char>::int_type characters from a
34 : : std::istream, a buffer, or some other input type. Accepts the return of
35 : : exactly one non-EOF character for future input. The int_type characters
36 : : returned consist of all valid char values as positive values (typically
37 : : unsigned char), plus an EOF value outside that range, specified by the value
38 : : of the function std::char_traits<char>::eof(). This value is typically -1, but
39 : : could be any arbitrary value which is not a valid char value.
40 : : */
41 : 0 : struct input_adapter_protocol
42 : : {
43 : : /// get a character [0,255] or std::char_traits<char>::eof().
44 : : virtual std::char_traits<char>::int_type get_character() = 0;
45 : 0 : virtual ~input_adapter_protocol() = default;
46 : : };
47 : :
48 : : /// a type to simplify interfaces
49 : : using input_adapter_t = std::shared_ptr<input_adapter_protocol>;
50 : :
51 : : /*!
52 : : Input adapter for stdio file access. This adapter read only 1 byte and do not use any
53 : : buffer. This adapter is a very low level adapter.
54 : : */
55 : : class file_input_adapter : public input_adapter_protocol
56 : : {
57 : : public:
58 : : explicit file_input_adapter(std::FILE* f) noexcept
59 : : : m_file(f)
60 : : {}
61 : :
62 : : // make class move-only
63 : : file_input_adapter(const file_input_adapter&) = delete;
64 : : file_input_adapter(file_input_adapter&&) = default;
65 : : file_input_adapter& operator=(const file_input_adapter&) = delete;
66 : : file_input_adapter& operator=(file_input_adapter&&) = default;
67 : : ~file_input_adapter() override = default;
68 : :
69 : : std::char_traits<char>::int_type get_character() noexcept override
70 : : {
71 : : return std::fgetc(m_file);
72 : : }
73 : :
74 : : private:
75 : : /// the file pointer to read from
76 : : std::FILE* m_file;
77 : : };
78 : :
79 : :
80 : : /*!
81 : : Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
82 : : beginning of input. Does not support changing the underlying std::streambuf
83 : : in mid-input. Maintains underlying std::istream and std::streambuf to support
84 : : subsequent use of standard std::istream operations to process any input
85 : : characters following those used in parsing the JSON input. Clears the
86 : : std::istream flags; any input errors (e.g., EOF) will be detected by the first
87 : : subsequent call for input from the std::istream.
88 : : */
89 : : class input_stream_adapter : public input_adapter_protocol
90 : : {
91 : : public:
92 : : ~input_stream_adapter() override
93 : : {
94 : : // clear stream flags; we use underlying streambuf I/O, do not
95 : : // maintain ifstream flags, except eof
96 : : is.clear(is.rdstate() & std::ios::eofbit);
97 : : }
98 : :
99 : : explicit input_stream_adapter(std::istream& i)
100 : : : is(i), sb(*i.rdbuf())
101 : : {}
102 : :
103 : : // delete because of pointer members
104 : : input_stream_adapter(const input_stream_adapter&) = delete;
105 : : input_stream_adapter& operator=(input_stream_adapter&) = delete;
106 : : input_stream_adapter(input_stream_adapter&&) = delete;
107 : : input_stream_adapter& operator=(input_stream_adapter&&) = delete;
108 : :
109 : : // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
110 : : // ensure that std::char_traits<char>::eof() and the character 0xFF do not
111 : : // end up as the same value, eg. 0xFFFFFFFF.
112 : : std::char_traits<char>::int_type get_character() override
113 : : {
114 : : auto res = sb.sbumpc();
115 : : // set eof manually, as we don't use the istream interface.
116 : : if (res == EOF)
117 : : {
118 : : is.clear(is.rdstate() | std::ios::eofbit);
119 : : }
120 : : return res;
121 : : }
122 : :
123 : : private:
124 : : /// the associated input stream
125 : : std::istream& is;
126 : : std::streambuf& sb;
127 : : };
128 : :
129 : : /// input adapter for buffer input
130 : : class input_buffer_adapter : public input_adapter_protocol
131 : : {
132 : : public:
133 : 0 : input_buffer_adapter(const char* b, const std::size_t l) noexcept
134 : 0 : : cursor(b), limit(b + l)
135 : 0 : {}
136 : :
137 : : // delete because of pointer members
138 : : input_buffer_adapter(const input_buffer_adapter&) = delete;
139 : : input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
140 : : input_buffer_adapter(input_buffer_adapter&&) = delete;
141 : : input_buffer_adapter& operator=(input_buffer_adapter&&) = delete;
142 : 0 : ~input_buffer_adapter() override = default;
143 : :
144 : 0 : std::char_traits<char>::int_type get_character() noexcept override
145 : : {
146 : 0 : if (JSON_LIKELY(cursor < limit))
147 : : {
148 : 0 : return std::char_traits<char>::to_int_type(*(cursor++));
149 : : }
150 : :
151 : 0 : return std::char_traits<char>::eof();
152 : 0 : }
153 : :
154 : : private:
155 : : /// pointer to the current character
156 : : const char* cursor;
157 : : /// pointer past the last character
158 : : const char* const limit;
159 : : };
160 : :
161 : : template<typename WideStringType, size_t T>
162 : : struct wide_string_input_helper
163 : : {
164 : : // UTF-32
165 : : static void fill_buffer(const WideStringType& str,
166 : : size_t& current_wchar,
167 : : std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
168 : : size_t& utf8_bytes_index,
169 : : size_t& utf8_bytes_filled)
170 : : {
171 : : utf8_bytes_index = 0;
172 : :
173 : : if (current_wchar == str.size())
174 : : {
175 : : utf8_bytes[0] = std::char_traits<char>::eof();
176 : : utf8_bytes_filled = 1;
177 : : }
178 : : else
179 : : {
180 : : // get the current character
181 : : const auto wc = static_cast<unsigned int>(str[current_wchar++]);
182 : :
183 : : // UTF-32 to UTF-8 encoding
184 : : if (wc < 0x80)
185 : : {
186 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
187 : : utf8_bytes_filled = 1;
188 : : }
189 : : else if (wc <= 0x7FF)
190 : : {
191 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u) & 0x1Fu));
192 : : utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
193 : : utf8_bytes_filled = 2;
194 : : }
195 : : else if (wc <= 0xFFFF)
196 : : {
197 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u) & 0x0Fu));
198 : : utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
199 : : utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
200 : : utf8_bytes_filled = 3;
201 : : }
202 : : else if (wc <= 0x10FFFF)
203 : : {
204 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((wc >> 18u) & 0x07u));
205 : : utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 12u) & 0x3Fu));
206 : : utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
207 : : utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
208 : : utf8_bytes_filled = 4;
209 : : }
210 : : else
211 : : {
212 : : // unknown character
213 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
214 : : utf8_bytes_filled = 1;
215 : : }
216 : : }
217 : : }
218 : : };
219 : :
220 : : template<typename WideStringType>
221 : : struct wide_string_input_helper<WideStringType, 2>
222 : : {
223 : : // UTF-16
224 : : static void fill_buffer(const WideStringType& str,
225 : : size_t& current_wchar,
226 : : std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
227 : : size_t& utf8_bytes_index,
228 : : size_t& utf8_bytes_filled)
229 : : {
230 : : utf8_bytes_index = 0;
231 : :
232 : : if (current_wchar == str.size())
233 : : {
234 : : utf8_bytes[0] = std::char_traits<char>::eof();
235 : : utf8_bytes_filled = 1;
236 : : }
237 : : else
238 : : {
239 : : // get the current character
240 : : const auto wc = static_cast<unsigned int>(str[current_wchar++]);
241 : :
242 : : // UTF-16 to UTF-8 encoding
243 : : if (wc < 0x80)
244 : : {
245 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
246 : : utf8_bytes_filled = 1;
247 : : }
248 : : else if (wc <= 0x7FF)
249 : : {
250 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u)));
251 : : utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
252 : : utf8_bytes_filled = 2;
253 : : }
254 : : else if (0xD800 > wc or wc >= 0xE000)
255 : : {
256 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u)));
257 : : utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
258 : : utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
259 : : utf8_bytes_filled = 3;
260 : : }
261 : : else
262 : : {
263 : : if (current_wchar < str.size())
264 : : {
265 : : const auto wc2 = static_cast<unsigned int>(str[current_wchar++]);
266 : : const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
267 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
268 : : utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
269 : : utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
270 : : utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
271 : : utf8_bytes_filled = 4;
272 : : }
273 : : else
274 : : {
275 : : // unknown character
276 : : ++current_wchar;
277 : : utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
278 : : utf8_bytes_filled = 1;
279 : : }
280 : : }
281 : : }
282 : : }
283 : : };
284 : :
285 : : template<typename WideStringType>
286 : : class wide_string_input_adapter : public input_adapter_protocol
287 : : {
288 : : public:
289 : : explicit wide_string_input_adapter(const WideStringType& w) noexcept
290 : : : str(w)
291 : : {}
292 : :
293 : : std::char_traits<char>::int_type get_character() noexcept override
294 : : {
295 : : // check if buffer needs to be filled
296 : : if (utf8_bytes_index == utf8_bytes_filled)
297 : : {
298 : : fill_buffer<sizeof(typename WideStringType::value_type)>();
299 : :
300 : : assert(utf8_bytes_filled > 0);
301 : : assert(utf8_bytes_index == 0);
302 : : }
303 : :
304 : : // use buffer
305 : : assert(utf8_bytes_filled > 0);
306 : : assert(utf8_bytes_index < utf8_bytes_filled);
307 : : return utf8_bytes[utf8_bytes_index++];
308 : : }
309 : :
310 : : private:
311 : : template<size_t T>
312 : : void fill_buffer()
313 : : {
314 : : wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
315 : : }
316 : :
317 : : /// the wstring to process
318 : : const WideStringType& str;
319 : :
320 : : /// index of the current wchar in str
321 : : std::size_t current_wchar = 0;
322 : :
323 : : /// a buffer for UTF-8 bytes
324 : : std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
325 : :
326 : : /// index to the utf8_codes array for the next valid byte
327 : : std::size_t utf8_bytes_index = 0;
328 : : /// number of valid bytes in the utf8_codes array
329 : : std::size_t utf8_bytes_filled = 0;
330 : : };
331 : :
332 : 0 : class input_adapter
333 : : {
334 : : public:
335 : : // native support
336 : : input_adapter(std::FILE* file)
337 : : : ia(std::make_shared<file_input_adapter>(file)) {}
338 : : /// input adapter for input stream
339 : : input_adapter(std::istream& i)
340 : : : ia(std::make_shared<input_stream_adapter>(i)) {}
341 : :
342 : : /// input adapter for input stream
343 : : input_adapter(std::istream&& i)
344 : : : ia(std::make_shared<input_stream_adapter>(i)) {}
345 : :
346 : : input_adapter(const std::wstring& ws)
347 : : : ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}
348 : :
349 : : input_adapter(const std::u16string& ws)
350 : : : ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}
351 : :
352 : : input_adapter(const std::u32string& ws)
353 : : : ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}
354 : :
355 : : /// input adapter for buffer
356 : : template<typename CharT,
357 : : typename std::enable_if<
358 : : std::is_pointer<CharT>::value and
359 : : std::is_integral<typename std::remove_pointer<CharT>::type>::value and
360 : : sizeof(typename std::remove_pointer<CharT>::type) == 1,
361 : : int>::type = 0>
362 : : input_adapter(CharT b, std::size_t l)
363 : : : ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}
364 : :
365 : : // derived support
366 : :
367 : : /// input adapter for string literal
368 : : template<typename CharT,
369 : : typename std::enable_if<
370 : : std::is_pointer<CharT>::value and
371 : : std::is_integral<typename std::remove_pointer<CharT>::type>::value and
372 : : sizeof(typename std::remove_pointer<CharT>::type) == 1,
373 : : int>::type = 0>
374 : : input_adapter(CharT b)
375 : : : input_adapter(reinterpret_cast<const char*>(b),
376 : : std::strlen(reinterpret_cast<const char*>(b))) {}
377 : :
378 : : /// input adapter for iterator range with contiguous storage
379 : : template<class IteratorType,
380 : : typename std::enable_if<
381 : : std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
382 : : int>::type = 0>
383 : 0 : input_adapter(IteratorType first, IteratorType last)
384 : : {
385 : : #ifndef NDEBUG
386 : : // assertion to check that the iterator range is indeed contiguous,
387 : : // see http://stackoverflow.com/a/35008842/266378 for more discussion
388 : 0 : const auto is_contiguous = std::accumulate(
389 : 0 : first, last, std::pair<bool, int>(true, 0),
390 : 0 : [&first](std::pair<bool, int> res, decltype(*first) val)
391 : : {
392 : 0 : res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
393 : 0 : return res;
394 : 0 : }).first;
395 : 0 : assert(is_contiguous);
396 : : #endif
397 : :
398 : : // assertion to check that each element is 1 byte long
399 : : static_assert(
400 : : sizeof(typename iterator_traits<IteratorType>::value_type) == 1,
401 : : "each element in the iterator range must have the size of 1 byte");
402 : :
403 : 0 : const auto len = static_cast<size_t>(std::distance(first, last));
404 : 0 : if (JSON_LIKELY(len > 0))
405 : : {
406 : : // there is at least one element: use the address of first
407 : 0 : ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
408 : 0 : }
409 : : else
410 : : {
411 : : // the address of first cannot be used: use nullptr
412 : 0 : ia = std::make_shared<input_buffer_adapter>(nullptr, len);
413 : : }
414 : 0 : }
415 : :
416 : : /// input adapter for array
417 : : template<class T, std::size_t N>
418 : : input_adapter(T (&array)[N])
419 : : : input_adapter(std::begin(array), std::end(array)) {}
420 : :
421 : : /// input adapter for contiguous container
422 : : template<class ContiguousContainer, typename
423 : : std::enable_if<not std::is_pointer<ContiguousContainer>::value and
424 : : std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
425 : : int>::type = 0>
426 : 0 : input_adapter(const ContiguousContainer& c)
427 : 0 : : input_adapter(std::begin(c), std::end(c)) {}
428 : :
429 : 0 : operator input_adapter_t()
430 : : {
431 : 0 : return ia;
432 : : }
433 : :
434 : : private:
435 : : /// the actual adapter
436 : 0 : input_adapter_t ia = nullptr;
437 : : };
438 : : } // namespace detail
439 : : } // namespace nlohmann
|