Public Access
A streaming JSON scanner (a 33 KB list of releases costs a few hundred bytes), the release reader built on it, HTTP response heads and chunked bodies, URLs, and the decisions: which release is an update, whether to announce it, and which download URLs the device takes. Tested against the real answers of git.twis.la. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
58 lines
1.9 KiB
C++
58 lines
1.9 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace roro::release {
|
|
|
|
// Reads JSON as it arrives, a chunk at a time, and reports each plain value (a string, a number,
|
|
// true, false, null) with where it was found: "tag_name", "assets[1].name", "[2].draft". Nothing
|
|
// is kept but the path, so a 33 KB list of releases costs a few hundred bytes. A value longer than
|
|
// `maxValueBytes` is cut (never in the middle of a character) and reported as truncated.
|
|
// Meant for a server's answer, not for validating JSON: it only refuses what it can't follow.
|
|
class JsonScanner {
|
|
public:
|
|
using Sink = std::function<void(const std::string& path, const std::string& value, bool isString, bool truncated)>;
|
|
|
|
explicit JsonScanner(Sink sink, size_t maxValueBytes = 300) : sink_(std::move(sink)), max_(maxValueBytes) {}
|
|
|
|
void feed(const char* data, size_t len);
|
|
bool failed() const { return failed_; }
|
|
bool done() const { return done_ && !failed_; } // the top-level value is complete
|
|
|
|
private:
|
|
enum class Expect : uint8_t { Value, KeyOrEnd, Colon, CommaOrEnd };
|
|
struct Frame {
|
|
bool isObject;
|
|
std::string key;
|
|
int index;
|
|
};
|
|
|
|
void step(char c);
|
|
void startString(bool key);
|
|
void stringChar(char c);
|
|
void appendCodePoint(uint32_t cp);
|
|
void endString();
|
|
void endLiteral();
|
|
void valueDone();
|
|
void append(const char* bytes, size_t n);
|
|
std::string path() const;
|
|
void fail() { failed_ = true; }
|
|
|
|
Sink sink_;
|
|
size_t max_;
|
|
std::vector<Frame> stack_;
|
|
Expect expect_ = Expect::Value;
|
|
bool inString_ = false, isKey_ = false, escape_ = false, inLiteral_ = false;
|
|
int unicodeLeft_ = 0;
|
|
uint32_t unicode_ = 0, highSurrogate_ = 0;
|
|
bool truncated_ = false;
|
|
std::string text_;
|
|
bool failed_ = false, done_ = false;
|
|
};
|
|
|
|
} // namespace roro::release
|