Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
#include <tvariant.h>
Ivan Mahonin 6e237b
Ivan Mahonin 9cf1a4
#include <sstream>
Ivan Mahonin 9cf1a4
#include <iostream>
Ivan Mahonin 9cf1a4
#include <cstdio>
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
int
Ivan Mahonin 6e237b
TVariantPath::compare(
Ivan Mahonin 6e237b
  const TVariantPath &a, int beginA,
Ivan Mahonin 6e237b
  const TVariantPath &b, int beginB, int count )
Ivan Mahonin 6e237b
{
Ivan Mahonin 6e237b
  assert(beginA >= 0 && beginA <= (int)a.size());
Ivan Mahonin 6e237b
  assert(beginB >= 0 && beginB <= (int)b.size());
Ivan Mahonin 6e237b
  if (count == 0) return 0;
Ivan Mahonin 6e237b
  int countA = std::min(count, (int)a.size() - beginA);
Ivan Mahonin 6e237b
  int countB = std::min(count, (int)b.size() - beginB);
Ivan Mahonin 6e237b
  count = std::min(countA, countB);
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
  TVariantPath::const_iterator ia = a.begin() + beginA;
Ivan Mahonin 6e237b
  TVariantPath::const_iterator ib = b.begin() + beginB;
Ivan Mahonin 6e237b
  for(int i = 0; i < count; ++i, ++ia, ++ib)
Ivan Mahonin 6e237b
    if ((*ia) < (*ib)) return -1; else
Ivan Mahonin 6e237b
      if ((*ib) < (*ia)) return 1;
Ivan Mahonin 6e237b
  return countA < countB ? -1
Ivan Mahonin 6e237b
       : countB < countA ?  1 : 0;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
void
Ivan Mahonin 6e237b
TVariant::setParentForChilds() {
Ivan Mahonin 6e237b
  if (m_type == List) {
Ivan Mahonin 6e237b
    for(TVariantList::iterator i = m_list.begin(); i != m_list.end(); ++i)
Ivan Mahonin 6e237b
      i->setParent(*this);
Ivan Mahonin 6e237b
  } else
Ivan Mahonin 6e237b
  if (m_type == Map) {
Ivan Mahonin 6e237b
    for(TVariantMap::iterator i = m_map.begin(); i != m_map.end(); ++i)
Ivan Mahonin 6e237b
      i->second.setParent(*this, i->first);
Ivan Mahonin 6e237b
  }
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
const TVariant&
Ivan Mahonin 6e237b
TVariant::blank() {
Ivan Mahonin 6e237b
  static const TVariant blank;
Ivan Mahonin 6e237b
  return blank;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
void
Ivan Mahonin 6e237b
TVariant::resize(int size) {
Ivan Mahonin 6e237b
  setType(List);
Ivan Mahonin 6e237b
  int prevSize = (int)m_list.size();
Ivan Mahonin 6e237b
  if (prevSize == size) return;
Ivan Mahonin 6e237b
  m_list.resize(size);
Ivan Mahonin 6e237b
  if (prevSize < size)
Ivan Mahonin 6e237b
    for(TVariantList::iterator i = m_list.begin() + prevSize; i != m_list.end(); ++i)
Ivan Mahonin 6e237b
      i->setParent(*this);
Ivan Mahonin 6e237b
  touch();
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
void
Ivan Mahonin 6e237b
TVariant::insert(int index, const TVariant &v) {
Ivan Mahonin 6e237b
  resize(std::max((int)m_list.size(), index));
Ivan Mahonin 6e237b
  m_list.insert(m_list.begin() + index, v);
Ivan Mahonin 6e237b
  m_list[index].setParent(*this);
Ivan Mahonin 6e237b
  touch();
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
void
Ivan Mahonin 6e237b
TVariant::remove(int index) {
Ivan Mahonin 6e237b
  if (m_type == List && index >= 0 && index < (int)m_list.size())
Ivan Mahonin 6e237b
    { m_list.erase(m_list.begin() + index); touch(); }
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
TVariant&
Ivan Mahonin 6e237b
TVariant::operator[] (int index) {
Ivan Mahonin 6e237b
  setType(List);
Ivan Mahonin 6e237b
  assert(index >= 0);
Ivan Mahonin 6e237b
  int prevSize = (int)m_list.size();
Ivan Mahonin 6e237b
  if (index >= prevSize) {
Ivan Mahonin 6e237b
    m_list.resize(index + 1);
Ivan Mahonin 6e237b
    for(TVariantList::iterator i = m_list.begin() + prevSize; i != m_list.end(); ++i)
Ivan Mahonin 6e237b
      i->setParent(*this);
Ivan Mahonin 6e237b
    touch();
Ivan Mahonin 6e237b
  }
Ivan Mahonin 6e237b
  return m_list[index];
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
TVariant&
Ivan Mahonin 6e237b
TVariant::operator[] (const TStringId &field) {
Ivan Mahonin 6e237b
  setType(Map);
Ivan Mahonin 6e237b
  TVariant &result = m_map[field];
Ivan Mahonin ae9154
  if (!result.m_parent) {
Ivan Mahonin ae9154
    result.setParent(*this, field);
Ivan Mahonin ae9154
    touch();
Ivan Mahonin ae9154
  }
Ivan Mahonin 6e237b
  return result;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
bool
Ivan Mahonin 6e237b
TVariant::remove(const TStringId &field) {
Ivan Mahonin 6e237b
  if (m_type == Map && m_map.erase(field))
Ivan Mahonin 6e237b
    { touch(); return true; }
Ivan Mahonin 6e237b
  return false;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
const TVariant&
Ivan Mahonin 6e237b
TVariant::byPath(const TVariantPath &path, int begin, int end) const {
Ivan Mahonin 6e237b
  if ((int)path.size() <= begin || begin >= end) return *this;
Ivan Mahonin 6e237b
  if (isNone()) return blank();
Ivan Mahonin 9cf8be
  return (*this)[path[begin]].byPath(path, begin + 1, end);
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
TVariant&
Ivan Mahonin 6e237b
TVariant::byPath(const TVariantPath &path, int begin, int end) {
Ivan Mahonin 6e237b
  if ((int)path.size() <= begin || begin >= end) return *this;
Ivan Mahonin 9cf8be
  return (*this)[path[begin]].byPath(path, begin + 1, end);
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
int
Ivan Mahonin 9cf8be
TVariant::getParentPathSize(const TVariant &parent) const {
Ivan Mahonin 6e237b
  int ac = 0;
Ivan Mahonin 9cf8be
  for(const TVariant *a = this; a; a = a->parent(), ++ac)
Ivan Mahonin 9cf8be
    if (a == &parent) return ac;
Ivan Mahonin 9cf8be
  return -1;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 9cf8be
bool
Ivan Mahonin 9cf8be
TVariant::getParentPath(TVariantPath &outPath, const TVariant &parent) const {
Ivan Mahonin 9cf8be
  if (!m_parent)
Ivan Mahonin 9cf8be
    { outPath.clear(); return false; }
Ivan Mahonin 9cf8be
  if (m_parent == this)
Ivan Mahonin 9cf8be
    { outPath.clear(); return true; }
Ivan Mahonin 9cf8be
  if (m_parent->getParentPath(outPath))
Ivan Mahonin 9cf8be
    { outPath.push_back(parentPathEntry()); return true; }
Ivan Mahonin 9cf8be
  return false;
Ivan Mahonin 9cf8be
}
Ivan Mahonin 9cf8be
Ivan Mahonin 9cf8be
//---------------------------------------------------------
Ivan Mahonin 9cf8be
Ivan Mahonin 9cf8be
bool
Ivan Mahonin 9cf8be
TVariant::getChildPathEntry(const TVariant &child, TVariantPathEntry &outEntry) const {
Ivan Mahonin 9cf8be
  for(const TVariant *a = &child; a->parent(); a = a->parent())
Ivan Mahonin 9cf8be
    if (a->parent() == this)
Ivan Mahonin 9cf8be
      { outEntry = a->parentPathEntry(); return true; }
Ivan Mahonin 9cf8be
  outEntry = TVariantPathEntry();
Ivan Mahonin 9cf8be
  return false;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
bool
Ivan Mahonin 6e237b
TVariant::isChildOf(const TVariant &other) const {
Ivan Mahonin 6e237b
  for(const TVariant *a = this->m_parent; a; a = a->m_parent)
Ivan Mahonin 6e237b
    if (a == &other) return true;
Ivan Mahonin 6e237b
  return false;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
bool
Ivan Mahonin 6e237b
TVariant::isChildOrEqual(const TVariant &other) const {
Ivan Mahonin 6e237b
  for(const TVariant *a = this; a; a = a->m_parent)
Ivan Mahonin 6e237b
    if (a == &other) return true;
Ivan Mahonin 6e237b
  return false;
Ivan Mahonin 6e237b
}
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
//---------------------------------------------------------
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
const TVariant*
Ivan Mahonin 6e237b
TVariant::findCommonParent(const TVariant &other) const {
Ivan Mahonin 6e237b
  if (m_root != other.m_root) return NULL;
Ivan Mahonin 6e237b
  const TVariant *a = this, *b = &other;
Ivan Mahonin 6e237b
  int ac = 0, bc = 0;
Ivan Mahonin 6e237b
  while(a->m_parent) a = a->m_parent, ++ac;
Ivan Mahonin 6e237b
  while(b->m_parent) b = b->m_parent, ++bc;
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
  a = this, b = &other;
Ivan Mahonin 6e237b
  while(ac > bc) a = a->m_parent, --ac;
Ivan Mahonin 6e237b
  while(bc > ac) b = b->m_parent, --bc;
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
  while(true) {
Ivan Mahonin 6e237b
    if (a == b) return a;
Ivan Mahonin 6e237b
    if (ac == 0) break;
Ivan Mahonin 6e237b
    --ac, a = a->m_parent, b = b->m_parent;
Ivan Mahonin 6e237b
  }
Ivan Mahonin 6e237b
Ivan Mahonin 6e237b
  return NULL;
Ivan Mahonin 6e237b
}
Ivan Mahonin 249386
Ivan Mahonin 249386
//---------------------------------------------------------
Ivan Mahonin 249386
Ivan Mahonin 249386
size_t
Ivan Mahonin 249386
TVariant::getMemSize() const {
Ivan Mahonin 249386
  size_t s = sizeof(*this);
Ivan Mahonin 249386
  for(TVariantList::const_iterator i = m_list.begin(); i != m_list.end(); ++i)
Ivan Mahonin 249386
    s += i->getMemSize();
Ivan Mahonin 249386
  for(TVariantMap::const_iterator i = m_map.begin(); i != m_map.end(); ++i)
Ivan Mahonin 249386
    s += sizeof(*i) - sizeof(*this) + i->second.getMemSize();
Ivan Mahonin 249386
  return s;
Ivan Mahonin 249386
}
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
//---------------------------------------------------------
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
void
Ivan Mahonin 9cf1a4
TVariant::toStream(std::ostream &stream, bool pretty, int level) const {
Ivan Mahonin 9cf1a4
  struct Writer {
Ivan Mahonin 9cf1a4
    const TVariant &data;
Ivan Mahonin 9cf1a4
    std::ostream &stream;
Ivan Mahonin 9cf1a4
    bool pretty;
Ivan Mahonin 9cf1a4
    int level;
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    Writer(const TVariant &data, std::ostream &stream, bool pretty, int level):
Ivan Mahonin 9cf1a4
      data(data), stream(stream), pretty(pretty), level(level) { }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void writeNewLine()
Ivan Mahonin 9cf1a4
      { if (pretty) stream << std::endl; }
Ivan Mahonin 9cf1a4
    void writeSpace()
Ivan Mahonin 9cf1a4
      { if (pretty) stream << " "; }
Ivan Mahonin 9cf1a4
    void writeTab(int level)
Ivan Mahonin 9cf1a4
      { if (pretty) for(int i = 2*level; i; --i) stream << " "; }
Ivan Mahonin 9cf1a4
    void writeChar(char c)
Ivan Mahonin 9cf1a4
      { stream.put(c); }
Ivan Mahonin 9cf1a4
    void writeWord(const char *word)
Ivan Mahonin 9cf1a4
      { stream << word; }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void writeString(const std::string &str) {
Ivan Mahonin 9cf1a4
      writeWord("\"");
Ivan Mahonin 9cf1a4
      for(const char *c = str.c_str(); *c; ++c) {
Ivan Mahonin 9cf1a4
        switch (*c) {
Ivan Mahonin 9cf1a4
        case '\"': writeWord("\\\""); break;
Ivan Mahonin 9cf1a4
        case '\\': writeWord("\\\\"); break;
Ivan Mahonin 9cf1a4
        case '\b': writeWord("\\b"); break;
Ivan Mahonin 9cf1a4
        case '\f': writeWord("\\f"); break;
Ivan Mahonin 9cf1a4
        case '\n': writeWord("\\n"); break;
Ivan Mahonin 9cf1a4
        case '\r': writeWord("\\r"); break;
Ivan Mahonin 9cf1a4
        case '\t': writeWord("\\t"); break;
Ivan Mahonin 9cf1a4
        default: writeChar(*c); break;
Ivan Mahonin 9cf1a4
        }
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
      writeWord("\"");
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void writeDouble(double x) {
Ivan Mahonin 9cf1a4
      char buf[256];
Ivan Mahonin 9cf1a4
      snprintf(buf, sizeof(buf), "%.12lg", x);
Ivan Mahonin 9cf1a4
      stream << buf;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void writeList(const TVariantList &list) {
Ivan Mahonin 9cf1a4
      writeWord("[");
Ivan Mahonin 9cf1a4
      if (!list.empty()) {
Ivan Mahonin 9cf1a4
        writeNewLine();
Ivan Mahonin 9cf1a4
        TVariantList::const_iterator i = list.begin();
Ivan Mahonin 9cf1a4
        while(true) {
Ivan Mahonin 9cf1a4
          writeTab(level + 1);
Ivan Mahonin 9cf1a4
          i->toStream(stream, pretty, level + 1);
Ivan Mahonin 9cf1a4
          if (++i == list.end()) { writeNewLine(); break; }
Ivan Mahonin 9cf1a4
          writeWord(",");
Ivan Mahonin 9cf1a4
          writeNewLine();
Ivan Mahonin 9cf1a4
        }
Ivan Mahonin 9cf1a4
        writeTab(level);
Ivan Mahonin 9cf1a4
      } else writeSpace();
Ivan Mahonin 9cf1a4
      writeWord("]");
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void writeMap(const TVariantMap &map) {
Ivan Mahonin 9cf1a4
      writeWord("{");
Ivan Mahonin 9cf1a4
      if (!map.empty()) {
Ivan Mahonin 9cf1a4
        writeNewLine();
Ivan Mahonin 9cf1a4
        TVariantMap::const_iterator i = map.begin();
Ivan Mahonin 9cf1a4
        while(true) {
Ivan Mahonin 9cf1a4
          writeTab(level + 1);
Ivan Mahonin 9cf1a4
          writeString(i->first.str());
Ivan Mahonin 9cf1a4
          writeWord(":");
Ivan Mahonin 9cf1a4
          writeSpace();
Ivan Mahonin 9cf1a4
          i->second.toStream(stream, pretty, level + 1);
Ivan Mahonin 9cf1a4
          if (++i == map.end()) { writeNewLine(); break; }
Ivan Mahonin 9cf1a4
          writeWord(",");
Ivan Mahonin 9cf1a4
          writeNewLine();
Ivan Mahonin 9cf1a4
        }
Ivan Mahonin 9cf1a4
        writeTab(level);
Ivan Mahonin 9cf1a4
      } else writeSpace();
Ivan Mahonin 9cf1a4
      writeWord("}");
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void write() {
Ivan Mahonin 9cf1a4
      switch(data.getType()) {
Ivan Mahonin 9cf1a4
      case Bool: writeWord(data.getBool() ? "true" : "false"); break;
Ivan Mahonin 9cf1a4
      case Double: writeDouble(data.getDouble()); break;
Ivan Mahonin 9cf1a4
      case String: writeString(data.getString()); break;
Ivan Mahonin 9cf1a4
      case List: writeList(data.getList()); break;
Ivan Mahonin 9cf1a4
      case Map: writeMap(data.getMap()); break;
Ivan Mahonin 9cf1a4
      case None:
Ivan Mahonin 9cf1a4
      default: writeWord("null"); break;
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
      if (!stream) throw TException("write to stream failed");
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
  };
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
  Writer(*this, stream, pretty, level).write();
Ivan Mahonin 9cf1a4
}
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
//---------------------------------------------------------
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
void
Ivan Mahonin 9cf1a4
TVariant::fromStream(std::istream &stream, int *currentRow, int *currentCol) {
Ivan Mahonin 9cf1a4
  struct Reader {
Ivan Mahonin 9cf1a4
    TVariant &data;
Ivan Mahonin 9cf1a4
    std::istream &stream;
Ivan Mahonin 9cf1a4
    int &row;
Ivan Mahonin 9cf1a4
    int &col;
Ivan Mahonin 9cf1a4
    Reader(TVariant &data, std::istream &stream, int &row, int &col):
Ivan Mahonin 9cf1a4
      data(data), stream(stream), row(row), col(col) { }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void warning(const std::string &msg)
Ivan Mahonin 9cf1a4
      { std::cerr << "TVariant load:" << row << ":" << col << ": " << msg << std::endl; }
Ivan Mahonin 9cf1a4
    void error(const std::string &msg)
Ivan Mahonin 9cf1a4
      { throw TVariantSyntaxException(row, col, msg); }
Ivan Mahonin 9cf1a4
    void error()
Ivan Mahonin 9cf1a4
      { error("cannot recognize type of data"); }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    int peek()
Ivan Mahonin 9cf1a4
      { return stream.peek(); }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    int get() {
Ivan Mahonin 9cf1a4
      int c = stream.get();
Ivan Mahonin 9cf1a4
      if (c == '\n') ++row, col = 1; else ++col;
Ivan Mahonin 9cf1a4
      if (!stream) error("unexpected end of file");
Ivan Mahonin 9cf1a4
      return c;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void skipSpaces()
Ivan Mahonin 9cf1a4
      { while(isspace(peek())) get(); }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool readWord(const char *word) {
Ivan Mahonin 9cf1a4
      if (peek() != *word) return false;
Ivan Mahonin 9cf1a4
      while(*word)
Ivan Mahonin 9cf1a4
        if (get() == *word) ++word; else error();
Ivan Mahonin 9cf1a4
      return true;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool readNull() {
Ivan Mahonin 9cf1a4
      if (readWord("null") || peek() == EOF)
Ivan Mahonin 9cf1a4
        { data.reset(); return true; }
Ivan Mahonin 9cf1a4
      return false;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool readBool() {
Ivan Mahonin 9cf1a4
      if (readWord("true")) { data.setBool(true); return true; }
Ivan Mahonin 9cf1a4
      if (readWord("false")) { data.setBool(false); return true; }
Ivan Mahonin 9cf1a4
      return false;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool isdouble(int c)
Ivan Mahonin 9cf1a4
      { return isdigit(c) || c == '-' || c == '+' || c == '.'; }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool readDouble() {
Ivan Mahonin 9cf1a4
      if (!isdouble(peek())) return false;
Ivan Mahonin 9cf1a4
      std::string str; str.reserve(20);
Ivan Mahonin 9cf1a4
      while(isdouble(peek()) || isalpha(peek())) str.push_back((char)get());
Ivan Mahonin 9cf1a4
      double d = 0.0;
Ivan Mahonin 9cf1a4
      try { d = std::stod(str); }
Ivan Mahonin 9cf1a4
      catch (const std::exception &e) { warning("wrong number: " + str); }
Ivan Mahonin 9cf1a4
      data.setDouble(d);
Ivan Mahonin 9cf1a4
      return true;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void readHexUnicode(std::string &str) {
Ivan Mahonin 9cf1a4
      // read utf16 code
Ivan Mahonin 9cf1a4
      // JSON standard requires exact four hex digits
Ivan Mahonin 9cf1a4
      // but we're kind and allows 0-4 hex digits
Ivan Mahonin 9cf1a4
      int code = 0;
Ivan Mahonin 9cf1a4
      for(int i = 0; i < 4; ++i) {
Ivan Mahonin 9cf1a4
        char c = peek();
Ivan Mahonin 9cf1a4
        if (c >= '0' && c <= '9')
Ivan Mahonin 9cf1a4
          code = 16*code + get() - '0';
Ivan Mahonin 9cf1a4
        else if (c >= 'a' && c <= 'f')
Ivan Mahonin 9cf1a4
          code = 16*code + get() - 'a';
Ivan Mahonin 9cf1a4
        else if (c >= 'A' && c <= 'F')
Ivan Mahonin 9cf1a4
          code = 16*code + get() - 'A';
Ivan Mahonin 9cf1a4
        else break;
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
      if (code == 0)
Ivan Mahonin 9cf1a4
        { warning("\\u token with zero code"); return; }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
      // 16 bits of utf16 character be encoded up to three utf8 bytes
Ivan Mahonin 9cf1a4
      // in the following format:
Ivan Mahonin 9cf1a4
      //   11000xxx 10xxxxxx 0xxxxxxx
Ivan Mahonin 9cf1a4
      if (code >= 1 << 13) {     // 11000xxx
Ivan Mahonin 9cf1a4
        str.push_back((char)(192 | (code >> 13)));
Ivan Mahonin 9cf1a4
        code &= (1 << 13) - 1;
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
      if (code >= 1 << 6) {      // 10xxxxxx
Ivan Mahonin 9cf1a4
        str.push_back((char)(128 | (code >> 6)));
Ivan Mahonin 9cf1a4
        code &= (1 << 6) - 1;
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
      str.push_back((char)code); // 0xxxxxxx
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void readString(std::string &str) {
Ivan Mahonin 9cf1a4
      if (get() != '\"') error("expected quote");
Ivan Mahonin 9cf1a4
      while(true) {
Ivan Mahonin 9cf1a4
        int c = get();
Ivan Mahonin 9cf1a4
        if (c == '\"') break;
Ivan Mahonin 9cf1a4
        else
Ivan Mahonin 9cf1a4
        if (c == '\\') {
Ivan Mahonin 9cf1a4
          switch(int cc = get()) {
Ivan Mahonin 9cf1a4
          case '\"': str.push_back('\"'); break;
Ivan Mahonin 9cf1a4
          case '\\': str.push_back('\\'); break;
Ivan Mahonin 9cf1a4
          case  '/': str.push_back( '/'); break;
Ivan Mahonin 9cf1a4
          case  'b': str.push_back('\b'); break;
Ivan Mahonin 9cf1a4
          case  'f': str.push_back('\f'); break;
Ivan Mahonin 9cf1a4
          case  'n': str.push_back('\n'); break;
Ivan Mahonin 9cf1a4
          case  'r': str.push_back('\r'); break;
Ivan Mahonin 9cf1a4
          case  't': str.push_back('\t'); break;
Ivan Mahonin 9cf1a4
          case  'u': readHexUnicode(str); break;
Ivan Mahonin 9cf1a4
          default: str.push_back((char)cc); break;
Ivan Mahonin 9cf1a4
          }
Ivan Mahonin 9cf1a4
        } else
Ivan Mahonin 9cf1a4
          str.push_back((char)c);
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool readString() {
Ivan Mahonin 9cf1a4
      if (peek() != '\"') return false;
Ivan Mahonin 9cf1a4
      std::string str;
Ivan Mahonin 9cf1a4
      readString(str);
Ivan Mahonin 9cf1a4
      data.setString(str);
Ivan Mahonin 9cf1a4
      return true;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool readList() {
Ivan Mahonin 9cf1a4
      if (peek() != '[') return false;
Ivan Mahonin 9cf1a4
      get(); // skip bracket
Ivan Mahonin 9cf1a4
      data.reset();
Ivan Mahonin 9cf1a4
      data.setType(List);
Ivan Mahonin 9cf1a4
      while(true) {
Ivan Mahonin 9cf1a4
        skipSpaces();
Ivan Mahonin 9cf1a4
        if (peek() == ']') { get(); break; }
Ivan Mahonin 9cf1a4
        if (data.size() && get() != ',') error("expected comma or close bracket");
Ivan Mahonin 9cf1a4
        skipSpaces();
Ivan Mahonin 9cf1a4
        if (peek() == ']') { get(); break; } // to allow comma at the end
Ivan Mahonin 9cf1a4
        data[data.size()].fromStream(stream, &row, &col);
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
      return true;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    bool readMap() {
Ivan Mahonin 9cf1a4
      if (peek() != '{') return false;
Ivan Mahonin 9cf1a4
      get(); // skip brace
Ivan Mahonin 9cf1a4
      data.reset();
Ivan Mahonin 9cf1a4
      data.setType(Map);
Ivan Mahonin 9cf1a4
      while(true) {
Ivan Mahonin 9cf1a4
        skipSpaces();
Ivan Mahonin 9cf1a4
        if (peek() == '}') { get(); break; }
Ivan Mahonin 9cf1a4
        if (data.size() && get() != ',') error("expected comma or close brace");
Ivan Mahonin 9cf1a4
        skipSpaces();
Ivan Mahonin 9cf1a4
        if (peek() == '}') { get(); break; } // to allow comma at the end
Ivan Mahonin 9cf1a4
        std::string key;
Ivan Mahonin 9cf1a4
        readString(key);
Ivan Mahonin 9cf1a4
        skipSpaces();
Ivan Mahonin 9cf1a4
        if (get() != ':') error("expected colon");
Ivan Mahonin 9cf1a4
        if (data.contains(key)) warning("duplicate key: " + key);
Ivan Mahonin 9cf1a4
        data[key].fromStream(stream, &row, &col);
Ivan Mahonin 9cf1a4
      }
Ivan Mahonin 9cf1a4
      return true;
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
    void read() {
Ivan Mahonin 9cf1a4
      skipSpaces();
Ivan Mahonin 9cf1a4
      if ( !readNull()
Ivan Mahonin 9cf1a4
        && !readBool()
Ivan Mahonin 9cf1a4
        && !readDouble()
Ivan Mahonin 9cf1a4
        && !readString()
Ivan Mahonin 9cf1a4
        && !readList()
Ivan Mahonin 9cf1a4
        && !readMap() )
Ivan Mahonin 9cf1a4
          error();
Ivan Mahonin 9cf1a4
    }
Ivan Mahonin 9cf1a4
  };
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
  reset();
Ivan Mahonin 9cf1a4
  int row = 1, col = 1;
Ivan Mahonin 9cf1a4
  Reader(
Ivan Mahonin 9cf1a4
    *this,
Ivan Mahonin 9cf1a4
    stream,
Ivan Mahonin 9cf1a4
    (currentRow ? *currentRow : row),
Ivan Mahonin 9cf1a4
    (currentCol ? *currentCol : col) ).read();
Ivan Mahonin 9cf1a4
}
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
//---------------------------------------------------------
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
std::string
Ivan Mahonin 9cf1a4
TVariant::toString(bool pretty, int level) const {
Ivan Mahonin 9cf1a4
  std::stringstream stream(std::ios_base::out);
Ivan Mahonin 9cf1a4
  toStream(stream, pretty, level);
Ivan Mahonin 9cf1a4
  return stream.str();
Ivan Mahonin 9cf1a4
}
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
//---------------------------------------------------------
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
void
Ivan Mahonin 9cf1a4
TVariant::fromString(const std::string &str, int *currentRow, int *currentCol) {
Ivan Mahonin 9cf1a4
  std::stringstream stream(str, std::ios_base::in);
Ivan Mahonin 9cf1a4
  fromStream(stream, currentRow, currentCol);
Ivan Mahonin 9cf1a4
}
Ivan Mahonin 9cf1a4
Ivan Mahonin 9cf1a4
//---------------------------------------------------------
Ivan Mahonin 9cf1a4