#include "qpiconfig.h" #include #include int QString2int(const QString & string) { QString s = string.trimmed(); if (s.left(2) == "0x") return s.mid(2).toLongLong(0, 16); if (s.left(1) == "0") return s.mid(1).toLongLong(0, 8); return s.toLongLong(); } QRect QString2QRect(const QString & string) { int sl, st, sw, sh; int s = 0, e; e = string.indexOf(";"); sl = string.mid(s, e - s).toInt(); s = e + 1; e = string.indexOf(";", s); st = string.mid(s, e - s).toInt(); s = e + 1; e = string.indexOf(";", s); sw = string.mid(s, e - s).toInt(); s = e + 1; e = string.length(); sh = string.mid(s, e - s).toInt(); return QRect(sl, st, sw, sh); } QRectF QString2QRectF(const QString & string) { double sl, st, sw, sh; int s = 0, e; e = string.indexOf(";"); sl = string.mid(s, e - s).toDouble(); s = e + 1; e = string.indexOf(";", s); st = string.mid(s, e - s).toDouble(); s = e + 1; e = string.indexOf(";", s); sw = string.mid(s, e - s).toDouble(); s = e + 1; e = string.length(); sh = string.mid(s, e - s).toDouble(); return QRectF(sl, st, sw, sh); } QPoint QString2QPoint(const QString & string) { int sx, sy; int s = 0, e; e = string.indexOf(";"); sx = string.mid(s, e - s).toInt(); s = e + 1; e = string.length(); sy = string.mid(s, e - s).toInt(); return QPoint(sx, sy); } QPointF QString2QPointF(const QString & string) { double sx, sy; int s = 0, e; e = string.indexOf(";"); sx = string.mid(s, e - s).toDouble(); s = e + 1; e = string.length(); sy = string.mid(s, e - s).toDouble(); return QPointF(sx, sy); } QString QRect2QString(const QRect & rect) { return QString::number(rect.left()) + ";" + QString::number(rect.top()) + ";" + QString::number(rect.width()) + ";" + QString::number(rect.height()); } QString QRectF2QString(const QRectF & rect) { return QString::number(rect.left()) + ";" + QString::number(rect.top()) + ";" + QString::number(rect.width()) + ";" + QString::number(rect.height()); } QPIConfig::Entry QPIConfig::Branch::_empty; QPIConfig::Entry QPIConfig::Entry::_empty; QPIConfig::Branch QPIConfig::Branch::allLeaves() { Branch b; b.delim = delim; foreach(Entry * i, *this) { if (i->isLeaf()) b << i; else allLeaves(b, i); } return b; } QPIConfig::Entry & QPIConfig::Branch::getValue(const QString & vname, const QString & def, bool * exist) { if (vname.isEmpty()) { _empty.clear(); _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } QStringList tree = vname.split(delim); QString name = tree.front(); tree.pop_front(); Entry * ce = 0; foreach(Entry * i, *this) if (i->_name == name) { ce = i; break; } if (ce == 0) { _empty._name = vname; _empty._value = def; _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } foreach(QString i, tree) { ce = ce->findChild(i); if (ce == 0) { _empty._name = vname; _empty._value = def; _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } } if (exist != 0) *exist = true; return *ce; } QPIConfig::Branch QPIConfig::Branch::getValues(const QString & name) { Branch b; b.delim = delim; foreach(Entry * i, *this) { if (i->isLeaf()) { if (i->_name.indexOf(name) >= 0) b << i; } else { foreach(Entry * j, i->_children) if (j->_name.indexOf(name) >= 0) b << j; } } return b; } QPIConfig::Branch QPIConfig::Branch::getLeaves() { Branch b; b.delim = delim; foreach(Entry * i, *this) if (i->isLeaf()) b << i; return b; } QPIConfig::Branch QPIConfig::Branch::getBranches() { Branch b; b.delim = delim; foreach(Entry * i, *this) if (!i->isLeaf()) b << i; return b; } QPIConfig::Branch & QPIConfig::Branch::filter(const QString & f) { for (int i = 0; i < size(); ++i) { if (at(i)->_name.indexOf(f) < 0) { remove(i); --i; } } return *this; } bool QPIConfig::Branch::entryExists(const Entry * e, const QString & name) const { if (e->_children.isEmpty()) { if (e->_name == name) return true; else return false; } foreach(Entry * i, e->_children) if (entryExists(i, name)) return true; return false; } QPIConfig::Entry & QPIConfig::Entry::getValue(const QString & vname, const QString & def, bool * exist) { QStringList tree = vname.split(delim); Entry * ce = this; foreach(QString i, tree) { ce = ce->findChild(i); if (ce == 0) { _empty._name = vname; _empty._value = def; _empty.delim = delim; if (exist != 0) *exist = false; return _empty; } } if (exist != 0) *exist = true; return *ce; } QPIConfig::Branch QPIConfig::Entry::getValues(const QString & vname) { Branch b; b.delim = delim; foreach(Entry * i, _children) if (i->_name.indexOf(vname) >= 0) b << i; return b; }; bool QPIConfig::Entry::entryExists(const Entry * e, const QString & name) const { if (e->_children.isEmpty()) { if (e->_name == name) return true; else return false; } foreach(Entry * i, e->_children) if (entryExists(i, name)) return true; return false; } QPIConfig::QPIConfig(const QString & path, QIODevice::OpenMode mode, QPIConfig::FileType type_): QFile(path) { init(); type = type_; if (!path.isEmpty()) { open(mode); incdirs << QFileInfo(path).absoluteDir().path(); parse(); } } QPIConfig::QPIConfig(const QString & path, QIODevice::OpenMode mode): QFile(path) { init(); type = Config; if (!path.isEmpty()) { open(mode); incdirs << QFileInfo(path).absoluteDir().path(); parse(); } } QPIConfig::QPIConfig(const QString & path, QPIConfig::FileType type_): QFile(path) { init(); type = type_; if (!path.isEmpty()) { open(QIODevice::ReadWrite); incdirs << QFileInfo(path).absoluteDir().path(); parse(); } } QPIConfig::QPIConfig(QString * str, QPIConfig::FileType type_) { init(); type = type_; buffer = str; parse(); } QPIConfig::QPIConfig(const QString & path, QStringList dirs) { init(); type = Config; internal = true; dev = new QFile(path); dev->open(QIODevice::ReadOnly); incdirs = dirs; incdirs << QFileInfo(path).absoluteDir().path(); QString cp = path; while (!dev->isOpen()) { if (dirs.isEmpty()) break; cp = dirs.back(); if (cp.endsWith("/") || cp.endsWith("\\")) cp.chop(1); cp += "/" + path; dev->setFileName(cp); dev->open(QIODevice::ReadOnly); dirs.pop_back(); } if (!dev->isOpen()) { delete dev; dev = 0; return; } dev->close(); setupCodec(); setFileName(cp); open(QIODevice::ReadOnly); parse(); } QPIConfig::~QPIConfig() { stream.setDevice(0); root.deleteBranch(); foreach(QPIConfig * c, inc_devs) delete c; inc_devs.clear(); includes.clear(); } void QPIConfig::init() { internal = false; buffer = 0; dev = 0; delim = "."; root._name = "root"; root.delim = delim; empty.delim = delim; empty._parent = 0; } void QPIConfig::setFile(const QString & path, QIODevice::OpenMode mode) { buffer = 0; setFileName(path); if (open(mode)) parse(); } void QPIConfig::setString(QString * str) { buffer = str; parse(); } void QPIConfig::setCodec(const char * codecName) { codec = codecName; setupCodec(); parse(); } void QPIConfig::setupCodec() { #if QT_VERSION_MAJOR <= 5 stream.setCodec(codec.toLatin1().data()); #else QString cn = codec.toLower().remove(' ').remove('-').trimmed(); QStringConverter::Encoding sc = QStringConverter::System; if (cn == "utf8") sc = QStringConverter::Utf8; else if (cn == "utf16") sc = QStringConverter::Utf16; stream.setEncoding(sc); #endif } QPIConfig::Entry & QPIConfig::getValue(const QString & vname, const QString & def, bool * exist) { QStringList tree = vname.split(delim); Entry * ce = &root; foreach(QString i, tree) { ce = ce->findChild(i); if (ce == 0) { if (exist != 0) *exist = false; empty._name = vname; empty._value = def; empty.delim = delim; return empty; } } if (exist != 0) *exist = true; return *ce; } QPIConfig::Branch QPIConfig::getValues(const QString & vname) { Branch b; b.delim = delim; foreach(Entry * i, root._children) if (i->_name.indexOf(vname) >= 0) b << i; return b; } QPIConfig::Entry & QPIConfig::addEntry(const QString & name, const QString & value, const QString & type, bool write, bool node) { if (getValue(name)._parent != 0) return empty; QString sn = name, tn; bool toRoot = false; while (sn.indexOf(delim) == 0) sn.remove(0, delim.length()); QStringList tree = sn.split(delim); QString ename = tree.back(); tn = tree.front(); tree.pop_back(); Entry *te, *ce, *entry = &root; if (tree.isEmpty()) toRoot = true; foreach(QString i, tree) { te = entry->findChild(i); if (te == 0) { ce = new Entry(); ce->delim = delim; ce->_tab = entry->_tab; ce->_line = entry->_line; ce->_name = i; ce->_parent = entry; // qDebug() << " [QPIC] add " + tn; ce->_full_name = tn; entry->_children << ce; entry = ce; } else entry = te; tn += delim + i; } QPIConfig::Branch ch = entry->_children; #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) qSort #else std::sort #endif (ch.begin(), ch.end(), QPIConfig::Entry::compare); te = (entry->isLeaf() ? 0 : ch.back()); ce = new Entry(); ce->delim = delim; ce->_name = ename; if (!node) ce->_value = value; ce->_type = type; if (te == 0) { // qDebug() << "[QPIC] te == 0"; ce->_tab = entry->_tab; if (toRoot) ce->_line = other.size(); else { ch = entry->_parent->_children; #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) qSort #else std::sort #endif (ch.begin(), ch.end(), QPIConfig::Entry::compare); ce->_line = ch.back()->_line + 1; } } else { ce->_tab = te->_tab; if (toRoot) ce->_line = other.size(); else ce->_line = te->_line + 1; } // qDebug() << "[QPIC] add " + sn + " at line " << ce->_line << ", parent " << entry->_name; ce->_full_name = sn; ce->_parent = entry; entry->_children << ce; // qDebug() << "[QPIC] children " << entry->childCount(); if (!node) { other.insert(ce->_line, ""); Branch b = allLeaves(); // qDebug() << "[QPIC] allLeaves " << b.size(); bool found = false; for (int i = 0; i < b.size(); ++i) { if (found) { b[i]->_line++; continue; } if (b[i] == ce) { found = true; if (i > 0) if (b[i - 1]->_line == b[i]->_line) b[i - 1]->_line++; } // qDebug() << b[i]->_line; } } // qDebug() << "[QPIC] add " + sn + " at line " << ce->_line << ", parent " + entry->_name; if (write) writeAll(); return *ce; } void QPIConfig::setValue(const QString & name, const QString & value, const QString & type, bool write) { Entry & e(getValue(name)); if (&e == &empty) { addEntry(name, value, type, write); return; } e._value = value; e._type = type; if (write) writeAll(); } QPIConfig::Branch QPIConfig::allLeaves() { Branch b; allLeaves(b, &root); #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) qSort #else std::sort #endif (b.begin(), b.end(), Entry::compare); return b; } int QPIConfig::entryIndex(const QString & name) { QStringList tree = name.split(delim); Entry * ce = &root; foreach(QString i, tree) { ce = ce->findChild(i); if (ce == 0) return -1; } Branch b = allLeaves(); return allLeaves().indexOf(ce); } void QPIConfig::setValue(uint number, const QString & value, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._value = value; if (write) writeAll(); } void QPIConfig::setName(uint number, const QString & name, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._name = name; if (write) writeAll(); } void QPIConfig::setType(uint number, const QString & type, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._type = type; if (write) writeAll(); } void QPIConfig::setComment(uint number, const QString & comment, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; e._comment = comment; if (write) writeAll(); } void QPIConfig::removeEntry(const QString & name, bool write) { Entry & e(getValue(name)); if (&e == &empty) return; Branch b = allLeaves(); removeEntry(b, &e); if (write) writeAll(); } void QPIConfig::removeEntry(uint number, bool write) { Entry & e(entryByIndex(number)); if (&e == &empty) return; Branch b = allLeaves(); removeEntry(b, &e); if (write) writeAll(); } void QPIConfig::removeEntry(Branch & b, QPIConfig::Entry * e) { bool leaf = true; // qDebug() << " before " << b.size(); if (e->isLeaf()) other.removeAt(e->_line); if (!e->isLeaf() && !e->_value.isEmpty()) { e->_value.clear(); } else { int cc = e->_children.size(); for (int i = 0; i < cc; ++i) removeEntry(b, e->_children.back()); } bool found = false; for (int i = 0; i < b.size(); ++i) { if (found) { b[i]->_line--; continue; } if (b[i] == e) found = true; } if (!leaf) return; int ti = e->_parent->_children.indexOf(e); if (ti >= 0) e->_parent->_children.remove(ti); ti = b.indexOf(e); if (ti >= 0) b.remove(ti); // qDebug() << " after " << b.size(); delete e; } void QPIConfig::writeAll() { if (buffer == 0) { stream.setDevice(this); resize(0); } else { stream.setString(buffer); buffer->clear(); } setupCodec(); stream.seek(0); buildFullNames(&root); Branch b = allLeaves(); QString prefix, tprefix; bool isPrefix; int j = 0; for (int i = 0; i < other.size(); ++i) { if (j >= 0 && j < b.size()) { if (b[j]->_line == i) { b[j]->buildLine(); stream << b[j]->_all << '\n'; ++j; } else { stream << other[i]; tprefix = getPrefixFromLine(other[i], &isPrefix); if (isPrefix) { prefix = tprefix; if (!prefix.isEmpty()) prefix += delim; } if (i < other.size() - 1) stream << '\n'; } } else { stream << other[i]; tprefix = getPrefixFromLine(other[i], &isPrefix); if (isPrefix) { prefix = tprefix; if (!prefix.isEmpty()) prefix += delim; } if (i < other.size() - 1) stream << '\n'; } } if (buffer == 0) flush(); readAll(); } QString QPIConfig::getPrefixFromLine(QString line, bool * exists) { line = line.trimmed(); if (line.left(1) == "#") { if (exists) *exists = false; return QString(); } int ci = line.indexOf("#"); if (ci >= 0) line = line.left(ci).trimmed(); if (line.indexOf("=") >= 0) { if (exists) *exists = false; return QString(); } if (line.indexOf("[") >= 0 && line.indexOf("]") >= 0) { if (exists) *exists = true; line.remove(0, 1); return line.left(line.lastIndexOf("]")).trimmed(); } if (exists) *exists = false; return QString(); } QString QPIConfig::writeAllToString() { QString str; QTextStream s(&str); buildFullNames(&root); Branch b = allLeaves(); int j = 0; for (int i = 0; i < other.size(); ++i) { if (j >= 0 && j < b.size()) { if (b[j]->_line == i) { b[j]->buildLine(); s << b[j]->_all << '\n'; ++j; } else { s << other[i]; if (i < other.size() - 1) s << '\n'; } } else { s << other[i]; if (i < other.size() - 1) s << '\n'; } } return str; } void QPIConfig::readAllFromString(const QString & str) { parse(str); } void QPIConfig::clear() { root.deleteBranch(); root.clear(); other.clear(); if (buffer == 0) resize(0); else buffer->clear(); stream.seek(0); } void QPIConfig::readAll() { if (buffer == 0) flush(); parse(); } bool QPIConfig::entryExists(const Entry * e, const QString & name) const { if (e->_children.isEmpty()) { if (e->_name == name) return true; else return false; } foreach(Entry * i, e->_children) if (entryExists(i, name)) return true; return false; } void QPIConfig::updateIncludes() { if (internal) return; all_includes.clear(); foreach(QPIConfig * c, includes) all_includes << c->allLeaves(); } QString QPIConfig::parseLine(QString v) { int i = -1, l = 0; while (1) { i = v.indexOf("${"); if (i < 0) break; l = v.indexOf("}", i + 1); QString w = v.mid(i + 2, l - i - 2), r; l = w.length() + 3; w = parseLine(w); w = w.trimmed(); bool ex = false; QPIConfig::Entry & me = getValue(w, "", &ex); if (ex) { r = me._value; } else { foreach(QPIConfig::Entry * e, all_includes) { if (e->_full_name == w) { r = e->_value; break; } } } v.replace(i, l, r); } return v; } void QPIConfig::parse(QString content) { root.deleteBranch(); root.clear(); QString src, str, tab, comm, all, name, type, prefix, tprefix; QStringList tree; Entry *entry = 0, *te = 0, *ce = 0; int ind, sind; bool isNew = false, isPrefix = false, wasMultiline = false, isMultiline = false; foreach(QPIConfig * c, inc_devs) delete c; inc_devs.clear(); includes.clear(); if (content.isEmpty()) { if (buffer == 0) { if (!isOpen()) return; stream.setDevice(this); } else stream.setString(buffer); } else { stream.setString(&content); } setupCodec(); stream.seek(0); other.clear(); lines = centry = 0; while (!stream.atEnd()) { other.push_back(QString()); src = str = parseLine(stream.readLine()); tprefix = getPrefixFromLine(src, &isPrefix); if (isPrefix) { prefix = tprefix; if (!prefix.isEmpty()) prefix += delim; } tab = str.left(str.indexOf(str.trimmed().left(1))); str = str.trimmed(); all = str; sind = str.indexOf('#'); if (sind > 0) { comm = str.mid(sind + 1).trimmed(); if (comm.length() > 0) { type = comm[0]; comm = comm.mid(1).trimmed(); } else type = "s"; str = str.left(sind).trimmed(); } else { type = "s"; comm = ""; } if (str.endsWith(" \\")) { isMultiline = true; str.chop(2); str = str.trimmed(); } else isMultiline = false; if (wasMultiline) { wasMultiline = false; if (ce) { ce->_value += str; ce->_all += " \\\n" + all; } str.clear(); } else ce = 0; wasMultiline = isMultiline; ind = str.indexOf('='); if ((ind > 0) && !(str[0] == '#')) { tree = (prefix + str.left(ind).trimmed()).split(delim); if (tree.front() == "include") { name = str.mid(ind + 1).trimmed(); QPIConfig * iconf = new QPIConfig(name, incdirs); if (!iconf->dev) { delete iconf; } else { inc_devs << iconf; includes << iconf << iconf->includes; updateIncludes(); } other.back() = src; } else { name = tree.back(); tree.pop_back(); entry = &root; foreach(QString i, tree) { te = entry->findChild(i); if (te == 0) { ce = new Entry(); ce->delim = delim; ce->_tab = tab; ce->_line = lines; ce->_name = i; ce->_parent = entry; entry->_children << ce; entry = ce; } else entry = te; } isNew = false; ce = entry->findChild(name); if (ce == 0) { ce = new Entry(); isNew = true; } ce->delim = delim; ce->_tab = tab; ce->_name = name; ce->_value = str.mid(ind + 1).trimmed(); ce->_type = type; ce->_comment = comm; ce->_line = lines; ce->_all = all; if (isNew) { ce->_parent = entry; entry->_children << ce; } } } else other.back() = src; lines++; } setEntryDelim(&root, delim); buildFullNames(&root); }