File indexing completed on 2024-04-28 04:40:03
0001 #include "utils.h" 0002 #include "pole.h" 0003 #include "leinputstream.h" 0004 #include "leoutputstream.h" 0005 #include <QByteArray> 0006 #include <QBuffer> 0007 #include <QFile> 0008 #include <QXmlStreamWriter> 0009 #include <QDebug> 0010 0011 using namespace std; 0012 0013 QByteArray 0014 escapeByteArray(const QByteArray& b) { 0015 // we escape all non printable byte values 0016 // printable is 9, 10, 13, 32-126 0017 QByteArray exclude(96, ' '); 0018 exclude[0] = 9; exclude[1] = 10; exclude[2] = 13; 0019 for (int i=3; i<8; ++i) { 0020 exclude[i] = i+29; 0021 } 0022 for (int i=8; i<96; ++i) { 0023 exclude[i] = i+30; 0024 } 0025 0026 QByteArray result = b.toPercentEncoding(exclude); 0027 if (QByteArray::fromPercentEncoding(result) != b) { 0028 qDebug() << "Escaping of bytearray " << b << " is not reversible."; 0029 exit(1); 0030 } 0031 return result; 0032 } 0033 0034 QVector<quint16> 0035 toUInt16Vector(const QString& s) { 0036 QVector<quint16> v; 0037 QString z = QString::fromUtf8(QByteArray::fromPercentEncoding(s.toUtf8())); 0038 v.resize(z.size()); 0039 for (int i=0; i<z.size(); ++i) { 0040 v[i] = z.utf16()[i]; 0041 } 0042 return v; 0043 } 0044 0045 QString 0046 toString(const QVector<quint16>& v) { 0047 QString s; 0048 foreach(quint16 c, v) { 0049 s.append(c); 0050 } 0051 s = QString::fromUtf8(escapeByteArray(s.toUtf8())); 0052 // TODO: implement and check reversibility 0053 /* 0054 if (toUInt16Vector(s) != v) { 0055 qDebug() << "Escaping of string " << v << " is not reversible."; 0056 qDebug() << toUInt16Vector(s); 0057 exit(1); 0058 } 0059 */ 0060 return s; 0061 } 0062 0063 void 0064 print(QXmlStreamWriter& out, const Introspectable* i) { 0065 const Introspection* is = i->getIntrospection(); 0066 for (int j=0; j<is->numberOfMembers; ++j) { 0067 for (int k=0; k<is->numberOfInstances[j](i); ++k) { 0068 out.writeStartElement(is->names[j]); 0069 const Introspectable* ci = is->introspectable[j](i, k); 0070 if (ci) { 0071 QString type = ci->getIntrospection()->name; 0072 out.writeAttribute("type", type); 0073 uint32_t offset = ci->streamOffset; 0074 out.writeAttribute("offset", QString::number(offset)); 0075 print(out, ci); 0076 } else { 0077 QVariant v(is->value[j](i, k)); 0078 if (v.canConvert<QVector<quint16> >()) { 0079 out.writeCharacters(toString(v.value<QVector<quint16> >())); 0080 } else { 0081 if (v.type() == QVariant::ByteArray) { 0082 v = escapeByteArray(v.toByteArray()); 0083 } 0084 out.writeCharacters(v.toString()); 0085 } 0086 } 0087 out.writeEndElement(); 0088 } 0089 } 0090 } 0091 0092 QMap<QString, QByteArray> 0093 readStreams(const QString& file) { 0094 QMap<QString, QByteArray> streams; 0095 POLE::Storage storage(file.toLocal8Bit()); 0096 if (!storage.open()) return streams; 0097 0098 // TODO add support for directories 0099 string prefix = "/"; 0100 list<string> entries = storage.entries(prefix); 0101 for (list<string>::const_iterator i=entries.begin(); i!=entries.end(); ++i){ 0102 string path(prefix+*i); 0103 if (!storage.isDirectory(path)) { 0104 POLE::Stream stream(&storage, path); 0105 QString streamname(QString::fromStdString(*i)); 0106 QByteArray array; 0107 array.resize(stream.size()); 0108 unsigned long read = stream.read((unsigned char*)array.data(), 0109 stream.size()); 0110 if (read != stream.size()) { 0111 qDebug() << "Error reading stream " << streamname; 0112 streams.clear(); 0113 return streams; 0114 } 0115 streams[path.c_str()] = array; 0116 } 0117 } 0118 0119 return streams; 0120 } 0121 0122 QMap<QString, QSharedPointer<const Introspectable> > 0123 parseStreams(const QMap<QString, QByteArray>& streams) { 0124 QMap<QString, QSharedPointer<const Introspectable> > result; 0125 QMap<QString, QByteArray>::const_iterator i; 0126 for (i = streams.begin(); i!= streams.end(); ++i) { 0127 const QString streampath(i.key()); 0128 const QString streamname = streampath.mid(streampath.lastIndexOf('/')+1); 0129 const QByteArray array(i.value()); 0130 QBuffer buffer; 0131 buffer.setData(array); 0132 buffer.open(QIODevice::ReadOnly); 0133 LEInputStream listream(&buffer); 0134 qDebug() << "Parsing stream '" << streampath << "'"; 0135 0136 const Introspectable* i; 0137 try { 0138 i = parse(streamname, listream); 0139 } catch (IOException& e) { 0140 qDebug() << "Error: " << e.msg; 0141 continue; 0142 } 0143 0144 if (listream.getPosition() != (qint64)array.size()) { 0145 qDebug() << array.size() - listream.getPosition() 0146 << "trailing bytes in stream " << streampath; 0147 result.clear(); 0148 return result; 0149 } 0150 buffer.close(); 0151 0152 // test if serialization gives the same bytearray as that which came in 0153 buffer.buffer().clear(); 0154 buffer.open(QIODevice::WriteOnly); 0155 LEOutputStream lostream(&buffer); 0156 serialize(i, streamname, lostream); 0157 if (array != buffer.data()) { 0158 qDebug() << "Serialized data different from original in " 0159 << streampath; 0160 } 0161 0162 result[streampath] = QSharedPointer<const Introspectable>(i); 0163 } 0164 return result; 0165 } 0166 0167 QMap<QString, QByteArray> 0168 serialize(const QMap<QString, QSharedPointer<const Introspectable> >& m) { 0169 QMap<QString, QByteArray> streams; 0170 QMap<QString, QSharedPointer<const Introspectable> >::const_iterator i; 0171 for (i = m.begin(); i!= m.end(); ++i) { 0172 const QString streampath(i.key()); 0173 const QString streamname 0174 = streampath.mid(streampath.lastIndexOf('/')+1); 0175 QBuffer buffer; 0176 buffer.open(QIODevice::WriteOnly); 0177 LEOutputStream lostream(&buffer); 0178 const Introspectable* is = i.value().data(); 0179 serialize(is, streamname, lostream); 0180 streams[streampath] = buffer.data(); 0181 } 0182 return streams; 0183 } 0184 0185 void 0186 write(const QString& name, const QByteArray& data) { 0187 QFile out(name); 0188 out.open(QIODevice::WriteOnly); 0189 out.write(data); 0190 out.close(); 0191 } 0192 0193 void printWithExtendedParser(QXmlStreamWriter& out, const Introspectable* i); 0194 0195 void 0196 printStyleTextPropAtom(QXmlStreamWriter& out, const Introspectable* i, 0197 int characterCount) { 0198 const Introspection* is = i->getIntrospection(); 0199 0200 // rh 0201 const Introspectable* ci = is->introspectable[0](i, 0); 0202 out.writeStartElement(is->names[0]); 0203 QString type = ci->getIntrospection()->name; 0204 out.writeAttribute("type", type); 0205 printWithExtendedParser(out, is->introspectable[0](i, 0)); // rh 0206 out.writeEndElement(); 0207 0208 // styles 0209 QByteArray blob = is->value[1](i, 0).toByteArray(); 0210 QBuffer buffer; 0211 buffer.setData(blob); 0212 buffer.open(QIODevice::ReadOnly); 0213 LEInputStream listream(&buffer); 0214 0215 try { 0216 int sum = 0; 0217 do { 0218 ci = parse("textPFRun", listream); 0219 const Introspection* cis = ci->getIntrospection(); 0220 sum += cis->value[0](ci, 0).toInt(); 0221 out.writeStartElement("rgTextPFRun"); 0222 out.writeAttribute("type", "TextPFRun"); 0223 printWithExtendedParser(out, ci); 0224 //qDebug() << "PF " << characterCount << " " << cis->value[0](ci, 0).toInt() << " " << sum; 0225 delete ci; 0226 out.writeEndElement(); 0227 } while (sum <= characterCount); 0228 sum = 0; 0229 do { 0230 ci = parse("textCFRun", listream); 0231 const Introspection* cis = ci->getIntrospection(); 0232 sum += cis->value[0](ci, 0).toInt(); 0233 out.writeStartElement("rgTextCFRun"); 0234 out.writeAttribute("type", "TextCFRun"); 0235 printWithExtendedParser(out, ci); 0236 //qDebug() << "CF " << characterCount << " " << cis->value[0](ci, 0).toInt() << " " << sum; 0237 delete ci; 0238 out.writeEndElement(); 0239 } while (sum <= characterCount); 0240 } catch (IOException& e) { 0241 qDebug() << "Error: " << e.msg; 0242 } 0243 if (buffer.size() != listream.getPosition()) { 0244 qDebug() << "Error: " << buffer.size() - listream.getPosition() 0245 << " bytes left for StyleTextPropAtom at position " 0246 << i->streamOffset; 0247 } 0248 } 0249 0250 void 0251 printWithExtendedParser(QXmlStreamWriter& out, const Introspectable* i) { 0252 int lastCharacterCount = 0; // needed for parsing StyleTextPropAtom 0253 0254 const Introspection* is = i->getIntrospection(); 0255 for (int j=0; j<is->numberOfMembers; ++j) { 0256 for (int k=0; k<is->numberOfInstances[j](i); ++k) { 0257 out.writeStartElement(is->names[j]); 0258 const Introspectable* ci = is->introspectable[j](i, k); 0259 if (ci) { 0260 QString type = ci->getIntrospection()->name; 0261 out.writeAttribute("type", type); 0262 uint32_t offset = ci->streamOffset; 0263 out.writeAttribute("offset", QString::number(offset)); 0264 if (type == "StyleTextPropAtom") { 0265 // StyleTextPropAtom is currently too hard to parse by the generated code 0266 printStyleTextPropAtom(out, ci, lastCharacterCount); 0267 } else if (type == "TextCharsAtom") { 0268 const Introspection* cis = ci->getIntrospection(); 0269 lastCharacterCount = cis->value[1](ci, 0).value<QVector<quint16> >().count(); 0270 printWithExtendedParser(out, ci); 0271 } else if (type == "TextBytesAtom") { 0272 const Introspection* cis = ci->getIntrospection(); 0273 lastCharacterCount = cis->value[1](ci, 0).toByteArray().count(); 0274 printWithExtendedParser(out, ci); 0275 } else { 0276 printWithExtendedParser(out, ci); 0277 } 0278 } else { 0279 QVariant v(is->value[j](i, k)); 0280 if (v.canConvert<QVector<quint16> >()) { 0281 out.writeCharacters(toString(v.value<QVector<quint16> >())); 0282 } else { 0283 if (v.type() == QVariant::ByteArray) { 0284 v = escapeByteArray(v.toByteArray()); 0285 } 0286 out.writeCharacters(v.toString()); 0287 } 0288 } 0289 out.writeEndElement(); 0290 } 0291 } 0292 } 0293 0294 QByteArray 0295 streamsToXml( 0296 const QMap<QString, QSharedPointer<const Introspectable> >& streams, 0297 void (*printFunction)(QXmlStreamWriter&,const Introspectable*)) { 0298 QBuffer xml; 0299 xml.open(QBuffer::WriteOnly); 0300 QXmlStreamWriter xmlout(&xml); 0301 xmlout.setAutoFormatting(true); 0302 xmlout.writeStartDocument(); 0303 xmlout.writeStartElement("ppt"); 0304 QMap<QString, QSharedPointer<const Introspectable> >::const_iterator i; 0305 for (i = streams.begin(); i!= streams.end(); ++i) { 0306 const Introspection* in = i.value()->getIntrospection(); 0307 xmlout.writeStartElement(in->name); 0308 xmlout.writeAttribute("stream-path", i.key()); 0309 if (in->name != "TODOS") { 0310 printFunction(xmlout, i.value().data()); 0311 } 0312 xmlout.writeEndElement(); 0313 } 0314 xmlout.writeEndElement(); 0315 xmlout.writeEndDocument(); 0316 return xml.data(); 0317 } 0318 0319 QByteArray 0320 streamsToXml(const QMap<QString, 0321 QSharedPointer<const Introspectable> >& streams) { 0322 return streamsToXml(streams, print); 0323 } 0324 0325 QByteArray 0326 streamsToExtendedXml(const QMap<QString, 0327 QSharedPointer<const Introspectable> >& streams) { 0328 return streamsToXml(streams, printWithExtendedParser); 0329 }