1//     __ _____ _____ _____
2//  __|  |   __|     |   | |  JSON for Modern C++
3// |  |  |__   |  |  | | | |  version 3.11.2
4// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9#pragma once
10
11#include <array> // array
12#include <cstddef> // size_t
13#include <cstring> // strlen
14#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
15#include <memory> // shared_ptr, make_shared, addressof
16#include <numeric> // accumulate
17#include <string> // string, char_traits
18#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
19#include <utility> // pair, declval
20
21#ifndef JSON_NO_IO
22    #include <cstdio>   // FILE *
23    #include <istream>  // istream
24#endif                  // JSON_NO_IO
25
26#include <nlohmann/detail/iterators/iterator_traits.hpp>
27#include <nlohmann/detail/macro_scope.hpp>
28
29NLOHMANN_JSON_NAMESPACE_BEGIN
30namespace detail
31{
32
33/// the supported input formats
34enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata };
35
36////////////////////
37// input adapters //
38////////////////////
39
40#ifndef JSON_NO_IO
41/*!
42Input adapter for stdio file access. This adapter read only 1 byte and do not use any
43 buffer. This adapter is a very low level adapter.
44*/
45class file_input_adapter
46{
47  public:
48    using char_type = char;
49
50    JSON_HEDLEY_NON_NULL(2)
51    explicit file_input_adapter(std::FILE* f) noexcept
52        : m_file(f)
53    {
54        JSON_ASSERT(m_file != nullptr);
55    }
56
57    // make class move-only
58    file_input_adapter(const file_input_adapter&) = delete;
59    file_input_adapter(file_input_adapter&&) noexcept = default;
60    file_input_adapter& operator=(const file_input_adapter&) = delete;
61    file_input_adapter& operator=(file_input_adapter&&) = delete;
62    ~file_input_adapter() = default;
63
64    std::char_traits<char>::int_type get_character() noexcept
65    {
66        return std::fgetc(m_file);
67    }
68
69  private:
70    /// the file pointer to read from
71    std::FILE* m_file;
72};
73
74
75/*!
76Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
77beginning of input. Does not support changing the underlying std::streambuf
78in mid-input. Maintains underlying std::istream and std::streambuf to support
79subsequent use of standard std::istream operations to process any input
80characters following those used in parsing the JSON input.  Clears the
81std::istream flags; any input errors (e.g., EOF) will be detected by the first
82subsequent call for input from the std::istream.
83*/
84class input_stream_adapter
85{
86  public:
87    using char_type = char;
88
89    ~input_stream_adapter()
90    {
91        // clear stream flags; we use underlying streambuf I/O, do not
92        // maintain ifstream flags, except eof
93        if (is != nullptr)
94        {
95            is->clear(is->rdstate() & std::ios::eofbit);
96        }
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& operator=(input_stream_adapter&&) = delete;
107
108    input_stream_adapter(input_stream_adapter&& rhs) noexcept
109        : is(rhs.is), sb(rhs.sb)
110    {
111        rhs.is = nullptr;
112        rhs.sb = nullptr;
113    }
114
115    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
116    // ensure that std::char_traits<char>::eof() and the character 0xFF do not
117    // end up as the same value, e.g. 0xFFFFFFFF.
118    std::char_traits<char>::int_type get_character()
119    {
120        auto res = sb->sbumpc();
121        // set eof manually, as we don't use the istream interface.
122        if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
123        {
124            is->clear(is->rdstate() | std::ios::eofbit);
125        }
126        return res;
127    }
128
129  private:
130    /// the associated input stream
131    std::istream* is = nullptr;
132    std::streambuf* sb = nullptr;
133};
134#endif  // JSON_NO_IO
135
136// General-purpose iterator-based adapter. It might not be as fast as
137// theoretically possible for some containers, but it is extremely versatile.
138template<typename IteratorType>
139class iterator_input_adapter
140{
141  public:
142    using char_type = typename std::iterator_traits<IteratorType>::value_type;
143
144    iterator_input_adapter(IteratorType first, IteratorType last)
145        : current(std::move(first)), end(std::move(last))
146    {}
147
148    typename std::char_traits<char_type>::int_type get_character()
149    {
150        if (JSON_HEDLEY_LIKELY(current != end))
151        {
152            auto result = std::char_traits<char_type>::to_int_type(*current);
153            std::advance(current, 1);
154            return result;
155        }
156
157        return std::char_traits<char_type>::eof();
158    }
159
160  private:
161    IteratorType current;
162    IteratorType end;
163
164    template<typename BaseInputAdapter, size_t T>
165    friend struct wide_string_input_helper;
166
167    bool empty() const
168    {
169        return current == end;
170    }
171};
172
173
174template<typename BaseInputAdapter, size_t T>
175struct wide_string_input_helper;
176
177template<typename BaseInputAdapter>
178struct wide_string_input_helper<BaseInputAdapter, 4>
179{
180    // UTF-32
181    static void fill_buffer(BaseInputAdapter& input,
182                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
183                            size_t& utf8_bytes_index,
184                            size_t& utf8_bytes_filled)
185    {
186        utf8_bytes_index = 0;
187
188        if (JSON_HEDLEY_UNLIKELY(input.empty()))
189        {
190            utf8_bytes[0] = std::char_traits<char>::eof();
191            utf8_bytes_filled = 1;
192        }
193        else
194        {
195            // get the current character
196            const auto wc = input.get_character();
197
198            // UTF-32 to UTF-8 encoding
199            if (wc < 0x80)
200            {
201                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
202                utf8_bytes_filled = 1;
203            }
204            else if (wc <= 0x7FF)
205            {
206                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));
207                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
208                utf8_bytes_filled = 2;
209            }
210            else if (wc <= 0xFFFF)
211            {
212                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));
213                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
214                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
215                utf8_bytes_filled = 3;
216            }
217            else if (wc <= 0x10FFFF)
218            {
219                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));
220                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));
221                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
222                utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
223                utf8_bytes_filled = 4;
224            }
225            else
226            {
227                // unknown character
228                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
229                utf8_bytes_filled = 1;
230            }
231        }
232    }
233};
234
235template<typename BaseInputAdapter>
236struct wide_string_input_helper<BaseInputAdapter, 2>
237{
238    // UTF-16
239    static void fill_buffer(BaseInputAdapter& input,
240                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
241                            size_t& utf8_bytes_index,
242                            size_t& utf8_bytes_filled)
243    {
244        utf8_bytes_index = 0;
245
246        if (JSON_HEDLEY_UNLIKELY(input.empty()))
247        {
248            utf8_bytes[0] = std::char_traits<char>::eof();
249            utf8_bytes_filled = 1;
250        }
251        else
252        {
253            // get the current character
254            const auto wc = input.get_character();
255
256            // UTF-16 to UTF-8 encoding
257            if (wc < 0x80)
258            {
259                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
260                utf8_bytes_filled = 1;
261            }
262            else if (wc <= 0x7FF)
263            {
264                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));
265                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
266                utf8_bytes_filled = 2;
267            }
268            else if (0xD800 > wc || wc >= 0xE000)
269            {
270                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
271                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
272                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
273                utf8_bytes_filled = 3;
274            }
275            else
276            {
277                if (JSON_HEDLEY_UNLIKELY(!input.empty()))
278                {
279                    const auto wc2 = static_cast<unsigned int>(input.get_character());
280                    const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
281                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
282                    utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
283                    utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
284                    utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
285                    utf8_bytes_filled = 4;
286                }
287                else
288                {
289                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
290                    utf8_bytes_filled = 1;
291                }
292            }
293        }
294    }
295};
296
297// Wraps another input apdater to convert wide character types into individual bytes.
298template<typename BaseInputAdapter, typename WideCharType>
299class wide_string_input_adapter
300{
301  public:
302    using char_type = char;
303
304    wide_string_input_adapter(BaseInputAdapter base)
305        : base_adapter(base) {}
306
307    typename std::char_traits<char>::int_type get_character() noexcept
308    {
309        // check if buffer needs to be filled
310        if (utf8_bytes_index == utf8_bytes_filled)
311        {
312            fill_buffer<sizeof(WideCharType)>();
313
314            JSON_ASSERT(utf8_bytes_filled > 0);
315            JSON_ASSERT(utf8_bytes_index == 0);
316        }
317
318        // use buffer
319        JSON_ASSERT(utf8_bytes_filled > 0);
320        JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
321        return utf8_bytes[utf8_bytes_index++];
322    }
323
324  private:
325    BaseInputAdapter base_adapter;
326
327    template<size_t T>
328    void fill_buffer()
329    {
330        wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
331    }
332
333    /// a buffer for UTF-8 bytes
334    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
335
336    /// index to the utf8_codes array for the next valid byte
337    std::size_t utf8_bytes_index = 0;
338    /// number of valid bytes in the utf8_codes array
339    std::size_t utf8_bytes_filled = 0;
340};
341
342
343template<typename IteratorType, typename Enable = void>
344struct iterator_input_adapter_factory
345{
346    using iterator_type = IteratorType;
347    using char_type = typename std::iterator_traits<iterator_type>::value_type;
348    using adapter_type = iterator_input_adapter<iterator_type>;
349
350    static adapter_type create(IteratorType first, IteratorType last)
351    {
352        return adapter_type(std::move(first), std::move(last));
353    }
354};
355
356template<typename T>
357struct is_iterator_of_multibyte
358{
359    using value_type = typename std::iterator_traits<T>::value_type;
360    enum
361    {
362        value = sizeof(value_type) > 1
363    };
364};
365
366template<typename IteratorType>
367struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
368{
369    using iterator_type = IteratorType;
370    using char_type = typename std::iterator_traits<iterator_type>::value_type;
371    using base_adapter_type = iterator_input_adapter<iterator_type>;
372    using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
373
374    static adapter_type create(IteratorType first, IteratorType last)
375    {
376        return adapter_type(base_adapter_type(std::move(first), std::move(last)));
377    }
378};
379
380// General purpose iterator-based input
381template<typename IteratorType>
382typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
383{
384    using factory_type = iterator_input_adapter_factory<IteratorType>;
385    return factory_type::create(first, last);
386}
387
388// Convenience shorthand from container to iterator
389// Enables ADL on begin(container) and end(container)
390// Encloses the using declarations in namespace for not to leak them to outside scope
391
392namespace container_input_adapter_factory_impl
393{
394
395using std::begin;
396using std::end;
397
398template<typename ContainerType, typename Enable = void>
399struct container_input_adapter_factory {};
400
401template<typename ContainerType>
402struct container_input_adapter_factory< ContainerType,
403       void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
404       {
405           using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
406
407           static adapter_type create(const ContainerType& container)
408{
409    return input_adapter(begin(container), end(container));
410}
411       };
412
413}  // namespace container_input_adapter_factory_impl
414
415template<typename ContainerType>
416typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
417{
418    return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
419}
420
421#ifndef JSON_NO_IO
422// Special cases with fast paths
423inline file_input_adapter input_adapter(std::FILE* file)
424{
425    return file_input_adapter(file);
426}
427
428inline input_stream_adapter input_adapter(std::istream& stream)
429{
430    return input_stream_adapter(stream);
431}
432
433inline input_stream_adapter input_adapter(std::istream&& stream)
434{
435    return input_stream_adapter(stream);
436}
437#endif  // JSON_NO_IO
438
439using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
440
441// Null-delimited strings, and the like.
442template < typename CharT,
443           typename std::enable_if <
444               std::is_pointer<CharT>::value&&
445               !std::is_array<CharT>::value&&
446               std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
447               sizeof(typename std::remove_pointer<CharT>::type) == 1,
448               int >::type = 0 >
449contiguous_bytes_input_adapter input_adapter(CharT b)
450{
451    auto length = std::strlen(reinterpret_cast<const char*>(b));
452    const auto* ptr = reinterpret_cast<const char*>(b);
453    return input_adapter(ptr, ptr + length);
454}
455
456template<typename T, std::size_t N>
457auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
458{
459    return input_adapter(array, array + N);
460}
461
462// This class only handles inputs of input_buffer_adapter type.
463// It's required so that expressions like {ptr, len} can be implicitly cast
464// to the correct adapter.
465class span_input_adapter
466{
467  public:
468    template < typename CharT,
469               typename std::enable_if <
470                   std::is_pointer<CharT>::value&&
471                   std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
472                   sizeof(typename std::remove_pointer<CharT>::type) == 1,
473                   int >::type = 0 >
474    span_input_adapter(CharT b, std::size_t l)
475        : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}
476
477    template<class IteratorType,
478             typename std::enable_if<
479                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
480                 int>::type = 0>
481    span_input_adapter(IteratorType first, IteratorType last)
482        : ia(input_adapter(first, last)) {}
483
484    contiguous_bytes_input_adapter&& get()
485    {
486        return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
487    }
488
489  private:
490    contiguous_bytes_input_adapter ia;
491};
492
493}  // namespace detail
494NLOHMANN_JSON_NAMESPACE_END
495