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 }