File indexing completed on 2024-04-28 04:40:02

0001 #include "leinputstream.h"
0002 #include "pole.h"
0003 #include <QBuffer>
0004 #include <QCoreApplication>
0005 #include <QXmlStreamWriter>
0006 #include <QDebug>
0007 #include <QFile>
0008 #include <QMap>
0009 #include <QTextStream>
0010 #include <QStringList>
0011 #include <QCoreApplication>
0012 #include <QDomDocument>
0013 
0014 #include <cstdio>
0015 
0016 using namespace std;
0017 
0018 class RecordType {
0019 public:
0020     QString name;
0021     QList<int> rectInstances;
0022 };
0023 
0024 QString
0025 getRecordNameString(const QList<RecordType>& rts, quint16 recInstance) {
0026     QString name;
0027     foreach (const RecordType& rt, rts) {
0028         if (rt.rectInstances.size() == 0 || rt.rectInstances.contains(recInstance)) {
0029             if (name.isNull()) {
0030                 name = rt.name;
0031             } else {
0032                 name += "/" + rt.name;
0033             }
0034         }
0035     }
0036     return name;
0037 }
0038 
0039 void
0040 printStructure(LEInputStream& in, int depth, QTextStream& out,
0041         const QMap<int, QList<RecordType> >& recordTypeNames) {
0042     quint8 recVer = in.readuint4();
0043     quint16 recInstance = in.readuint12();
0044     quint16 recType = in.readuint16();
0045     quint32 recLen = in.readuint32();
0046 
0047     QString hexinstance = QString::number(recInstance, 16);
0048     QString hextype = QString::number(recType, 16);
0049     QString t = "\t";
0050     QString recordTypeName = getRecordNameString(recordTypeNames.value(recType),
0051         recInstance);
0052     out << depth << t << recVer << t << hexinstance << t << hextype << t << recLen << t << in.getPosition() << t << recordTypeName << endl;
0053 
0054     if ((recVer == 0xF && recType != 0x428) || recType == 0x138B) {
0055         int end = in.getPosition() + recLen;
0056         while (in.getPosition() != end) {
0057             if (in.getPosition() > end) {
0058                 throw IOException("structure is too long");
0059             }
0060             printStructure(in, depth + 1, out, recordTypeNames);
0061         }
0062     } else {
0063         in.skip(recLen);
0064     }
0065 }
0066 
0067 bool
0068 parse(const QString& file, const QMap<int, QList<RecordType> >& recordTypeNames) {
0069     QFile out;
0070     out.open(stdout, QIODevice::WriteOnly);
0071     QTextStream textout(&out);
0072     POLE::Storage storage(file.toLocal8Bit());
0073     if (!storage.open()) return false;
0074 
0075     string prefix;
0076     if (storage.isDirectory("PP97_DUALSTORAGE")) {
0077         prefix = "PP97_DUALSTORAGE/";
0078     } else {
0079         prefix = "/";
0080     }
0081     list<string> entries = storage.entries(prefix);
0082     for (list<string>::const_iterator i=entries.begin(); i!=entries.end(); ++i) {
0083         if (!storage.isDirectory(prefix+*i)) {
0084             try {
0085                 POLE::Stream stream(&storage, prefix+*i);
0086                 QString streamname(QString::fromStdString(*i));
0087                 textout << "Stream '" << streamname << "' of size "
0088                         << stream.size() << ":" << endl;
0089                 QByteArray array;
0090                 array.resize(stream.size());
0091                 unsigned long read = stream.read((unsigned char*)array.data(), stream.size());
0092                 if (read != stream.size()) {
0093                     qDebug() << "Error reading stream " << streamname;
0094                     return false;
0095                 }
0096                 QBuffer buffer;
0097                 buffer.setData(array);
0098                 buffer.open(QIODevice::ReadOnly);
0099                 LEInputStream listream(&buffer);
0100                 while (listream.getPosition() != buffer.size()) {
0101                     printStructure(listream, 0, textout, recordTypeNames);
0102                 }
0103             } catch (IOException& e) {
0104                 qDebug() << "Error: " << e.msg;
0105             }
0106         }
0107     }
0108     return true;
0109 }
0110 QList<int>
0111 getNumbers(const QString& value) {
0112     QList<int> numbers;
0113     foreach (QString s, value.split("|")) {
0114         int base = 10;
0115         if (s.startsWith("0x")) {
0116             s.replace("0x", "");
0117             base = 16;
0118         }
0119         bool ok;
0120         int value = s.toInt(&ok, base);
0121         if (!ok) return QList<int>();
0122         numbers.append(value);
0123     }
0124     return numbers;
0125 }
0126 
0127 QMap<int, QList<RecordType> >
0128 getRecordTypeNames(const QString& filename) {
0129     QDomDocument dom;
0130     QFile f(filename);
0131     f.open(QIODevice::ReadOnly);
0132     dom.setContent(&f);
0133 
0134     QMap<int, QList<RecordType> > map;
0135     QDomNodeList structs = dom.elementsByTagName("struct");
0136     for (int i=0; i<structs.count(); ++i) {
0137         QDomElement s = structs.item(i).toElement();
0138         QDomElement rh = s.elementsByTagName("type").item(0).toElement();
0139         if (rh.isNull() || rh.attribute("name") != "rh") continue;
0140         QList<int> typeNumbers;
0141         RecordType rt;
0142         rt.name = s.attribute("name");
0143         QDomNodeList limits = rh.elementsByTagName("limitation");
0144         for (int i=0; i<limits.count(); ++i) {
0145             QDomElement l = limits.item(i).toElement();
0146             if (l.attribute("name") == "recType") {
0147                 typeNumbers = getNumbers(l.attribute("value"));
0148             } else if (l.attribute("name") == "recInstance") {
0149                 rt.rectInstances = getNumbers(l.attribute("value"));
0150             }
0151         }
0152         foreach (int typeNumber, typeNumbers) {
0153             map[typeNumber].append(rt);
0154         }
0155     }
0156 
0157     return map;
0158 }
0159 
0160 int
0161 main(int argc, char** argv) {
0162     QCoreApplication app(argc, argv);
0163     //if (argc < 2) return -1;
0164 
0165     const QMap<int, QList<RecordType> > recordTypeNames
0166         = getRecordTypeNames(":/src/mso.xml");
0167 
0168     for (int i=1; i<argc; ++i) {
0169         QString file(argv[i]);
0170         qDebug() << "Parsing of " << file;
0171         if (parse(file, recordTypeNames)) {
0172             qDebug() << "Parsing of " << file << " succeedded.";
0173         } else {
0174             qDebug() << "Parsing of " << file << " failed.";
0175         }
0176     }
0177 
0178     return 0;
0179 }