916ef3e by Jos van den Oever at 2009-09-16 1
#include "leinputstream.h"
2
#include "pole.h"
3
#include <QBuffer>
4
#include <QCoreApplication>
5
#include <QXmlStreamWriter>
6
#include <QDebug>
7
#include <QFile>
8
#include <QMap>
9
#include <QTextStream>
10
#include <QStringList>
caa1df7 by Jos van den Oever at 2009-09-17 11
#include <QCoreApplication>
916ef3e by Jos van den Oever at 2009-09-16 12
#include <QDomDocument>
13
14
#include <cstdio>
15
16
using namespace std;
17
00655b1 by Jos van den Oever at 2010-01-24 18
class RecordType {
19
public:
20
    QString name;
21
    QList<int> rectInstances;
22
};
23
24
QString
25
getRecordNameString(const QList<RecordType>& rts, quint16 recInstance) {
26
    QString name;
27
    foreach (const RecordType& rt, rts) {
28
        if (rt.rectInstances.size() == 0 || rt.rectInstances.contains(recInstance)) {
29
            if (name.isNull()) {
30
                name = rt.name;
31
            } else {
32
                name += "/" + rt.name;
33
            }
34
        }
35
    }
36
    return name;
37
}
38
916ef3e by Jos van den Oever at 2009-09-16 39
void
40
printStructure(LEInputStream& in, int depth, QTextStream& out,
00655b1 by Jos van den Oever at 2010-01-24 41
        const QMap<int, QList<RecordType> >& recordTypeNames) {
916ef3e by Jos van den Oever at 2009-09-16 42
    quint8 recVer = in.readuint4();
43
    quint16 recInstance = in.readuint12();
44
    quint16 recType = in.readuint16();
45
    quint32 recLen = in.readuint32();
46
47
    QString hexinstance = QString::number(recInstance, 16);
48
    QString hextype = QString::number(recType, 16);
49
    QString t = "\t";
00655b1 by Jos van den Oever at 2010-01-24 50
    QString recordTypeName = getRecordNameString(recordTypeNames.value(recType),
51
        recInstance);
52
    out << depth << t << recVer << t << hexinstance << t << hextype << t << recLen << t << in.getPosition() << t << recordTypeName << endl;
916ef3e by Jos van den Oever at 2009-09-16 53
631e40e by Jos van den Oever at 2010-03-15 54
    if ((recVer == 0xF && recType != 0x428) || recType == 0x138B) {
916ef3e by Jos van den Oever at 2009-09-16 55
        int end = in.getPosition() + recLen;
56
        while (in.getPosition() != end) {
57
            if (in.getPosition() > end) {
58
                throw IOException("structure is too long");
59
            }
60
            printStructure(in, depth + 1, out, recordTypeNames);
61
        }
62
    } else {
63
        in.skip(recLen);
64
    }
65
}
66
67
bool
00655b1 by Jos van den Oever at 2010-01-24 68
parse(const QString& file, const QMap<int, QList<RecordType> >& recordTypeNames) {
916ef3e by Jos van den Oever at 2009-09-16 69
    QFile out;
70
    out.open(stdout, QIODevice::WriteOnly);
71
    QTextStream textout(&out);
72
    POLE::Storage storage(file.toLocal8Bit());
73
    if (!storage.open()) return false;
74
75
    string prefix;
76
    if (storage.isDirectory("PP97_DUALSTORAGE")) {
77
        prefix = "PP97_DUALSTORAGE/";
78
    } else {
79
        prefix = "/";
80
    }
81
    list<string> entries = storage.entries(prefix);
82
    for (list<string>::const_iterator i=entries.begin(); i!=entries.end(); ++i) {
83
        if (!storage.isDirectory(prefix+*i)) {
84
            try {
85
                POLE::Stream stream(&storage, prefix+*i);
86
                QString streamname(QString::fromStdString(*i));
52211d1 by Jos van den Oever at 2010-04-06 87
                textout << "Stream '" << streamname << "' of size "
88
                        << stream.size() << ":" << endl;
916ef3e by Jos van den Oever at 2009-09-16 89
                QByteArray array;
90
                array.resize(stream.size());
91
                unsigned long read = stream.read((unsigned char*)array.data(), stream.size());
92
                if (read != stream.size()) {
93
                    qDebug() << "Error reading stream " << streamname;
94
                    return false;
95
                }
96
                QBuffer buffer;
97
                buffer.setData(array);
98
                buffer.open(QIODevice::ReadOnly);
99
                LEInputStream listream(&buffer);
100
                while (listream.getPosition() != buffer.size()) {
101
                    printStructure(listream, 0, textout, recordTypeNames);
102
                }
103
            } catch (IOException& e) {
104
                qDebug() << "Error: " << e.msg;
105
            }
106
        }
107
    }
108
    return true;
109
}
00655b1 by Jos van den Oever at 2010-01-24 110
QList<int>
111
getNumbers(const QString& value) {
112
    QList<int> numbers;
113
    foreach (QString s, value.split("|")) {
114
        int base = 10;
115
        if (s.startsWith("0x")) {
116
            s.replace("0x", "");
117
            base = 16;
118
        }
119
        bool ok;
120
        int value = s.toInt(&ok, base);
121
        if (!ok) return QList<int>();
122
        numbers.append(value);
123
    }
124
    return numbers;
125
}
916ef3e by Jos van den Oever at 2009-09-16 126
00655b1 by Jos van den Oever at 2010-01-24 127
QMap<int, QList<RecordType> >
916ef3e by Jos van den Oever at 2009-09-16 128
getRecordTypeNames(const QString& filename) {
129
    QDomDocument dom;
130
    QFile f(filename);
131
    f.open(QIODevice::ReadOnly);
132
    dom.setContent(&f);
133
00655b1 by Jos van den Oever at 2010-01-24 134
    QMap<int, QList<RecordType> > map;
135
    QDomNodeList structs = dom.elementsByTagName("struct");
136
    for (int i=0; i<structs.count(); ++i) {
137
        QDomElement s = structs.item(i).toElement();
138
        QDomElement rh = s.elementsByTagName("type").item(0).toElement();
139
        if (rh.isNull() || rh.attribute("name") != "rh") continue;
140
        QList<int> typeNumbers;
141
        RecordType rt;
142
        rt.name = s.attribute("name");
143
        QDomNodeList limits = rh.elementsByTagName("limitation");
144
        for (int i=0; i<limits.count(); ++i) {
145
            QDomElement l = limits.item(i).toElement();
146
            if (l.attribute("name") == "recType") {
147
                typeNumbers = getNumbers(l.attribute("value"));
148
            } else if (l.attribute("name") == "recInstance") {
149
                rt.rectInstances = getNumbers(l.attribute("value"));
916ef3e by Jos van den Oever at 2009-09-16 150
            }
151
        }
00655b1 by Jos van den Oever at 2010-01-24 152
        foreach (int typeNumber, typeNumbers) {
153
            map[typeNumber].append(rt);
154
        }
916ef3e by Jos van den Oever at 2009-09-16 155
    }
156
157
    return map;
158
}
159
160
int
161
main(int argc, char** argv) {
162
    QCoreApplication app(argc, argv);
163
    //if (argc < 2) return -1;
164
00655b1 by Jos van den Oever at 2010-01-24 165
    const QMap<int, QList<RecordType> > recordTypeNames
5c7f973 by Jos van den Oever at 2009-09-22 166
        = getRecordTypeNames(":/src/mso.xml");
916ef3e by Jos van den Oever at 2009-09-16 167
168
    for (int i=1; i<argc; ++i) {
169
        QString file(argv[i]);
170
        qDebug() << "Parsing of " << file;
171
        if (parse(file, recordTypeNames)) {
172
            qDebug() << "Parsing of " << file << " succeedded.";
173
        } else {
174
            qDebug() << "Parsing of " << file << " failed.";
175
        }
176
    }
177
178
    return 0;
179
}