17 */ |
17 */ |
18 |
18 |
19 #include <archive.h> |
19 #include <archive.h> |
20 #include <archive_entry.h> |
20 #include <archive_entry.h> |
21 #include "ldproject.h" |
21 #include "ldproject.h" |
|
22 #include "ldDocument.h" |
|
23 |
|
24 enum { CurrentBinaryVersion = 0 }; |
22 |
25 |
23 LDProject::LDProject() {} |
26 LDProject::LDProject() {} |
24 LDProject::~LDProject() {} |
27 LDProject::~LDProject() {} |
25 |
28 |
26 LDProjectPtr LDProject::LoadFromFile (const QString& filename) |
29 LDProjectPtr LDProject::LoadFromFile (const QString& filename) |
27 { |
30 { |
28 FILE* fp = fopen ("log.txt", "w"); |
31 LDProjectPtr proj = LDProject::NewProject(); |
29 if (!fp) |
32 LDProjectLoader (proj); |
30 return LDProjectPtr(); |
33 } |
31 |
34 |
|
35 struct Xyz |
|
36 { |
|
37 double x, y, z; |
|
38 Xyz (Vertex const& a) : |
|
39 x (a.x()), |
|
40 y (a.y()), |
|
41 z (a.z()) {} |
|
42 Vertex toVertex() const { return Vertex (x, y, z); } |
|
43 }; |
|
44 |
|
45 QDataStream& operator>> (QDataStream& ds, Xyz& a) |
|
46 { |
|
47 return ds >> a.x >> a.y >> a.z; |
|
48 } |
|
49 |
|
50 QDataStream& operator<< (QDataStream& ds, const Xyz& a) |
|
51 { |
|
52 return ds << a.x << a.y << a.z; |
|
53 } |
|
54 |
|
55 struct LDProjectLoader |
|
56 { |
|
57 QVector<QPair<LDSubfilePtr, QString>> referenceNames; |
|
58 |
|
59 LDProjectLoader (LDProjectPtr proj); |
|
60 void loadDocument (const QString &name, const QByteArray &data); |
|
61 |
|
62 }; |
|
63 |
|
64 LDProjectLoader::LDProjectLoader (LDProjectPtr proj) |
|
65 { |
32 archive* arc = archive_read_new(); |
66 archive* arc = archive_read_new(); |
33 archive_read_support_filter_all (arc); |
67 archive_read_support_filter_all (arc); |
34 archive_read_support_format_zip (arc); |
68 archive_read_support_format_zip (arc); |
35 int result = archive_read_open_filename (arc, filename.toLocal8Bit().constData(), 0x4000); |
69 int result = archive_read_open_filename (arc, filename.toLocal8Bit().constData(), 0x4000); |
36 |
70 |
37 if (result != ARCHIVE_OK) |
71 if (result != ARCHIVE_OK) |
38 { |
72 { |
39 fprint (fp, "unable to open argh.pk3 (%1)\n", archive_error_string (arc)); |
73 fprint (stderr, "unable to open argh.pk3 (%1)\n", archive_error_string (arc)); |
40 return LDProjectPtr(); |
74 return LDProjectPtr(); |
41 } |
75 } |
42 |
76 |
43 for (archive_entry* arcent; archive_read_next_header(arc, &arcent) == ARCHIVE_OK;) |
77 for (archive_entry* arcent; archive_read_next_header(arc, &arcent) == ARCHIVE_OK;) |
44 { |
78 { |
48 int size = archive_read_data(arc, buffer.data(), buffer.size()); |
82 int size = archive_read_data(arc, buffer.data(), buffer.size()); |
49 |
83 |
50 if (size >= 0) |
84 if (size >= 0) |
51 { |
85 { |
52 if (pathname.startsWith ("dat/")) |
86 if (pathname.startsWith ("dat/")) |
53 loadBinaryDocument (pathname.right (4), QByteArray (buffer.constData(), buffer.size())); |
87 loadDocument (pathname.right (4), QByteArray (buffer.constData(), buffer.size())); |
54 } |
88 } |
55 else |
89 else |
56 fprint (fp, "Unable to read %1: %2", pathname, archive_error_string (arc)); |
90 fprint (stderr, "Unable to read %1: %2", pathname, archive_error_string (arc)); |
57 } |
91 } |
58 |
92 |
59 if ((result = archive_read_free(arc)) != ARCHIVE_OK) |
93 if ((result = archive_read_free(arc)) != ARCHIVE_OK) |
60 { |
94 { |
61 fprint (fp, "unable to close argh.pk3\n"); |
95 fprint (stderr, "unable to close argh.pk3\n"); |
62 return LDProjectPtr(); |
96 return LDProjectPtr(); |
63 } |
97 } |
64 |
98 |
65 return LDProjectPtr(); |
99 return LDProjectPtr(); |
66 } |
100 } |
67 |
101 |
68 #include "ldDocument.h" |
102 void LDProjectLoader::loadDocument (const QString &name, const QByteArray &data) |
69 void LDProject::loadBinaryDocument(const QString &name, const QByteArray &data) |
|
70 { |
103 { |
71 QDataStream ds (&data, QIODevice::ReadOnly); |
104 QDataStream ds (&data, QIODevice::ReadOnly); |
72 ds.setVersion (QDataStream::Qt_4_8); |
105 ds.setVersion (QDataStream::Qt_4_8); |
73 enum { CurrentVersion = 0 }; |
|
74 |
106 |
75 quint16 version; |
107 quint16 version; |
76 ds << version; |
108 ds << version; |
77 |
109 |
78 if (version > CurrentVersion) |
110 if (version > CurrentBinaryVersion) |
79 return; // too new |
111 return; // too new |
80 |
112 |
81 qint8 header; |
113 qint8 header; |
82 quint32 color; |
114 quint32 color; |
83 LDDocumentPtr doc = LDDocument::createNew(); |
115 LDDocumentPtr doc = LDDocument::createNew(); |
|
116 doc->setName (name); |
84 LDObjectPtr obj; |
117 LDObjectPtr obj; |
85 struct XYZ { double x, y, z; Vertex toVertex() const { return Vertex (x,y,z); }}; |
118 Vertex vertex; |
86 XYZ verts[4]; |
119 Matrix matrix; |
87 |
120 |
88 while ((ds << header) != -1) |
121 while ((ds << header) != -1) |
89 { |
122 { |
90 switch (header) |
123 switch (header) |
91 { |
124 { |
92 case 0: |
125 case 0: |
93 { |
126 { |
94 QString message; |
127 QString message; |
95 ds >> message; |
128 ds >> message; |
96 doc->addObject (LDSpawn<LDComment> (message)); |
129 doc->addObject (LDSpawn<LDComment> (message)); |
|
130 } |
|
131 break; |
|
132 |
|
133 case 1: |
|
134 { |
|
135 LDSubfilePtr ref = LDSpawn<LDSubfile>(); |
|
136 QString name; |
|
137 ds >> color; |
|
138 ds >> vertex; |
|
139 |
|
140 for (int i = 0; i < 9; ++i) |
|
141 ds >> matrix[i]; |
|
142 |
|
143 ds >> name; |
|
144 ref->setColor (LDColor::fromIndex (color)); |
|
145 ref->setPosition (vertex); |
|
146 ref->setTransform (matrix); |
|
147 |
|
148 // We leave the fileInfo null for now, references are resolved during post-process. |
|
149 // If this object references a document that we'll parse later, finding it would |
|
150 // yield null now. |
|
151 referenceNames.append ({ref, name}); |
97 } |
152 } |
98 break; |
153 break; |
99 |
154 |
100 case 2: |
155 case 2: |
101 obj = LDSpawn<LDLine>(); |
156 obj = LDSpawn<LDLine>(); |
111 |
166 |
112 case 5: |
167 case 5: |
113 obj = LDSpawn<LDCondLine>(); |
168 obj = LDSpawn<LDCondLine>(); |
114 polyobject: |
169 polyobject: |
115 ds >> color; |
170 ds >> color; |
|
171 obj->setColor (LDColor::fromIndex (color)); |
|
172 |
116 for (int i = 0; i < obj->numVertices(); ++i) |
173 for (int i = 0; i < obj->numVertices(); ++i) |
117 { |
174 { |
118 XYZ v; |
175 ds >> vertex; |
119 ds >> v.x >> v.y >> v.z; |
176 obj->setVertex (i, vertex); |
120 obj->setVertex (i, Vertex (v.x, v.y, v.z)); |
|
121 } |
177 } |
122 |
178 |
123 doc->addObject (obj); |
179 doc->addObject (obj); |
124 break; |
180 break; |
125 } |
181 } |
126 } |
182 } |
127 |
183 } |
|
184 |
|
185 struct ArchiveEntry |
|
186 { |
|
187 archive_entry* entry; |
|
188 ArchiveEntry() : entry (archive_entry_new()) {} |
|
189 ArchiveEntry (const ArchiveEntry&) = delete; |
|
190 ~ArchiveEntry() { archive_entry_free (entry); } |
|
191 void operator= (const ArchiveEntry&) = delete; |
|
192 operator archive_entry*() { return entry; } |
|
193 |
|
194 void clear() { archive_entry_clear (entry); } |
|
195 void setSize (size_t size) { archive_entry_set_size (entry, size); } |
|
196 void setPathName (const char* name) { archive_entry_set_pathname (entry, name); } |
|
197 void setFileType (unsigned type) { archive_entry_set_filetype (entry, type); } |
|
198 void setPermissions (int perms) { archive_entry_set_perm (entry, perms); } |
|
199 }; |
|
200 |
|
201 void LDProject::saveBinaryDocuments (archive* arc) |
|
202 { |
|
203 ArchiveEntry ent; |
|
204 |
|
205 for (LDDocumentPtr doc : m_documents) |
|
206 { |
|
207 QByteArray buffer; |
|
208 QDataStream ds (&buffer, QIODevice::WriteOnly); |
|
209 ds << CurrentBinaryVersion; |
|
210 |
|
211 for (LDObjectPtr obj : doc->objects()) |
|
212 { |
|
213 int number; |
|
214 |
|
215 switch (obj->type()) |
|
216 { |
|
217 case OBJ_Comment: |
|
218 ds << 0 |
|
219 << obj.staticCast<LDCommentPtr>()->text(); |
|
220 break; |
|
221 |
|
222 case OBJ_Subfile: |
|
223 { |
|
224 LDSubfilePtr ref = obj.staticCast<LDSubfilePtr>(); |
|
225 ds << 1 |
|
226 << ref->color().index() |
|
227 << ref->position(); |
|
228 |
|
229 for (int i = 0; i < 9; ++i) |
|
230 ds << ref->transform()[i]; |
|
231 |
|
232 ds << ref->fileInfo()->name(); |
|
233 } |
|
234 break; |
|
235 |
|
236 case OBJ_Line: |
|
237 number = 2; |
|
238 goto polyobj; |
|
239 |
|
240 case OBJ_Triangle: |
|
241 number = 3; |
|
242 goto polyobj; |
|
243 |
|
244 case OBJ_Quad: |
|
245 number = 4; |
|
246 goto polyobj; |
|
247 |
|
248 case OBJ_CondLine: |
|
249 number = 5; |
|
250 polyobj: |
|
251 ds << obj->color().index(); |
|
252 |
|
253 for (int i = 0; i < obj->numVertices(); ++i) |
|
254 ds << obj->vertex (i); |
|
255 break; |
|
256 } |
|
257 } |
|
258 |
|
259 ent.clear(); |
|
260 ent.setSize (buffer.size()); |
|
261 ent.setPathName (QString ("doc/" + doc->name() + ".dat").toLocal8Bit()); |
|
262 ent.setFileType (AE_IFREG); |
|
263 ent.setPermissions (0644); |
|
264 archive_write_header (arc, ent); |
|
265 archive_write_data (arc, buffer.constData(), buffer.size()); |
|
266 } |
128 } |
267 } |
129 |
268 |
130 LDProjectPtr LDProject::NewProject() |
269 LDProjectPtr LDProject::NewProject() |
131 { |
270 { |
132 return LDProjectPtr (new LDProject()); |
271 return LDProjectPtr (new LDProject()); |
133 } |
272 } |
134 |
273 |
135 bool LDProject::save (const QString &filename) |
274 bool LDProject::save (const QString& filename) |
136 { |
275 { |
137 return false; |
276 QString tempname = filename; |
138 } |
277 |
139 |
278 if (tempname.endsWith (".ldforge")) |
|
279 tempname.chop (strlen (".ldforge")); |
|
280 |
|
281 if (not tempname.endsWith (".zip")) |
|
282 tempname += ".zip"; |
|
283 |
|
284 archive* arc = archive_write_new(); |
|
285 archive_write_open_filename (arc, filename); |
|
286 saveBinaryDocuments (arc); |
|
287 archive_write_close (arc); |
|
288 m_lastErrorString = archive_error_string (arc); |
|
289 archive_write_free (arc); |
|
290 return true; |
|
291 } |