Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
vendorpull https://github.com/sourcemeta/vendorpull 1dcbac42809cf87cb5b045106b863e17ad84ba02
core https://github.com/sourcemeta/core 3ea3a54756071232ca017b96bc15f17d8b5be370
blaze https://github.com/sourcemeta/blaze 0ff98cb5e537f571bdf04f0d59a031a0d8634e07
core https://github.com/sourcemeta/core aa314809fdb59ed6fcb1b10b3087f32eebf708c5
blaze https://github.com/sourcemeta/blaze 5554d3106d7920b28b852e929f0a31d7805effe1
bootstrap https://github.com/twbs/bootstrap 1a6fdfae6be09b09eaced8f0e442ca6f7680a61e
2 changes: 1 addition & 1 deletion config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if(NOT JSONBINPACK_COMPONENTS)
endif()

include(CMakeFindDependencyMacro)
find_dependency(Core COMPONENTS numeric regex uri json jsonpointer jsonschema)
find_dependency(Core COMPONENTS numeric regex uri json jsonpointer jsonschema io)
find_dependency(Blaze COMPONENTS alterschema)

foreach(component ${JSONBINPACK_COMPONENTS})
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT jsonbinpack NAME runtime
SOURCES
input_stream.cc
output_stream.cc
varint.h
unreachable.h
cache.cc

Expand Down Expand Up @@ -44,3 +43,5 @@ target_link_libraries(sourcemeta_jsonbinpack_runtime PUBLIC
sourcemeta::core::json)
target_link_libraries(sourcemeta_jsonbinpack_runtime PUBLIC
sourcemeta::core::numeric)
target_link_libraries(sourcemeta_jsonbinpack_runtime PUBLIC
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Runtime now links against sourcemeta::core::io, but config.cmake.in still calls find_dependency(Core COMPONENTS ...) without io, which can break consumers using find_package(JSONBinPack). Consider adding the Core io component there to match the runtime target’s transitive requirements.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

sourcemeta::core::io)
2 changes: 1 addition & 1 deletion src/runtime/encoder_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ auto Encoder::RFC3339_DATE_INTEGER_TRIPLET(
assert(month >= 1 && month <= 12);
assert(day >= 1 && day <= 31);

this->put_bytes(year);
this->put_word(year);
this->put_byte(month);
this->put_byte(day);
}
Expand Down
19 changes: 4 additions & 15 deletions src/runtime/include/sourcemeta/jsonbinpack/runtime_input_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,29 @@
#include <sourcemeta/jsonbinpack/runtime_export.h>
#endif

#include <sourcemeta/core/io.h>
#include <sourcemeta/core/json.h>

#include <cstdint> // std::uint8_t, std::uint16_t, std::uint64_t
#include <cstdint> // std::uint64_t, std::int64_t
#include <istream> // std::basic_istream

