summaryrefslogtreecommitdiffstats
path: root/src/s3select/rapidjson/example/schemavalidator
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/s3select/rapidjson/example/schemavalidator
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/s3select/rapidjson/example/schemavalidator')
-rw-r--r--src/s3select/rapidjson/example/schemavalidator/schemavalidator.cpp198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/s3select/rapidjson/example/schemavalidator/schemavalidator.cpp b/src/s3select/rapidjson/example/schemavalidator/schemavalidator.cpp
new file mode 100644
index 000000000..8c7e26c79
--- /dev/null
+++ b/src/s3select/rapidjson/example/schemavalidator/schemavalidator.cpp
@@ -0,0 +1,198 @@
+// Schema Validator example
+
+// The example validates JSON text from stdin with a JSON schema specified in the argument.
+
+#define RAPIDJSON_HAS_STDSTRING 1
+
+#include "rapidjson/error/en.h"
+#include "rapidjson/filereadstream.h"
+#include "rapidjson/schema.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/prettywriter.h"
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace rapidjson;
+
+typedef GenericValue<UTF8<>, CrtAllocator > ValueType;
+
+// Forward ref
+static void CreateErrorMessages(const ValueType& errors, size_t depth, const char* context);
+
+// Convert GenericValue to std::string
+static std::string GetString(const ValueType& val) {
+ std::ostringstream s;
+ if (val.IsString())
+ s << val.GetString();
+ else if (val.IsDouble())
+ s << val.GetDouble();
+ else if (val.IsUint())
+ s << val.GetUint();
+ else if (val.IsInt())
+ s << val.GetInt();
+ else if (val.IsUint64())
+ s << val.GetUint64();
+ else if (val.IsInt64())
+ s << val.GetInt64();
+ else if (val.IsBool() && val.GetBool())
+ s << "true";
+ else if (val.IsBool())
+ s << "false";
+ else if (val.IsFloat())
+ s << val.GetFloat();
+ return s.str();}
+
+// Create the error message for a named error
+// The error object can either be empty or contain at least member properties:
+// {"errorCode": <code>, "instanceRef": "<pointer>", "schemaRef": "<pointer>" }
+// Additional properties may be present for use as inserts.
+// An "errors" property may be present if there are child errors.
+static void HandleError(const char* errorName, const ValueType& error, size_t depth, const char* context) {
+ if (!error.ObjectEmpty()) {
+ // Get error code and look up error message text (English)
+ int code = error["errorCode"].GetInt();
+ std::string message(GetValidateError_En(static_cast<ValidateErrorCode>(code)));
+ // For each member property in the error, see if its name exists as an insert in the error message and if so replace with the stringified property value
+ // So for example - "Number '%actual' is not a multiple of the 'multipleOf' value '%expected'." - we would expect "actual" and "expected" members.
+ for (ValueType::ConstMemberIterator insertsItr = error.MemberBegin();
+ insertsItr != error.MemberEnd(); ++insertsItr) {
+ std::string insertName("%");
+ insertName += insertsItr->name.GetString(); // eg "%actual"
+ size_t insertPos = message.find(insertName);
+ if (insertPos != std::string::npos) {
+ std::string insertString("");
+ const ValueType &insert = insertsItr->value;
+ if (insert.IsArray()) {
+ // Member is an array so create comma-separated list of items for the insert string
+ for (ValueType::ConstValueIterator itemsItr = insert.Begin(); itemsItr != insert.End(); ++itemsItr) {
+ if (itemsItr != insert.Begin()) insertString += ",";
+ insertString += GetString(*itemsItr);
+ }
+ } else {
+ insertString += GetString(insert);
+ }
+ message.replace(insertPos, insertName.length(), insertString);
+ }
+ }
+ // Output error message, references, context
+ std::string indent(depth * 2, ' ');
+ std::cout << indent << "Error Name: " << errorName << std::endl;
+ std::cout << indent << "Message: " << message.c_str() << std::endl;
+ std::cout << indent << "Instance: " << error["instanceRef"].GetString() << std::endl;
+ std::cout << indent << "Schema: " << error["schemaRef"].GetString() << std::endl;
+ if (depth > 0) std::cout << indent << "Context: " << context << std::endl;
+ std::cout << std::endl;
+
+ // If child errors exist, apply the process recursively to each error structure.
+ // This occurs for "oneOf", "allOf", "anyOf" and "dependencies" errors, so pass the error name as context.
+ if (error.HasMember("errors")) {
+ depth++;
+ const ValueType &childErrors = error["errors"];
+ if (childErrors.IsArray()) {
+ // Array - each item is an error structure - example
+ // "anyOf": {"errorCode": ..., "errors":[{"pattern": {"errorCode\": ...\"}}, {"pattern": {"errorCode\": ...}}]
+ for (ValueType::ConstValueIterator errorsItr = childErrors.Begin();
+ errorsItr != childErrors.End(); ++errorsItr) {
+ CreateErrorMessages(*errorsItr, depth, errorName);
+ }
+ } else if (childErrors.IsObject()) {
+ // Object - each member is an error structure - example
+ // "dependencies": {"errorCode": ..., "errors": {"address": {"required": {"errorCode": ...}}, "name": {"required": {"errorCode": ...}}}
+ for (ValueType::ConstMemberIterator propsItr = childErrors.MemberBegin();
+ propsItr != childErrors.MemberEnd(); ++propsItr) {
+ CreateErrorMessages(propsItr->value, depth, errorName);
+ }
+ }
+ }
+ }
+}
+
+// Create error message for all errors in an error structure
+// Context is used to indicate whether the error structure has a parent 'dependencies', 'allOf', 'anyOf' or 'oneOf' error
+static void CreateErrorMessages(const ValueType& errors, size_t depth = 0, const char* context = 0) {
+ // Each member property contains one or more errors of a given type
+ for (ValueType::ConstMemberIterator errorTypeItr = errors.MemberBegin(); errorTypeItr != errors.MemberEnd(); ++errorTypeItr) {
+ const char* errorName = errorTypeItr->name.GetString();
+ const ValueType& errorContent = errorTypeItr->value;
+ if (errorContent.IsArray()) {
+ // Member is an array where each item is an error - eg "type": [{"errorCode": ...}, {"errorCode": ...}]
+ for (ValueType::ConstValueIterator contentItr = errorContent.Begin(); contentItr != errorContent.End(); ++contentItr) {
+ HandleError(errorName, *contentItr, depth, context);
+ }
+ } else if (errorContent.IsObject()) {
+ // Member is an object which is a single error - eg "type": {"errorCode": ... }
+ HandleError(errorName, errorContent, depth, context);
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc != 2) {
+ fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
+ return EXIT_FAILURE;
+ }
+
+ // Read a JSON schema from file into Document
+ Document d;
+ char buffer[4096];
+
+ {
+ FILE *fp = fopen(argv[1], "r");
+ if (!fp) {
+ printf("Schema file '%s' not found\n", argv[1]);
+ return -1;
+ }
+ FileReadStream fs(fp, buffer, sizeof(buffer));
+ d.ParseStream(fs);
+ if (d.HasParseError()) {
+ fprintf(stderr, "Schema file '%s' is not a valid JSON\n", argv[1]);
+ fprintf(stderr, "Error(offset %u): %s\n",
+ static_cast<unsigned>(d.GetErrorOffset()),
+ GetParseError_En(d.GetParseError()));
+ fclose(fp);
+ return EXIT_FAILURE;
+ }
+ fclose(fp);
+ }
+
+ // Then convert the Document into SchemaDocument
+ SchemaDocument sd(d);
+
+ // Use reader to parse the JSON in stdin, and forward SAX events to validator
+ SchemaValidator validator(sd);
+ Reader reader;
+ FileReadStream is(stdin, buffer, sizeof(buffer));
+ if (!reader.Parse(is, validator) && reader.GetParseErrorCode() != kParseErrorTermination) {
+ // Schema validator error would cause kParseErrorTermination, which will handle it in next step.
+ fprintf(stderr, "Input is not a valid JSON\n");
+ fprintf(stderr, "Error(offset %u): %s\n",
+ static_cast<unsigned>(reader.GetErrorOffset()),
+ GetParseError_En(reader.GetParseErrorCode()));
+ }
+
+ // Check the validation result
+ if (validator.IsValid()) {
+ printf("Input JSON is valid.\n");
+ return EXIT_SUCCESS;
+ }
+ else {
+ printf("Input JSON is invalid.\n");
+ StringBuffer sb;
+ validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
+ fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
+ fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
+ fprintf(stderr, "Invalid code: %d\n", validator.GetInvalidSchemaCode());
+ fprintf(stderr, "Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
+ sb.Clear();
+ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
+ fprintf(stderr, "Invalid document: %s\n", sb.GetString());
+ // Detailed violation report is available as a JSON value
+ sb.Clear();
+ PrettyWriter<StringBuffer> w(sb);
+ validator.GetError().Accept(w);
+ fprintf(stderr, "Error report:\n%s\n", sb.GetString());
+ CreateErrorMessages(validator.GetError());
+ return EXIT_FAILURE;
+ }
+}