Owner sign-off: replace root LICENSE with Apache License 2.0, add a root NOTICE file, and swap the GPL-2.0 boilerplate header in every first-party core/ and obs-adapter/ source file for a short Apache-2.0 notice. This resolves review finding C2 (GPLv2 top-level LICENSE vs. the vendored Apache-2.0 LiveKit SDK is a license-compatibility violation): the whole repo is now Apache-2.0, matching LiveKit, so there's no GPL/Apache clash left. Updated the README Status gate and the CI workflow comment to reflect that C2 is resolved, while leaving the C1 WebRTC/OpenH264 patent/royalty gate untouched -- that question is still open and still blocks release. third_party/ stays under its own upstream licenses; only this project's own code changed hands. All 6 CTest suites still pass after the header swap. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RL8abRmgFXkVASHkkqiJbE
100 lines
3.6 KiB
C++
100 lines
3.6 KiB
C++
/*
|
|
streamer-tools OBS Camera Plugin - minimal JSON reader
|
|
Copyright (C) 2026 CyberCoveLLC <jknapp85@gmail.com>
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
// A deliberately small, strict, allocation-bounded JSON reader.
|
|
//
|
|
// Why hand-rolled rather than vendoring nlohmann/json: the only JSON this
|
|
// plugin ever parses is two small, fixed-shape responses from its own
|
|
// server (apps/server/src/obs/plugin.routes.ts in the streamer-tools repo),
|
|
// and the parser has to build unmodified on three platforms with no package
|
|
// manager step in CI. The scope is small enough to test exhaustively --
|
|
// including the malformed inputs a compromised or misconfigured endpoint
|
|
// could return, which is the case that must not crash or hang OBS.
|
|
//
|
|
// Properties this parser guarantees, all covered by core/tests/test_json.cpp:
|
|
// - never throws; every failure is reported as Value::invalid()
|
|
// - bounded recursion (kMaxDepth) so nesting cannot blow the stack
|
|
// - trailing garbage after the top-level value is an error
|
|
// - accessors on a wrong-typed value return the caller's default rather
|
|
// than aborting, so callers can be written without type interrogation
|
|
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace stplugin {
|
|
namespace json {
|
|
|
|
/// Maximum nesting depth accepted by parse(). Any deeper input is rejected
|
|
/// as invalid rather than recursed into.
|
|
constexpr int kMaxDepth = 32;
|
|
|
|
class Value {
|
|
public:
|
|
enum class Type { Invalid, Null, Bool, Number, String, Array, Object };
|
|
|
|
Value() = default;
|
|
|
|
static Value invalid() { return Value(); }
|
|
static Value makeNull();
|
|
static Value makeBool(bool v);
|
|
static Value makeNumber(double v);
|
|
static Value makeString(std::string v);
|
|
static Value makeArray(std::vector<Value> v);
|
|
static Value makeObject(std::map<std::string, Value> v);
|
|
|
|
Type type() const { return type_; }
|
|
bool valid() const { return type_ != Type::Invalid; }
|
|
bool isNull() const { return type_ == Type::Null; }
|
|
bool isBool() const { return type_ == Type::Bool; }
|
|
bool isNumber() const { return type_ == Type::Number; }
|
|
bool isString() const { return type_ == Type::String; }
|
|
bool isArray() const { return type_ == Type::Array; }
|
|
bool isObject() const { return type_ == Type::Object; }
|
|
|
|
/// Object member lookup. Returns invalid() for a missing key or when this
|
|
/// value is not an object.
|
|
const Value &operator[](const std::string &key) const;
|
|
|
|
/// Array element access. Returns invalid() when out of range or when this
|
|
/// value is not an array.
|
|
const Value &at(std::size_t index) const;
|
|
|
|
std::size_t size() const;
|
|
|
|
/// Typed accessors. Each returns `fallback` when this value is missing or
|
|
/// of the wrong type, so callers never have to check first.
|
|
std::string asString(const std::string &fallback = std::string()) const;
|
|
bool asBool(bool fallback = false) const;
|
|
double asNumber(double fallback = 0.0) const;
|
|
|
|
const std::vector<Value> &elements() const { return array_; }
|
|
|
|
private:
|
|
Type type_ = Type::Invalid;
|
|
bool bool_ = false;
|
|
double number_ = 0.0;
|
|
std::string string_;
|
|
std::vector<Value> array_;
|
|
std::map<std::string, Value> object_;
|
|
};
|
|
|
|
/// Parse a complete JSON document. Returns Value::invalid() on any syntax
|
|
/// error, on trailing non-whitespace content, or on excessive nesting.
|
|
/// Never throws.
|
|
Value parse(const std::string &text);
|
|
|
|
} // namespace json
|
|
} // namespace stplugin
|