namespace sourcemeta::jsonbinpack {

/// @ingroup runtime
class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT InputStream {
class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT InputStream
: public sourcemeta::core::BinaryReader {
public:
using Stream = std::basic_istream<sourcemeta::core::JSON::Char,
sourcemeta::core::JSON::CharTraits>;
InputStream(Stream &input);
// Prevent copying, as this class is tied to a stream resource
InputStream(const InputStream &) = delete;
auto operator=(const InputStream &) -> InputStream & = delete;

[[nodiscard]] auto position() const noexcept -> std::uint64_t;
auto seek(const std::uint64_t offset) -> void;
// Seek backwards given a relative offset
auto rewind(const std::uint64_t relative_offset, const std::uint64_t position)
-> std::uint64_t;
auto get_byte() -> std::uint8_t;
// A "word" corresponds to two bytes
// See https://stackoverflow.com/questions/28066462/how-many-bits-is-a-word
auto get_word() -> std::uint16_t;
auto get_varint() -> std::uint64_t;
auto get_varint_zigzag() -> std::int64_t;
[[nodiscard]] auto has_more_data() const noexcept -> bool;
auto get_string_utf8(const std::uint64_t length)
-> sourcemeta::core::JSON::String;

private:
Stream &stream;
};

} // namespace sourcemeta::jsonbinpack
Expand Down
16 changes: 4 additions & 12 deletions src/runtime/include/sourcemeta/jsonbinpack/runtime_output_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,26 @@
#include <sourcemeta/jsonbinpack/runtime_export.h>
#endif

#include <sourcemeta/core/io.h>
#include <sourcemeta/core/json.h>

#include <cstdint> // std::uint8_t, std::uint16_t, std::uint64_t
#include <cstdint> // std::uint64_t, std::int64_t
#include <ostream> // std::basic_ostream

namespace sourcemeta::jsonbinpack {

/// @ingroup runtime
class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT OutputStream {
class SOURCEMETA_JSONBINPACK_RUNTIME_EXPORT OutputStream
: public sourcemeta::core::BinaryWriter {
public:
using Stream = std::basic_ostream<sourcemeta::core::JSON::Char,
sourcemeta::core::JSON::CharTraits>;
OutputStream(Stream &output);

// Prevent copying, as this class is tied to a stream resource
OutputStream(const OutputStream &) = delete;
auto operator=(const OutputStream &) -> OutputStream & = delete;

[[nodiscard]] auto position() const noexcept -> std::uint64_t;
auto put_byte(const std::uint8_t byte) -> void;
auto put_bytes(const std::uint16_t bytes) -> void;
auto put_varint(const std::uint64_t value) -> void;
auto put_varint_zigzag(const std::int64_t value) -> void;
auto put_string_utf8(const sourcemeta::core::JSON::String &string,
const std::uint64_t length) -> void;

private:
Stream &stream;
};

} // namespace sourcemeta::jsonbinpack
Expand Down
65 changes: 27 additions & 38 deletions src/runtime/input_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,14 @@

#include <sourcemeta/core/numeric.h>

#include "varint.h"

#include <cassert> // assert
#include <ios> // std::ios_base
#include <cstddef> // std::size_t
#include <cstdint> // std::uint8_t, std::uint64_t, std::int64_t

namespace sourcemeta::jsonbinpack {

InputStream::InputStream(Stream &input) : stream{input} {
this->stream.exceptions(std::ios_base::badbit | std::ios_base::failbit |
std::ios_base::eofbit);
}

auto InputStream::position() const noexcept -> std::uint64_t {
return static_cast<std::uint64_t>(this->stream.tellg());
}

auto InputStream::seek(const std::uint64_t offset) -> void {
this->stream.seekg(static_cast<std::streamoff>(offset));
}
InputStream::InputStream(Stream &input)
: sourcemeta::core::BinaryReader{input} {}

auto InputStream::rewind(const std::uint64_t relative_offset,
const std::uint64_t position) -> std::uint64_t {
Expand All @@ -32,33 +21,33 @@ auto InputStream::rewind(const std::uint64_t relative_offset,
return current;
}

auto InputStream::get_byte() -> std::uint8_t {
return static_cast<std::uint8_t>(this->stream.get());
}

auto InputStream::get_word() -> std::uint16_t {
std::uint16_t word;
this->stream.read(reinterpret_cast<char *>(&word), sizeof word);
return word;
}

auto InputStream::get_varint() -> std::uint64_t {
return varint_decode(this->stream);
}
constexpr std::uint8_t LEAST_SIGNIFICANT_BITS{0b01111111};
constexpr std::uint8_t MOST_SIGNIFICANT_BIT{0b10000000};
constexpr std::uint8_t SHIFT{7};
std::uint64_t result{0};
std::size_t cursor{0};
while (true) {
const std::uint8_t byte{this->get_byte()};
const std::uint64_t value{
static_cast<std::uint64_t>(byte & LEAST_SIGNIFICANT_BITS)};
#ifndef NDEBUG
const std::uint64_t current = result;
#endif
result += static_cast<std::uint64_t>(value << SHIFT * cursor);
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InputStream::get_varint() lets cursor grow without a hard cap, so value << (SHIFT * cursor) becomes undefined once the shift reaches/exceeds 64 bits (and a malformed varint can also force a long decode loop). Consider enforcing a maximum byte count for 64-bit varints before shifting.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

// Try to catch potential overflows from the above addition
assert(result >= current);
cursor += 1;
if ((byte & MOST_SIGNIFICANT_BIT) == 0) {
break;
}
}

auto InputStream::get_varint_zigzag() -> std::int64_t {
const std::uint64_t value = varint_decode(this->stream);
return sourcemeta::core::zigzag_decode(value);
return result;
}

auto InputStream::has_more_data() const noexcept -> bool {
// A way to check if the stream is empty without using `.peek()`,
// which throws given we set exceptions on the EOF bit.
// However, `in_avail()` works on characters and will return zero
// if all that's remaining is 0x00 (null), so we need to handle
// that case separately.
return this->stream.rdbuf()->in_avail() > 0 ||
this->stream.rdbuf()->sgetc() == '\0';
auto InputStream::get_varint_zigzag() -> std::int64_t {
return sourcemeta::core::zigzag_decode(this->get_varint());
}

auto InputStream::get_string_utf8(const std::uint64_t length)
Expand Down
39 changes: 16 additions & 23 deletions src/runtime/output_stream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,31 @@

#include <sourcemeta/core/numeric.h>

#include "varint.h"

#include <cassert> // assert
#include <ios> // std::ios_base
#include <cstdint> // std::uint8_t, std::uint64_t, std::int64_t

namespace sourcemeta::jsonbinpack {

OutputStream::OutputStream(Stream &output) : stream{output} {
this->stream.exceptions(std::ios_base::badbit | std::ios_base::failbit |
std::ios_base::eofbit);
}

auto OutputStream::position() const noexcept -> std::uint64_t {
return static_cast<std::uint64_t>(this->stream.tellp());
}

auto OutputStream::put_byte(const std::uint8_t byte) -> void {
this->stream.put(static_cast<sourcemeta::core::JSON::Char>(byte));
}

auto OutputStream::put_bytes(const std::uint16_t bytes) -> void {
this->stream.write(
reinterpret_cast<const sourcemeta::core::JSON::Char *>(&bytes),
sizeof bytes);
}
OutputStream::OutputStream(Stream &output)
: sourcemeta::core::BinaryWriter{output} {}

auto OutputStream::put_varint(const std::uint64_t value) -> void {
varint_encode(this->stream, value);
constexpr std::uint8_t LEAST_SIGNIFICANT_BITS{0b01111111};
constexpr std::uint8_t MOST_SIGNIFICANT_BIT{0b10000000};
constexpr std::uint8_t SHIFT{7};
std::uint64_t accumulator = value;

while (accumulator > LEAST_SIGNIFICANT_BITS) {
this->put_byte(static_cast<std::uint8_t>(
(accumulator & LEAST_SIGNIFICANT_BITS) | MOST_SIGNIFICANT_BIT));
accumulator >>= SHIFT;
}

this->put_byte(static_cast<std::uint8_t>(accumulator));
}

auto OutputStream::put_varint_zigzag(const std::int64_t value) -> void {
varint_encode(this->stream, sourcemeta::core::zigzag_encode(value));
this->put_varint(sourcemeta::core::zigzag_encode(value));
}

auto OutputStream::put_string_utf8(const sourcemeta::core::JSON::String &string,
Expand Down
60 changes: 0 additions & 60 deletions src/runtime/varint.h

This file was deleted.

21 changes: 21 additions & 0 deletions vendor/blaze/CMakeLists.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions vendor/blaze/DEPENDENCIES

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading