blob: 5bffda2559c2948da33dcf39fef6da51444236c8 [file] [log] [blame]
/**
* 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