#include #include #include #include "smartpen.h" #include "replaydata.h" namespace { bool readUtfString(QDataStream &stream, QString &s) { quint16 len; stream >> len; QByteArray buffer(len, Qt::Uninitialized); if (stream.readRawData(buffer.data(), len) != len) { return false; } s = QString::fromUtf8(buffer); return true; } } ReplayData::ReplayData(QObject *parent) : QObject(parent) { } bool ReplayData::open(const QString &path) { _dir.setPath(path); if (!_dir.exists()) { return false; } QDirIterator iter(_dir.path(), QStringList("session.info"), QDir::Files, QDirIterator::Subdirectories); while (iter.hasNext()) { QFileInfo finfo(iter.next()); QDir sessionDir(finfo.path()); Session session; if (!parseSessionInfo(session, finfo.filePath())) { qWarning() << "Could not parse:" << finfo.absoluteFilePath(); } if (!parseSessionPages(session, sessionDir.filePath("session.pages"))) { qWarning() << "Could not parse:" << sessionDir.absoluteFilePath("session.pages"); } } return true; } bool ReplayData::parseSessionInfo(Session &session, const QString &path) { QFile f(path); if (f.open(QIODevice::ReadOnly)) { return parseSessionInfo(session, &f); } else { return false; } } bool ReplayData::parseSessionInfo(Session &session, QIODevice *dev) { unsigned char magic[2]; if (dev->read(reinterpret_cast(magic), 2) != 2 || magic[0] != 0xFA || magic[1] != 0xCE) { qWarning() << "Invalid magic"; return false; } char version = 0; if (!dev->getChar(&version)) { qWarning() << "Short read while getting version number"; return false; } switch (version) { case 3: return parseSessionInfoV3(session, dev); default: qWarning() << "Unknown version:" << version; return false; } } bool ReplayData::parseSessionInfoV3(Session &session, QIODevice *dev) { QDataStream s(dev); if (s.skipRawData(5) != 5) return false; qint64 startTime, endTime, creationTime; QString name; s >> startTime >> endTime >> creationTime; if (!readUtfString(s, name)) { return false; } qDebug() << "Name:" << name << Smartpen::fromPenTime(startTime) << Smartpen::fromPenTime(endTime) << creationTime; quint16 num_clips; s >> num_clips; for (uint i = 0; i < num_clips; ++i) { QString file; if (!readUtfString(s, file)) { return false; } s >> startTime >> endTime; qDebug() << " Clip:" << file << startTime << endTime; qDebug() << " " << QDateTime::fromTime_t(startTime) << QDateTime::fromTime_t(endTime); } quint16 num_strokes; s >> num_strokes; for (uint i = 0; i < num_strokes; ++i) { quint64 a, b, c; quint32 d; QString nbGuid; quint8 f, g; s >> a >> b >> c >> d; if (!readUtfString(s, nbGuid)) { return false; } s >> f >> g; qDebug() << " Stroke:" << a << b << c << d << nbGuid << f << g; } return true; } bool ReplayData::parseSessionPages(Session &session, const QString &path) { QFile f(path); if (f.open(QIODevice::ReadOnly)) { return parseSessionPages(session, &f); } else { return false; } } bool ReplayData::parseSessionPages(Session &session, QIODevice *dev) { unsigned char magic[2]; if (dev->read(reinterpret_cast(magic), 2) != 2 || magic[0] != 0xCA || magic[1] != 0xBE) { qWarning() << "Invalid magic"; return false; } char version = 0; if (!dev->getChar(&version)) { qWarning() << "Short read while getting version number"; return false; } switch (version) { case 1: return parseSessionPagesV1(session, dev); default: qWarning() << "Unknown version:" << version; return false; } } bool ReplayData::parseSessionPagesV1(Session &session, QIODevice *dev) { QDataStream s(dev); if (s.skipRawData(1) != 1) return false; quint16 num_pages = 0; s >> num_pages; session.pages.reserve(session.pages.size() + num_pages); for (uint i = 0; i < num_pages; ++i) { quint64 address, unk; s >> address >> unk; session.pages.append(address); qDebug() << " Page:" << address << unk; } return true; }