| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "JsonDom.hh" |
| |
| #include <stdexcept> |
| |
| #include <cstring> |
| |
| #include "JsonIO.hh" |
| #include "Stream.hh" |
| |
| using boost::format; |
| using std::string; |
| |
| namespace avro { |
| namespace json { |
| const char *typeToString(EntityType t) { |
| switch (t) { |
| case EntityType::Null: return "null"; |
| case EntityType::Bool: return "bool"; |
| case EntityType::Long: return "long"; |
| case EntityType::Double: return "double"; |
| case EntityType::String: return "string"; |
| case EntityType::Arr: return "array"; |
| case EntityType::Obj: return "object"; |
| default: return "unknown"; |
| } |
| } |
| |
| Entity readEntity(JsonParser &p) { |
| switch (p.peek()) { |
| case JsonParser::Token::Null: |
| p.advance(); |
| return Entity(p.line()); |
| case JsonParser::Token::Bool: |
| p.advance(); |
| return Entity(p.boolValue(), p.line()); |
| case JsonParser::Token::Long: |
| p.advance(); |
| return Entity(p.longValue(), p.line()); |
| case JsonParser::Token::Double: |
| p.advance(); |
| return Entity(p.doubleValue(), p.line()); |
| case JsonParser::Token::String: |
| p.advance(); |
| return Entity(std::make_shared<String>(p.rawString()), p.line()); |
| case JsonParser::Token::ArrayStart: { |
| size_t l = p.line(); |
| p.advance(); |
| std::shared_ptr<Array> v = std::make_shared<Array>(); |
| while (p.peek() != JsonParser::Token::ArrayEnd) { |
| v->push_back(readEntity(p)); |
| } |
| p.advance(); |
| return Entity(v, l); |
| } |
| case JsonParser::Token::ObjectStart: { |
| size_t l = p.line(); |
| p.advance(); |
| std::shared_ptr<Object> v = std::make_shared<Object>(); |
| while (p.peek() != JsonParser::Token::ObjectEnd) { |
| p.advance(); |
| std::string k = p.stringValue(); |
| Entity n = readEntity(p); |
| v->insert(std::make_pair(k, n)); |
| } |
| p.advance(); |
| return Entity(v, l); |
| } |
| default: |
| throw std::domain_error(JsonParser::toString(p.peek())); |
| } |
| } |
| |
| Entity loadEntity(const char *text) { |
| return loadEntity(reinterpret_cast<const uint8_t *>(text), ::strlen(text)); |
| } |
| |
| Entity loadEntity(InputStream &in) { |
| JsonParser p; |
| p.init(in); |
| return readEntity(p); |
| } |
| |
| Entity loadEntity(const uint8_t *text, size_t len) { |
| std::unique_ptr<InputStream> in = memoryInputStream(text, len); |
| return loadEntity(*in); |
| } |
| |
| void writeEntity(JsonGenerator<JsonNullFormatter> &g, const Entity &n) { |
| switch (n.type()) { |
| case EntityType::Null: |
| g.encodeNull(); |
| break; |
| case EntityType::Bool: |
| g.encodeBool(n.boolValue()); |
| break; |
| case EntityType::Long: |
| g.encodeNumber(n.longValue()); |
| break; |
| case EntityType::Double: |
| g.encodeNumber(n.doubleValue()); |
| break; |
| case EntityType::String: |
| g.encodeString(n.stringValue()); |
| break; |
| case EntityType::Arr: { |
| g.arrayStart(); |
| const Array &v = n.arrayValue(); |
| for (const auto &it : v) { |
| writeEntity(g, it); |
| } |
| g.arrayEnd(); |
| } break; |
| case EntityType::Obj: { |
| g.objectStart(); |
| const Object &v = n.objectValue(); |
| for (const auto &it : v) { |
| g.encodeString(it.first); |
| writeEntity(g, it.second); |
| } |
| g.objectEnd(); |
| } break; |
| } |
| } |
| |
| void Entity::ensureType(EntityType type) const { |
| if (type_ != type) { |
| format msg = format("Invalid type. Expected \"%1%\" actual %2%") % typeToString(type) % typeToString(type_); |
| throw Exception(msg); |
| } |
| } |
| |
| String Entity::stringValue() const { |
| ensureType(EntityType::String); |
| return JsonParser::toStringValue(**boost::any_cast<std::shared_ptr<String>>(&value_)); |
| } |
| |
| String Entity::bytesValue() const { |
| ensureType(EntityType::String); |
| return JsonParser::toBytesValue(**boost::any_cast<std::shared_ptr<String>>(&value_)); |
| } |
| |
| std::string Entity::toString() const { |
| std::unique_ptr<OutputStream> out = memoryOutputStream(); |
| JsonGenerator<JsonNullFormatter> g; |
| g.init(*out); |
| writeEntity(g, *this); |
| g.flush(); |
| std::unique_ptr<InputStream> in = memoryInputStream(*out); |
| const uint8_t *p = nullptr; |
| size_t n = 0; |
| size_t c = 0; |
| while (in->next(&p, &n)) { |
| c += n; |
| } |
| std::string result; |
| result.resize(c); |
| c = 0; |
| std::unique_ptr<InputStream> in2 = memoryInputStream(*out); |
| while (in2->next(&p, &n)) { |
| ::memcpy(&result[c], p, n); |
| c += n; |
| } |
| return result; |
| } |
| |
| } // namespace json |
| } // namespace avro |