#include <jsoncons_ext/cbor/cbor_cursor.hpp>
template<
typename Source=jsoncons::binary_stream_source,
typename Allocator=std::allocator<char>>
class basic_cbor_cursor;A pull parser for reporting CBOR parse events. A typical application will
repeatedly process the current() event and call the next()
function to advance to the next event, until done() returns true.
In addition, when positioned on a begin_object event,
the read_to function can pull a complete object representing
the events from begin_object to end_object,
and when positioned on a begin_array event, a complete array
representing the events from begin_array ro end_array.
basic_cbor_cursor is noncopyable and nonmoveable.
Aliases for common sources are provided:
| Type | Definition |
|---|---|
| cbor_stream_cursor | basic_cbor_cursorjsoncons::binary_stream_source |
| cbor_bytes_cursor | basic_cbor_cursorjsoncons::bytes_source |
basic_cbor_cursor(Sourceable&& source,
const cbor_decode_options& options = cbor_decode_options(), (1)
const Allocator& alloc = Allocator());
template <typename Sourceable>
basic_cbor_cursor(Sourceable&& source, std::error_code& ec); (2)
template <typename Sourceable>
basic_cbor_cursor(Sourceable&& source, (3)
const cbor_decode_options& options,
std::error_code& ec);
template <typename Sourceable>
basic_cbor_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source, (4)
const cbor_decode_options& options,
std::error_code& ec);
Constructors (1) reads from a buffer or stream source and throws a ser_error if a parsing error is encountered while processing the initial event.
Constructors (2)-(4) read from a buffer or stream source and set ec
if a parsing error is encountered while processing the initial event.
Note: It is the programmer's responsibility to ensure that basic_cbor_cursor does not outlive any source passed in the constuctor,
as basic_cbor_cursor holds a pointer to but does not own this object.
source - a value from which a source_type is constructible.
bool done() const final;
Check if there are no more events.
void next() final;
Get the next event. If a parsing error is encountered, throws a ser_error.
void next(std::error_code& ec) final;
Get the next event. If a parsing error is encountered, sets ec.
const staj_event& current() const final;
Returns the current staj_event.
void read_to(json_visitor& visitor) final;
Sends the parse events from the current event to the
matching completion event to the supplied visitor
E.g., if the current event is begin_object, sends the begin_object
event and all inbetween events until the matching end_object event.
If a parsing error is encountered, throws a ser_error.
void read_to(json_visitor& visitor, std::error_code& ec) final;
Sends the parse events from the current event to the
matching completion event to the supplied visitor
E.g., if the current event is begin_object, sends the begin_object
event and all inbetween events until the matching end_object event.
If a parsing error is encountered, sets ec.
bool is_typed_array() const final; (since 1.8.0)
typed_array_tags array_tag() const final; (since 1.8.0)
Returns a tag that indicates the element type of the typed array.
jsoncons::span<uint8_t> array_buffer() final; (since 1.8.0)
void to_end_array() final; (since 1.8.0)
bool is_multi_dim() const final; (since 1.8.0)
Indicates whether an array is a multi-dimensional array.
jsoncons::span<const std::size_t> extents() const final; (since 1.8.0)
Indicates the number of elements along each dimension of the array.
mdarray_order order() const final; (since 1.8.0)
Indicates whether the elements of a multi-dimensional array are arranged in row-major or column-major order. Returns a mdarray_order.
const ser_context& context() const final;
Returns the current context
void reset();
Reset cursor to read another value from the same source
template <typename Sourceable>
reset(Sourceable&& source)
Reset cursor to read new value from a new source
uint64_t raw_tag() const; (since 1.2.0)
Returns the CBOR tag associated with the current value
Inherited from jsoncons::basic_staj_cursor
template <typename T> (since 1.8.0)
void read_typed_array(T& v);
template <typename Source,typename Allocator>
staj_filter_view operator|(basic_cbor_cursor<Source,Allocator>& cursor,
std::function<bool(const staj_event&, const ser_context&)> pred);
Read CBOR parse events
Filter CBOR parse events
Typed array examples (until 1.8.0)
Typed array examples (since 1.8.0)
Read non-string keys (since 1.9.0)
Input JSON file book_catalog.json:
[
{
"author" : "Haruki Murakami",
"title" : "Hard-Boiled Wonderland and the End of the World",
"isbn" : "0679743464",
"publisher" : "Vintage",
"date" : "1993-03-02",
"price": 18.90
},
{
"author" : "Graham Greene",
"title" : "The Comedians",
"isbn" : "0099478374",
"publisher" : "Vintage Classics",
"date" : "2005-09-21",
"price": 15.74
}
]#include <jsoncons_ext/cbor/cbor_cursor.hpp>
#include <string>
#include <fstream>
using namespace jsoncons;
int main()
{
std::ifstream is("book_catalog.json");
cbor_cursor cursor(is);
for (; !cursor.done(); cursor.next())
{
const auto& event = cursor.current();
switch (event.event_type())
{
case staj_event_type::begin_array:
std::cout << event.event_type() << "\n";
break;
case staj_event_type::end_array:
std::cout << event.event_type() << "\n";
break;
case staj_event_type::begin_object:
std::cout << event.event_type() << "\n";
break;
case staj_event_type::end_object:
std::cout << event.event_type() << "\n";
break;
case staj_event_type::key:
// Or std::string_view, if supported
std::cout << event.event_type() << ": " << event.get<jsoncons::string_view>() << "\n";
break;
case staj_event_type::string_value:
// Or std::string_view, if supported
std::cout << event.event_type() << ": " << event.get<jsoncons::string_view>() << "\n";
break;
case staj_event_type::null_value:
std::cout << event.event_type() << ": " << "\n";
break;
case staj_event_type::bool_value:
std::cout << event.event_type() << ": " << std::boolalpha << event.get<bool>() << "\n";
break;
case staj_event_type::int64_value:
std::cout << event.event_type() << ": " << event.get<int64_t>() << "\n";
break;
case staj_event_type::uint64_value:
std::cout << event.event_type() << ": " << event.get<uint64_t>() << "\n";
break;
case staj_event_type::half_value:
case staj_event_type::double_value:
std::cout << event.event_type() << ": " << event.get<double>() << "\n";
break;
default:
std::cout << "Unhandled event type\n";
break;
}
}
}Output:
begin_array
begin_object
key: author
string_value: Haruki Murakami
key: title
string_value: Hard-Boiled Wonderland and the End of the World
key: isbn
string_value: 0679743464
key: publisher
string_value: Vintage
key: date
string_value: 1993-03-02
key: price
double_value: 19
end_object
begin_object
key: author
string_value: Graham Greene
key: title
string_value: The Comedians
key: isbn
string_value: 0099478374
key: publisher
string_value: Vintage Classics
key: date
string_value: 2005-09-21
key: price
double_value: 16
end_object
end_array
#include <jsoncons_ext/cbor/cbor_cursor.hpp>
#include <string>
#include <fstream>
using namespace jsoncons;
int main()
{
bool author_next = false;
auto filter = [&](const staj_event& event, const ser_context&) -> bool
{
if (event.event_type() == staj_event_type::key &&
event.get<jsoncons::string_view>() == "author")
{
author_next = true;
return false;
}
if (author_next)
{
author_next = false;
return true;
}
return false;
};
std::ifstream is("book_catalog.json");
cbor_cursor cursor(is);
auto filtered_c = cursor | filter;
for (; !filtered_c.done(); filtered_c.next())
{
const auto& event = filtered_c.current();
switch (event.event_type())
{
case staj_event_type::string_value:
std::cout << event.get<jsoncons::string_view>() << "\n";
break;
}
}
}Output:
Haruki Murakami
Graham Greene
#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <iostream>
#include <cassert>
namespace cbor = jsoncons::cbor;
struct my_cbor_visitor : public jsoncons::default_json_visitor
{
std::vector<double> v;
private:
bool visit_typed_array(const jsoncons::span<const double>&data,
jsoncons::semantic_tag,
const jsoncons::ser_context&,
std::error_code&) override
{
v = std::vector<double>(data.begin(), data.end());
return false;
}
};
int main()
{
std::vector<uint8_t> data = {
0xd8, // Tag
0x56, // Tag 86, float64, little endian, typed array
0x58, 0x20, // Byte string value of length 32
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40
};
cbor::cbor_bytes_cursor cursor(data);
//assert(jsoncons::staj_event_type::begin_array == cursor.current().event_type());
assert(jsoncons::staj_events::begin_array == cursor.current().event_type()); // (since 1.7.0)
assert(cursor.is_typed_array());
my_cbor_visitor visitor;
cursor.read_to(visitor);
for (auto item : visitor.v)
{
std::cout << item << "\n";
}
std::cout << "\n";
}Output:
10
20
30
40
This example is taken from CBOR Tags for Typed Arrays
#include <jsoncons_ext/cbor/cbor_cursor.hpp>
int main()
{
const std::vector<uint8_t> input = {
0xd8,0x28, // Tag 40 (multi-dimensional row-major array)
0x82, // array(2)
0x82, // array(2)
0x02, // unsigned(2) 1st Dimension
0x03, // unsigned(3) 2nd Dimension
0xd8,0x41, // Tag 65 (uint16 big endian typed array)
0x4c, // byte string(12)
0x00,0x02, // unsigned(2)
0x00,0x04, // unsigned(4)
0x00,0x08, // unsigned(8)
0x00,0x04, // unsigned(4)
0x00,0x10, // unsigned(16)
0x01,0x00 // unsigned(256)
};
cbor::cbor_bytes_cursor cursor(input);
for (; !cursor.done(); cursor.next())
{
const auto& event = cursor.current();
switch (event.event_type())
{
case staj_event_type::begin_array:
std::cout << event.event_type()
<< " " << "(" << event.tag() << ")\n";
break;
case staj_event_type::end_array:
std::cout << event.event_type()
<< " " << "(" << event.tag() << ")\n";
break;
case staj_event_type::uint64_value:
std::cout << event.event_type()
<< ": " << event.get<uint64_t>() << " " << "(" << event.tag() << ")\n";
break;
default:
std::cout << "Unhandled event type " << event.event_type()
<< " " << "(" << event.tag() << ")\n";
break;
}
}
}Output:
begin_array (multi-dim-row-major)
begin_array (n/a)
uint64_value: 2 (n/a)
uint64_value: 3 (n/a)
end_array (n/a)
begin_array (n/a)
uint64_value: 2 (n/a)
uint64_value: 4 (n/a)
uint64_value: 8 (n/a)
uint64_value: 4 (n/a)
uint64_value: 10 (n/a)
uint64_value: 100 (n/a)
end_array (n/a)
end_array (n/a)
This example is taken from CBOR Tags for Typed Arrays
#include <jsoncons_ext/cbor/cbor_cursor.hpp>
int main()
{
const std::vector<uint8_t> input = {
0xd9,0x04,0x10, // Tag 1040 (multi-dimensional column-major array)
0x82, // array(2)
0x82, // array(2)
0x02, // unsigned(2) 1st Dimension
0x03, // unsigned(3) 2nd Dimension
0x86, // array(6)
0x02, // unsigned(2)
0x04, // unsigned(4)
0x08, // unsigned(8)
0x04, // unsigned(4)
0x10, // unsigned(16)
0x19,0x01,0x00 // unsigned(256)
};
cbor::cbor_bytes_cursor cursor(input);
for (; !cursor.done(); cursor.next())
{
const auto& event = cursor.current();
switch (event.event_type())
{
case staj_event_type::begin_array:
std::cout << event.event_type()
<< " " << "(" << event.tag() << ")\n";
break;
case staj_event_type::end_array:
std::cout << event.event_type()
<< " " << "(" << event.tag() << ")\n";
break;
case staj_event_type::uint64_value:
std::cout << event.event_type()
<< ": " << event.get<uint64_t>() << " " << "(" << event.tag() << ")\n";
break;
default:
std::cout << "Unhandled event type " << event.event_type()
<< " " << "(" << event.tag() << ")\n";
break;
}
}
}Output:
begin_array (multi-dim-column-major)
begin_array (n/a)
uint64_value: 2 (n/a)
uint64_value: 3 (n/a)
end_array (n/a)
begin_array (n/a)
uint64_value: 2 (n/a)
uint64_value: 4 (n/a)
uint64_value: 8 (n/a)
uint64_value: 4 (n/a)
uint64_value: 10 (n/a)
uint64_value: 100 (n/a)
end_array (n/a)
end_array (n/a)
#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <iostream>
#include <cassert>
namespace cbor = jsoncons::cbor;
int main()
{
std::vector<uint8_t> data = {
0xd8, // Tag
0x56, // Tag 86, float64, little endian, Typed Array
0x58, 0x20, // Byte string value of length 32
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40
};
cbor::cbor_bytes_cursor cursor(data);
assert(jsoncons::staj_events::begin_array == cursor.current().event_type());
assert(cursor.is_typed_array());
std::vector<double> v;
cursor.read_typed_array(v);
assert(jsoncons::staj_events::end_array == cursor.current().event_type());
std::cout << "[";
for (std::size_t i = 0; i < v.size(); ++i)
{
if (i > 0) std::cout << ',';
std::cout << v[i];
}
std::cout << "]\n\n";
cursor.next();
assert(cursor.done());
}Output:
[10,20,30,40]
#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <iostream>
#include <cassert>
namespace cbor = jsoncons::cbor;
int main()
{
// A 3D typed array 2 x 3 x 2 with row-major storage
std::vector<uint8_t> data = {
0xD8, 0x28, // tag(40) row-major storage
0x82, // array(2)
0x83, // shape array(3)
0x02, 0x03, 0x02, // [2, 3, 2]
0xD8, 0x40, // tag(64) uint8 typed array
0x4C, // bytes(12)
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C
};
cbor::cbor_bytes_cursor cursor(data);
assert(jsoncons::staj_events::begin_array == cursor.current().event_type());
assert(true == cursor.is_multi_dim());
assert(jsoncons::mdarray_order::row_major == cursor.order());
assert(true == cursor.is_typed_array());
assert(jsoncons::typed_array_tags::uint8 == cursor.array_tag());
auto extents = cursor.extents();
std::cout << "(1) ";
for (std::size_t i = 0; i < extents.size(); ++i)
{
if (i > 0) std::cout << " x ";
std::cout << extents[i];
}
std::cout << "\n\n";
std::vector<int> v;
cursor.read_typed_array(v);
std::cout << "(2) [";
for (std::size_t i = 0; i < v.size(); ++i)
{
if (i > 0) std::cout << ',';
std::cout << v[i];
}
std::cout << "]\n\n";
assert(jsoncons::staj_events::end_array == cursor.current().event_type());
cursor.next();
assert(cursor.done());
}Output:
(1) 2 x 3 x 2
(2) [1,2,3,4,5,6,7,8,9,10,11,12]
#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <iostream>
#include <cassert>
namespace cbor = jsoncons::cbor;
int main()
{
// A 3D typed array 2 x 3 x 2 with column-major storage
std::vector<uint8_t> data = {
0xD9, 0x04, 0x10, // tag(1040) column-major storage
0x82, // array(2)
0x83, // shape array(3)
0x02, 0x03, 0x02, // [2, 3, 2]
0xD8, 0x40, // tag(64) uint8 typed array
0x4C, // bytes(12)
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C
};
cbor::cbor_bytes_cursor cursor(data);
assert(jsoncons::staj_events::begin_array == cursor.current().event_type());
assert(true == cursor.is_multi_dim());
assert(jsoncons::mdarray_order::column_major == cursor.order());
assert(true == cursor.is_typed_array());
assert(jsoncons::typed_array_tags::uint8 == cursor.array_tag());
auto extents = cursor.extents();
std::cout << "(1) ";
for (std::size_t i = 0; i < extents.size(); ++i)
{
if (i > 0) std::cout << " x ";
std::cout << extents[i];
}
std::cout << "\n\n";
std::vector<int> v;
cursor.read_typed_array(v);
std::cout << "(2) [";
for (std::size_t i = 0; i < v.size(); ++i)
{
if (i > 0) std::cout << ',';
std::cout << v[i];
}
std::cout << "]\n\n";
assert(jsoncons::staj_events::end_array == cursor.current().event_type());
cursor.next();
assert(cursor.done());
}Output:
(1) 2 x 3 x 2
(2) [1,2,3,4,5,6,7,8,9,10,11,12]
#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <iostream>
#include <cassert>
namespace cbor = jsoncons::cbor;
int main()
{
// A 3D classical array 2 x 3 x 2 with row-major storage
std::vector<uint8_t> data = {
0xD8, 0x28, // tag(40) row-major storage
0x82, // array(2)
0x83, // shape array(3)
0x02, 0x03, 0x02, // [2, 3, 2]
0x8C, // data array(12)
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C
};
cbor::cbor_bytes_cursor cursor(data);
assert(jsoncons::staj_events::begin_array == cursor.current().event_type());
assert(true == cursor.is_multi_dim());
assert(jsoncons::mdarray_order::row_major == cursor.order());
assert(false == cursor.is_typed_array());
auto extents = cursor.extents();
std::cout << "(1) ";
for (std::size_t i = 0; i < extents.size(); ++i)
{
if (i > 0) std::cout << " x ";
std::cout << extents[i];
}
std::cout << "\n\n";
jsoncons::json_decoder<jsoncons::json> sub_decoder;
cursor.read_to(sub_decoder);
assert(sub_decoder.is_valid());
auto jval = sub_decoder.get_result();
assert(jval.is_array());
std::cout << "(2) [";
for (std::size_t i = 0; i < jval.size(); ++i)
{
if (i > 0) std::cout << ',';
std::cout << jval[i];
}
std::cout << "]\n\n";
assert(jsoncons::staj_events::end_array == cursor.current().event_type());
cursor.next();
assert(cursor.done());
}Output:
(1) 2 x 3 x 2
(2) [1,2,3,4,5,6,7,8,9,10,11,12]
#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <iostream>
#include <cassert>
namespace cbor = jsoncons::cbor;
int main()
{
// A 3D classical array 2 x 3 x 2 with row-major storage
std::vector<uint8_t> data = {
0xD9, 0x04, 0x10, // tag(1040) column-major storage
0x82, // array(2)
0x83, // shape array(3)
0x02, 0x03, 0x02, // [2, 3, 2]
0x8C, // data array(12)
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C
};
cbor::cbor_bytes_cursor cursor(data);
assert(jsoncons::staj_events::begin_array == cursor.current().event_type());
assert(true == cursor.is_multi_dim());
assert(jsoncons::mdarray_order::column_major == cursor.order());
assert(false == cursor.is_typed_array());
auto extents = cursor.extents();
std::cout << "(1) ";
for (std::size_t i = 0; i < extents.size(); ++i)
{
if (i > 0) std::cout << " x ";
std::cout << extents[i];
}
std::cout << "\n\n";
jsoncons::json_decoder<jsoncons::json> sub_decoder;
cursor.read_to(sub_decoder);
assert(sub_decoder.is_valid());
auto jval = sub_decoder.get_result();
assert(jval.is_array());
std::cout << "(2) [";
for (std::size_t i = 0; i < jval.size(); ++i)
{
if (i > 0) std::cout << ',';
std::cout << jval[i];
}
std::cout << "]\n\n";
assert(jsoncons::staj_events::end_array == cursor.current().event_type());
cursor.next();
assert(cursor.done());
}Output:
(1) 2 x 3 x 2
(2) [1,2,3,4,5,6,7,8,9,10,11,12]
Since 1.9.0, jsoncons supports reading non-string keys using the cursor API.
Keys are reported by staj_events
that are ORed with the flag staj_events::key_flag.
For backwards compatibility, the enum value staj_events::key has been redefined as
staj_events::string_value | staj_events::key_flagIn addition, for the common case of CBOR or MessagePack unsigned integer keys,
the enum value id has been added to sjaj_events and defined as
staj_events::uint64_value | staj_events::key_flag`#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <iostream>
namespace cbor = jsoncons::cbor;
int main()
{
std::vector<uint8_t> data = {
0x82, // Array(2)
0xA2, // Map (2)
0x01, // Key 1
0x63, 0x6F, 0x6E, 0x65, // Text "one"
0x02, // Key 2
0x63, 0x74, 0x77, 0x6F, // Text "two"
0xA2, // Map(2)
0x0A, // Key 10
0x67, 0x68, 0x75, 0x6E,
0x64, 0x72, 0x65, 0x64, // Value "hundred"
0x14, // Key 20
0x6B, 0x74, 0x77, 0x6F, 0x20, 0x68,
0x75, 0x6E, 0x64, 0x72, 0x65, 0x64 // Value "two hundred"
};
cbor::cbor_bytes_cursor cursor{data};
while (!cursor.done())
{
switch (cursor.current().event_type())
{
case jsoncons::staj_events::begin_array:
std::cout << "begin array\n";
break;
case jsoncons::staj_events::end_array:
std::cout << "end array\n";
break;
case jsoncons::staj_events::begin_object:
std::cout << " begin object\n";
break;
case jsoncons::staj_events::end_object:
std::cout << " end object\n";
break;
case jsoncons::staj_events::string_value:
std::cout << " value: " << cursor.current().get<std::string>() << "\n";
break;
case jsoncons::staj_events::id:
std::cout << " key: " << cursor.current().get<uint64_t>() << "\n";
break;
}
cursor.next();
}
}Output:
begin array
begin object
key: 1
value: one
key: 2
value: two
end object
begin object
key: 10
value: hundred
key: 20
value: two hundred
end object
end array