| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- #include <iostream>
- #include <sstream>
- #include "jsonElement.hh"
- #include "streamConsumer.hh"
- StreamConsumer::StreamConsumer(std::istream &s): stream(s), root(nullptr)
- { }
- StreamConsumer::~StreamConsumer()
- {
- if (root)
- delete root;
- for (Warning i : warnings)
- {
- delete i.getPtrUnsafe();
- }
- }
- StreamConsumer *StreamConsumer::withConfig(const AParams *p)
- {
- params = p;
- return this;
- }
- StreamConsumer *StreamConsumer::read()
- {
- if (root)
- return this;
- root = readNext(nullptr);
- return this;
- }
- JSonElement *StreamConsumer::readNext(JSonContainer *parent)
- {
- std::string buf;
- JSonElement *root = consumeToken(parent, buf);
- if (root == nullptr)
- {
- if (buf == "{")
- {
- return readObject(parent);
- }
- else if (buf == "[")
- {
- return readArray(parent);
- }
- else
- return nullptr;
- }
- return root;
- }
- JSonElement * const StreamConsumer::getRoot() const
- {
- return root;
- }
- JSonObject *StreamConsumer::readObject(JSonContainer *parent)
- {
- JSonElement *keyObj;
- JSonObject *result = nullptr;
- std::string buf;
- do
- {
- keyObj = consumeToken(result, buf);
- if (result == nullptr && keyObj == nullptr && buf == "}")
- return new JSonObject(parent);
- JSonPrimitive<std::string> *key = dynamic_cast<JSonPrimitive<std::string> *>(keyObj);
- if (key == nullptr)
- throw JSonObject::NotAKeyException(stream.tellg(), history);
- if (consumeToken(parent, buf) != nullptr || buf != ":")
- throw JsonUnexpectedException(':', stream.tellg(), history);
- if (result == nullptr)
- result = new JSonObject(parent);
- else if (result->contains(key->getValue()))
- {
- if (params->isStrict())
- throw JSonObject::DoubleKeyException(stream.tellg(), key->getValue(), history);
- else // add Warning, new key erase previous one
- {
- result->erase(key->getValue());
- warnings.push_back(Warning(new JSonObject::DoubleKeyException(stream.tellg(), key->getValue(), history)));
- }
- }
- JSonElement *child = readNext(result);
- result->push(key->getValue(), child);
- delete keyObj;
- keyObj = consumeToken(result, buf);
- } while (!keyObj && buf != "}");
- return result;
- }
- JSonArray *StreamConsumer::readArray(JSonContainer *parent)
- {
- JSonArray *result = nullptr;
- std::string buf;
- JSonElement *child = consumeToken(parent, buf);
- if (child == nullptr && buf == "]")
- return new JSonArray(parent); //Empty object
- do
- {
- if (child == nullptr && buf == "[")
- child = readArray(nullptr);
- if (child == nullptr && buf == "{")
- child = readObject(nullptr);
- if (child == nullptr)
- throw JsonNotJsonException(stream.tellg(), history);
- if (result == nullptr)
- result = new JSonArray(parent);
- child->setParent(result);
- result->push_back(child);
- child = consumeToken(result, buf);
- if (child != nullptr)
- throw JsonUnexpectedException(']', stream.tellg(), history);
- else if (buf == "]")
- break;
- else if (buf != ",")
- throw JsonUnexpectedException(']', stream.tellg(), history);
- child = consumeToken(result, buf);
- } while (true);
- return result;
- }
- JSonElement *StreamConsumer::consumeToken(JSonContainer *parent, std::string &buf)
- {
- bool escaped = false;
- bool inString = false;
- bool inBool = false;
- bool inNumber = false;
- bool numberIsDouble = false;
- while (stream.good())
- {
- char c = stream.get();
- history.put(c);
- if (inString)
- {
- if (!escaped)
- {
- if (c == '"')
- return new JSonPrimitive<std::string>(parent, buf);
- else if (c == '\\')
- escaped = true;
- else
- buf += c;
- }
- else
- {
- if (c == '\\' || c == '"')
- {
- buf += c;
- escaped = false;
- }
- else if (c == 'u')
- {
- if (params && params->isIgnoringUnicode())
- {
- buf += "\\u";
- escaped = false;
- }
- else
- {
- char unicodeBuf[4];
- stream.read(unicodeBuf, 4);
- std::streamsize gcount = stream.gcount();
- history.put(unicodeBuf, gcount);
- if (gcount != 4)
- break;
- try {
- appendUnicode(unicodeBuf, buf);
- }
- catch (std::invalid_argument &e)
- {
- throw JsonHexvalueException(e.what(), stream.tellg(), history);
- }
- escaped = false;
- }
- }
- else
- throw JsonEscapedException(c, stream.tellg(), history);
- }
- }
- else if (inBool)
- {
- if (c == 'a' || c == 'e' || c == 'l' || c == 'r' || c == 's' || c == 'u')
- buf += c;
- else if (buf == "true")
- {
- history.pop_back();
- stream.unget();
- return new JSonPrimitive<bool>(parent, true);
- }
- else if (buf == "false")
- {
- history.pop_back();
- stream.unget();
- return new JSonPrimitive<bool>(parent, false);
- }
- else if (ignoreChar(c))
- ;
- else
- throw JsonFormatException(stream.tellg(), history);
- }
- else if (inNumber)
- {
- if (c >= '0' && c <= '9')
- buf += c;
- else if (c == '.' && !numberIsDouble)
- {
- numberIsDouble = true;
- buf += c;
- }
- else
- {
- history.pop_back();
- stream.unget();
- if (numberIsDouble)
- {
- try {
- return new JSonPrimitive<double>(parent, atof(buf.c_str()));
- } catch (std::runtime_error &e)
- {
- throw JsonFormatException(stream.tellg(), history);
- }
- }
- try
- {
- return new JSonPrimitive<int>(parent, std::stoi(buf));
- }
- catch(std::out_of_range e)
- {
- return new JSonPrimitive<long long>(parent, std::stol(buf));
- }
- }
- }
- else
- {
- //!InString, !inbool
- if (c == '"')
- {
- buf = "";
- inString = true;
- }
- else if (c == 't' || c == 'f')
- {
- buf = c;
- inBool = true;
- }
- else if (c == '{' || c == '[' || c == '}' || c == ']' || c == ':' || c == ',')
- {
- buf = c;
- return nullptr;
- }
- else if ((c >= '0' && c <= '9') || c == '.' || c == '-')
- {
- buf = c;
- inNumber = true;
- }
- else if (!ignoreChar(c))
- throw JsonFormatException(stream.tellg(), history);
- }
- }
- buf = "";
- return nullptr;
- }
- static unsigned char hexbyte(const char c)
- {
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- throw std::invalid_argument(JsonHexvalueException::msg(c));
- }
- static unsigned char hexbyte(const char str[2])
- {
- unsigned char result = 0;
- result = (hexbyte(*str) <<4) + hexbyte(str[1]);
- return result;
- }
- void StreamConsumer::appendUnicode(const char unicode[4], std::string &buf)
- {
- unsigned short uni = (hexbyte(unicode) <<8) + hexbyte(unicode+2);
- char test[5];
- bzero(test, sizeof(*test) *5);
- snprintf(test, 4, "%lc", uni);
- buf += test;
- }
- bool StreamConsumer::ignoreChar(char c) const noexcept
- {
- return (c <= 32 || c >= 127 || c == '\n');
- }
- const std::list<Warning> &StreamConsumer::getMessages() const
- { return warnings; }
|