--- a/src/ldproject.cpp Thu Mar 19 15:24:02 2015 +0200 +++ b/src/ldproject.cpp Thu Apr 02 11:25:58 2015 +0300 @@ -28,8 +28,132 @@ LDProjectPtr LDProject::LoadFromFile (const QString& filename) { - LDProjectPtr proj = LDProject::NewProject(); - LDProjectLoader (proj); + QVector<QPair<LDSubfilePtr, QString>> referenceNames; + std::function<LDProjectPtr (const QString&)> loadProject; + std::function<void (const QString &name, const QByteArray &data)> loadDocument; + + loadProject = [&](const QString& filename) -> LDProjectPtr + { + archive* arc = archive_read_new(); + archive_read_support_filter_all (arc); + archive_read_support_format_zip (arc); + int result = archive_read_open_filename (arc, filename.toLocal8Bit().constData(), 0x4000); + + if (result != ARCHIVE_OK) + { + fprint (stderr, "unable to open argh.pk3 (%1)\n", archive_error_string (arc)); + return LDProjectPtr(); + } + + for (archive_entry* arcent; archive_read_next_header(arc, &arcent) == ARCHIVE_OK;) + { + QString pathname = archive_entry_pathname (arcent); + QVector<char> buffer; + buffer.resize (archive_entry_size (arcent)); + int size = archive_read_data(arc, buffer.data(), buffer.size()); + + if (size >= 0) + { + if (pathname.startsWith ("dat/")) + loadDocument (pathname.right (4), QByteArray (buffer.constData(), buffer.size())); + } + else + fprint (stderr, "Unable to read %1: %2", pathname, archive_error_string (arc)); + } + + if ((result = archive_read_free(arc)) != ARCHIVE_OK) + { + fprint (stderr, "unable to close argh.pk3\n"); + return LDProjectPtr(); + } + + return LDProjectPtr(); + }; + + loadDocument = [&](const QString &name, const QByteArray &data) -> void + { + QDataStream ds (&data, QIODevice::ReadOnly); + ds.setVersion (QDataStream::Qt_4_8); + + quint16 version; + ds << version; + + if (version > CurrentBinaryVersion) + return; // too new + + qint8 header; + quint32 color; + LDDocumentPtr doc = LDDocument::createNew(); + doc->setName (name); + LDObjectPtr obj; + Vertex vertex; + Matrix matrix; + + while ((ds << header) != -1) + { + switch (header) + { + case 0: + { + QString message; + ds >> message; + doc->addObject (LDSpawn<LDComment> (message)); + } + break; + + case 1: + { + LDSubfilePtr ref = LDSpawn<LDSubfile>(); + QString name; + ds >> color; + ds >> vertex; + + for (int i = 0; i < 9; ++i) + ds >> matrix[i]; + + ds >> name; + ref->setColor (LDColor::fromIndex (color)); + ref->setPosition (vertex); + ref->setTransform (matrix); + + // We leave the fileInfo null for now, references are resolved during + // post-process. If this object references a document that we'll parse + // later, trying to find it now would yield null. + referenceNames.append ({ref, name}); + } + break; + + case 2: + obj = LDSpawn<LDLine>(); + goto polyobject; + + case 3: + obj = LDSpawn<LDTriangle>(); + goto polyobject; + + case 4: + obj = LDSpawn<LDQuad>(); + goto polyobject; + + case 5: + obj = LDSpawn<LDCondLine>(); + polyobject: + ds >> color; + obj->setColor (LDColor::fromIndex (color)); + + for (int i = 0; i < obj->numVertices(); ++i) + { + ds >> vertex; + obj->setVertex (i, vertex); + } + + doc->addObject (obj); + break; + } + } + }; + + return loadProject (filename); } struct Xyz @@ -54,134 +178,12 @@ struct LDProjectLoader { - QVector<QPair<LDSubfilePtr, QString>> referenceNames; - LDProjectLoader (LDProjectPtr proj); + LDProjectPtr loadProject(); void loadDocument (const QString &name, const QByteArray &data); }; -LDProjectLoader::LDProjectLoader (LDProjectPtr proj) -{ - archive* arc = archive_read_new(); - archive_read_support_filter_all (arc); - archive_read_support_format_zip (arc); - int result = archive_read_open_filename (arc, filename.toLocal8Bit().constData(), 0x4000); - - if (result != ARCHIVE_OK) - { - fprint (stderr, "unable to open argh.pk3 (%1)\n", archive_error_string (arc)); - return LDProjectPtr(); - } - - for (archive_entry* arcent; archive_read_next_header(arc, &arcent) == ARCHIVE_OK;) - { - QString pathname = archive_entry_pathname (arcent); - QVector<char> buffer; - buffer.resize (archive_entry_size (arcent)); - int size = archive_read_data(arc, buffer.data(), buffer.size()); - - if (size >= 0) - { - if (pathname.startsWith ("dat/")) - loadDocument (pathname.right (4), QByteArray (buffer.constData(), buffer.size())); - } - else - fprint (stderr, "Unable to read %1: %2", pathname, archive_error_string (arc)); - } - - if ((result = archive_read_free(arc)) != ARCHIVE_OK) - { - fprint (stderr, "unable to close argh.pk3\n"); - return LDProjectPtr(); - } - - return LDProjectPtr(); -} - -void LDProjectLoader::loadDocument (const QString &name, const QByteArray &data) -{ - QDataStream ds (&data, QIODevice::ReadOnly); - ds.setVersion (QDataStream::Qt_4_8); - - quint16 version; - ds << version; - - if (version > CurrentBinaryVersion) - return; // too new - - qint8 header; - quint32 color; - LDDocumentPtr doc = LDDocument::createNew(); - doc->setName (name); - LDObjectPtr obj; - Vertex vertex; - Matrix matrix; - - while ((ds << header) != -1) - { - switch (header) - { - case 0: - { - QString message; - ds >> message; - doc->addObject (LDSpawn<LDComment> (message)); - } - break; - - case 1: - { - LDSubfilePtr ref = LDSpawn<LDSubfile>(); - QString name; - ds >> color; - ds >> vertex; - - for (int i = 0; i < 9; ++i) - ds >> matrix[i]; - - ds >> name; - ref->setColor (LDColor::fromIndex (color)); - ref->setPosition (vertex); - ref->setTransform (matrix); - - // We leave the fileInfo null for now, references are resolved during post-process. - // If this object references a document that we'll parse later, finding it would - // yield null now. - referenceNames.append ({ref, name}); - } - break; - - case 2: - obj = LDSpawn<LDLine>(); - goto polyobject; - - case 3: - obj = LDSpawn<LDTriangle>(); - goto polyobject; - - case 4: - obj = LDSpawn<LDQuad>(); - goto polyobject; - - case 5: - obj = LDSpawn<LDCondLine>(); - polyobject: - ds >> color; - obj->setColor (LDColor::fromIndex (color)); - - for (int i = 0; i < obj->numVertices(); ++i) - { - ds >> vertex; - obj->setVertex (i, vertex); - } - - doc->addObject (obj); - break; - } - } -} - struct ArchiveEntry { archive_entry* entry;