@@ -46,6 +46,18 @@ const char* Consume(std::vector<std::uint8_t>::const_iterator& byte_it,
4646 byte_it += num_bytes;
4747 return reinterpret_cast <const char *>(pos);
4848}
49+
50+ std::string Consume (std::vector<std::uint8_t >::const_iterator& byte_it,
51+ const std::ptrdiff_t num_bytes, const char * context) {
52+ const auto cstr = Consume (byte_it, num_bytes);
53+ // strnlen isn't portable
54+ const std::size_t str_len = std::find (cstr, cstr + num_bytes, ' \0 ' ) - cstr;
55+ if (str_len == num_bytes) {
56+ throw databento::DbnResponseError{std::string{" Invalid " } + context +
57+ " missing null terminator" };
58+ }
59+ return std::string{cstr, str_len};
60+ }
4961} // namespace
5062
5163DbnDecoder::DbnDecoder (detail::SharedChannel channel)
@@ -106,7 +118,7 @@ databento::Metadata DbnDecoder::DecodeMetadataFields(
106118 std::to_string (res.version )};
107119 }
108120 auto read_buffer_it = buffer.cbegin ();
109- res.dataset = std::string{ Consume (read_buffer_it, kDatasetCstrLen )} ;
121+ res.dataset = Consume (read_buffer_it, kDatasetCstrLen , " dataset " ) ;
110122 const auto raw_schema = Consume<std::uint16_t >(read_buffer_it);
111123 if (raw_schema == std::numeric_limits<std::uint16_t >::max ()) {
112124 res.has_mixed_schema = true ;
@@ -266,8 +278,8 @@ bool DbnDecoder::DetectCompression() {
266278std::string DbnDecoder::DecodeSymbol (
267279 std::size_t symbol_cstr_len,
268280 std::vector<std::uint8_t >::const_iterator& read_buffer_it) {
269- return std::string{
270- Consume (read_buffer_it, static_cast <std:: ptrdiff_t >(symbol_cstr_len))} ;
281+ return Consume (read_buffer_it, static_cast < std::ptrdiff_t >(symbol_cstr_len),
282+ " symbol " ) ;
271283}
272284
273285std::vector<std::string> DbnDecoder::DecodeRepeatedSymbol (
0 commit comments