/** * Copyright (c) 2014-present, Facebook, Inc. * All rights reserved. * * This source code is licensed in accordance with the terms specified in * the LICENSE file found in the root directory of this source tree. */ #pragma once #include #include #include #include #include #include namespace osquery { namespace schemer { namespace impl { template ::value, int>::type = 0> void writeValue(WriterType& writer, ValueType value) { writer.Bool(value); } template < typename WriterType, typename ValueType, typename std::enable_if::value || std::is_same::value || std::is_same::value, int>::type = 0> void writeValue(WriterType& writer, ValueType value) { writer.Int(value); } template ::value, int>::type = 0> void writeValue(WriterType& writer, ValueType const& value) { writer.Int64(value); } template < typename WriterType, typename ValueType, typename std::enable_if::value || std::is_same::value || std::is_same::value, int>::type = 0> void writeValue(WriterType& writer, ValueType value) { writer.Uint(value); } template ::value, int>::type = 0> void writeValue(WriterType& writer, ValueType const& value) { writer.Uint64(value); } template ::value, int>::type = 0> void writeValue(WriterType& writer, ValueType const& value) { writer.Double(value); } template ::value, int>::type = 0> void writeValue(WriterType& writer, ValueType const& value) { writer.String(value); } template class JsonWriter; template ::value, int>::type = 0> void writeValue(WriterType& writer, ValueType const& value) { auto next_writer = impl::JsonWriter(writer); ValueType::discloseSchema(next_writer, value); } template class JsonWriter final { public: explicit JsonWriter(WriterType& writer) : writer_(writer) { writer_.StartObject(); } ~JsonWriter() { writer_.EndObject(); } template void record(const KeyType& key, ValueType const& value) { writer_.Key(key); writeValue(writer_, value); } private: WriterType& writer_; }; class JsonReader final { public: explicit JsonReader(rapidjson::Value const& jObject) : jObject_(jObject) { status.ignoreResult(); if (!jObject_.IsObject()) { status = createError(JsonError::TypeMismatch) << "Wrong type of value: " << jValueToStringForErrorMessage(jObject_) << ", expected object"; } } template void record(const KeyType& key, ValueType& value) { if (status.isError()) { return; } auto const it = jObject_.FindMember(key); if (it == jObject_.MemberEnd()) { status = createError(JsonError::MissedKey) << "Missed mandatory key " << key; } else { copyValueFromJValue(key, value, it->value); } } static inline std::string jValueToStringForErrorMessage( rapidjson::Value const& jObject) { auto buf = rapidjson::StringBuffer{}; rapidjson::Writer writer(buf); jObject.Accept(writer); // make sure string representation of value is not too long std::size_t const kMaxLength = 22u; if (buf.GetSize() < kMaxLength) { return std::string{buf.GetString(), buf.GetSize()}; } else { return std::string{buf.GetString(), kMaxLength - 3} + "..."; } } template ::value, int>::type = 0> void copyValueFromJValue(const KeyType& key, ValueType& value, rapidjson::Value const& jValue) { if (jValue.IsString()) { value.assign(jValue.GetString(), jValue.GetStringLength()); } else { status = createError(JsonError::TypeMismatch) << "Wrong type of value in pair {\"" << key << "\":" << jValueToStringForErrorMessage(jValue) << "}, expected string"; } } template ::value, int>::type = 0> void copyValueFromJValue(const KeyType& key, ValueType& value, rapidjson::Value const& jValue) { if (jValue.IsNumber()) { value = jValue.GetDouble(); } else { status = createError(JsonError::TypeMismatch) << "Wrong type of value in pair {\"" << key << "\":" << jValueToStringForErrorMessage(jValue) << "}, expected floating point number"; } } template ::value, int>::type = 0> void copyValueFromJValue(const KeyType& key, ValueType& value, rapidjson::Value const& jValue) { if (jValue.template Is()) { value = jValue.template Get(); } else { status = createError(JsonError::TypeMismatch) << "Wrong type of value in pair {\"" << key << "\":" << jValueToStringForErrorMessage(jValue) << "}, expected " << boost::core::demangle(typeid(ValueType).name()); } } template < typename KeyType, typename ValueType, typename std::enable_if::value, int>::type = 0> void copyValueFromJValue(const KeyType& key, ValueType& value, rapidjson::Value const& jValue) { auto next_reader = impl::JsonReader{jValue}; if (next_reader.status.isError()) { status = std::move(next_reader.status); } else { ValueType::discloseSchema(next_reader, value); if (next_reader.status.isError()) { status = std::move(next_reader.status); } } } public: ExpectedSuccess status = Success{}; private: rapidjson::Value const& jObject_; }; } // namespace impl } // namespace schemer } // namespace osquery