185 } |
189 } |
186 |
190 |
187 // ============================================================================= |
191 // ============================================================================= |
188 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
192 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
189 // ============================================================================= |
193 // ============================================================================= |
190 std::vector<LDObject*> loadFileContents (FILE* fp, ulong* numWarnings) { |
194 void FileLoader::work () { |
191 char line[1024]; |
195 char line[1024]; |
192 vector<str> lines; |
196 m_progress = 0; |
193 vector<LDObject*> objs; |
197 abortflag = false; |
194 ulong lnum = 0; |
198 |
195 |
199 while (fgets (line, sizeof line, filePointer ())) { |
196 if (numWarnings) |
|
197 *numWarnings = 0; |
|
198 |
|
199 while (fgets (line, sizeof line, fp)) { |
|
200 // Trim the trailing newline |
200 // Trim the trailing newline |
201 str data = line; |
201 str data = line; |
202 while (data[~data - 1] == '\n' || data[~data - 1] == '\r') |
202 while (data[~data - 1] == '\n' || data[~data - 1] == '\r') |
203 data -= 1; |
203 data -= 1; |
204 |
204 |
205 LDObject* obj = parseLine (data); |
205 LDObject* obj = parseLine (data); |
206 assert (obj != null); |
206 assert (obj != null); |
207 |
207 |
208 // Check for parse errors and warn about tthem |
208 // Check for parse errors and warn about tthem |
209 if (obj->getType() == LDObject::Gibberish) { |
209 if (obj->getType () == LDObject::Gibberish) { |
210 logf (LOG_Warning, "Couldn't parse line #%lu: %s\n", |
210 logf (LOG_Warning, "Couldn't parse line #%lu: %s\n", |
211 lnum, static_cast<LDGibberish*> (obj)->reason.chars()); |
211 m_progress + 1, static_cast<LDGibberish*> (obj)->reason.chars()); |
212 |
212 |
213 logf (LOG_Warning, "- Line was: %s\n", data.chars()); |
213 logf (LOG_Warning, "- Line was: %s\n", data.chars()); |
214 |
214 |
215 if (numWarnings) |
215 if (m_warningsPointer) |
216 (*numWarnings)++; |
216 (*m_warningsPointer)++; |
217 } |
217 } |
218 |
218 |
219 objs.push_back (obj); |
219 m_objs.push_back (obj); |
220 lnum++; |
220 m_progress++; |
221 } |
221 emit progressUpdate (m_progress); |
|
222 |
|
223 if (abortflag) { |
|
224 // We were flagged for abortion, so abort. |
|
225 for (LDObject* obj : m_objs) |
|
226 delete obj; |
|
227 |
|
228 m_objs.clear (); |
|
229 return; |
|
230 } |
|
231 } |
|
232 |
|
233 emit workDone (); |
|
234 m_done = true; |
|
235 } |
|
236 |
|
237 // ============================================================================= |
|
238 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
|
239 // ============================================================================= |
|
240 std::vector<LDObject*> loadFileContents (FILE* fp, ulong* numWarnings, bool* ok) { |
|
241 vector<str> lines; |
|
242 vector<LDObject*> objs; |
|
243 |
|
244 if (numWarnings) |
|
245 *numWarnings = 0; |
|
246 |
|
247 FileLoader* loader = new FileLoader; |
|
248 loader->setFilePointer (fp); |
|
249 loader->setWarningsPointer (numWarnings); |
|
250 |
|
251 // Calculate the amount of lines |
|
252 ulong numLines = 0; |
|
253 char line[1024]; |
|
254 while (fgets (line, sizeof line, fp)) |
|
255 numLines++; |
|
256 |
|
257 rewind (fp); |
|
258 |
|
259 if (g_loadingMainFile) { |
|
260 // Show a progress dialog if we're loading the main file here and move |
|
261 // the actual work to a separate thread as this can be a rather intensive |
|
262 // operation and if we don't respond quickly enough, the program can be |
|
263 // deemed inresponsive.. which is a bad thing. |
|
264 |
|
265 // Init the thread and move the loader into it |
|
266 QThread* loaderThread = new QThread; |
|
267 QObject::connect (loaderThread, SIGNAL (started ()), loader, SLOT (work ())); |
|
268 QObject::connect (loaderThread, SIGNAL (finished ()), loader, SLOT (deleteLater ())); |
|
269 loader->moveToThread (loaderThread); |
|
270 loaderThread->start (); |
|
271 |
|
272 // Now create a progress dialog for the operation |
|
273 OpenFileDialog* dlg = new OpenFileDialog (g_win); |
|
274 dlg->setFileName ("???"); |
|
275 dlg->setNumLines (numLines); |
|
276 |
|
277 // Connect the loader in so we can actually show updates |
|
278 QObject::connect (loader, SIGNAL (progressUpdate (int)), dlg, SLOT (updateProgress (int))); |
|
279 QObject::connect (loader, SIGNAL (workDone ()), dlg, SLOT (accept ())); |
|
280 |
|
281 // Show the dialog. If the user hits cancel, tell the loader to abort. |
|
282 if (!dlg->exec ()) |
|
283 loader->abortflag = true; |
|
284 } else |
|
285 loader->work (); |
|
286 |
|
287 // If we wanted the success value, supply that now |
|
288 if (ok) |
|
289 *ok = loader->done (); |
|
290 |
|
291 // If the loader was done, return the objects it generated |
|
292 if (loader->done ()) |
|
293 objs = loader->objs (); |
222 |
294 |
223 return objs; |
295 return objs; |
224 } |
296 } |
225 |
297 |
226 // ============================================================================= |
298 // ============================================================================= |
227 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
299 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
228 // ============================================================================= |
300 // ============================================================================= |
229 LDOpenFile* openDATFile (str path, bool search, bool mainfile) { |
301 LDOpenFile* openDATFile (str path, bool search) { |
230 logf ("Opening %s...\n", path.chars()); |
302 logf ("Opening %s...\n", path.chars()); |
231 |
303 |
232 // Convert the file name to lowercase since some parts contain uppercase |
304 // Convert the file name to lowercase since some parts contain uppercase |
233 // file names. I'll assume here that the library will always use lowercase |
305 // file names. I'll assume here that the library will always use lowercase |
234 // file names for the actual parts.. |
306 // file names for the actual parts.. |
390 |
469 |
391 // ============================================================================= |
470 // ============================================================================= |
392 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
471 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
393 // ============================================================================= |
472 // ============================================================================= |
394 void openMainFile (str path) { |
473 void openMainFile (str path) { |
|
474 g_loadingMainFile = true; |
395 closeAll (); |
475 closeAll (); |
396 |
476 |
397 LDOpenFile* file = openDATFile (path, false, true); |
477 LDOpenFile* file = openDATFile (path, false); |
398 |
478 |
399 if (!file) { |
479 if (!file) { |
400 // Tell the user loading failed. |
480 // Tell the user loading failed. |
401 setlocale (LC_ALL, "C"); |
481 setlocale (LC_ALL, "C"); |
402 critical (fmt ("Failed to open %s: %s", path.chars(), strerror (errno))); |
482 critical (fmt ("Failed to open %s: %s", path.chars(), strerror (errno))); |
|
483 |
|
484 g_loadingMainFile = false; |
403 return; |
485 return; |
404 } |
486 } |
405 |
487 |
406 file->m_implicit = false; |
488 file->m_implicit = false; |
407 g_curfile = file; |
489 g_curfile = file; |
596 { |
679 { |
597 // Subfile |
680 // Subfile |
598 CHECK_TOKEN_COUNT (15) |
681 CHECK_TOKEN_COUNT (15) |
599 CHECK_TOKEN_NUMBERS (1, 13) |
682 CHECK_TOKEN_NUMBERS (1, 13) |
600 |
683 |
601 // Try open the file |
684 // Try open the file. Disable g_loadingMainFile temporarily since we're |
602 LDOpenFile* pFile = loadSubfile (tokens[14]); |
685 // not loading the main file now, but the subfile |
|
686 bool oldLoadingMainFile = g_loadingMainFile; |
|
687 g_loadingMainFile = false; |
|
688 LDOpenFile* load = loadSubfile (tokens[14]); |
|
689 g_loadingMainFile = oldLoadingMainFile; |
603 |
690 |
604 // If we cannot open the file, mark it an error |
691 // If we cannot open the file, mark it an error |
605 if (!pFile) |
692 if (!load) |
606 return new LDGibberish (line, "Could not open referred file"); |
693 return new LDGibberish (line, "Could not open referred file"); |
607 |
694 |
608 LDSubfile* obj = new LDSubfile; |
695 LDSubfile* obj = new LDSubfile; |
609 obj->color = atol (tokens[1]); |
696 obj->color = atol (tokens[1]); |
610 obj->pos = parseVertex (tokens, 2); // 2 - 4 |
697 obj->pos = parseVertex (tokens, 2); // 2 - 4 |
611 |
698 |
612 for (short i = 0; i < 9; ++i) |
699 for (short i = 0; i < 9; ++i) |
613 obj->transform[i] = atof (tokens[i + 5]); // 5 - 13 |
700 obj->transform[i] = atof (tokens[i + 5]); // 5 - 13 |
614 |
701 |
615 obj->fileName = tokens[14]; |
702 obj->fileName = tokens[14]; |
616 obj->fileInfo = pFile; |
703 obj->fileInfo = load; |
617 return obj; |
704 return obj; |
618 } |
705 } |
619 |
706 |
620 case 2: |
707 case 2: |
621 { |
708 { |
681 } |
768 } |
682 |
769 |
683 // ============================================================================= |
770 // ============================================================================= |
684 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
771 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
685 // ============================================================================= |
772 // ============================================================================= |
686 LDOpenFile* loadSubfile (str zFile) { |
773 LDOpenFile* loadSubfile (str fname) { |
687 // Try open the file |
774 // Try find the subfile in the list of loaded files |
688 LDOpenFile* pFile = findLoadedFile (zFile); |
775 LDOpenFile* load = findLoadedFile (fname); |
689 if (!pFile) |
776 |
690 pFile = openDATFile (zFile, true, false); |
777 // If it's not loaded, try open it |
691 |
778 if (!load) |
692 return pFile; |
779 load = openDATFile (fname, true); |
|
780 |
|
781 return load; |
693 } |
782 } |
694 |
783 |
695 // ============================================================================= |
784 // ============================================================================= |
696 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
785 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
697 // ============================================================================= |
786 // ============================================================================= |
708 g_loadedFiles.push_back (g_curfile); |
797 g_loadedFiles.push_back (g_curfile); |
709 |
798 |
710 // Go through all objects in the current file and reload the subfiles |
799 // Go through all objects in the current file and reload the subfiles |
711 for (LDObject* obj : g_curfile->m_objs) { |
800 for (LDObject* obj : g_curfile->m_objs) { |
712 if (obj->getType() == LDObject::Subfile) { |
801 if (obj->getType() == LDObject::Subfile) { |
713 // Note: ref->pFile is invalid right now since all subfiles were closed. |
802 // Note: ref->fileInfo is invalid right now since all subfiles were closed. |
714 LDSubfile* ref = static_cast<LDSubfile*> (obj); |
803 LDSubfile* ref = static_cast<LDSubfile*> (obj); |
715 LDOpenFile* pFile = loadSubfile (ref->fileName); |
804 LDOpenFile* fileInfo = loadSubfile (ref->fileName); |
716 |
805 |
717 if (pFile) |
806 if (fileInfo) |
718 ref->fileInfo = pFile; |
807 ref->fileInfo = fileInfo; |
719 else { |
808 else { |
720 // Couldn't load the file, mark it an error |
809 // Couldn't load the file, mark it an error |
721 ref->replace (new LDGibberish (ref->getContents (), "Could not open referred file")); |
810 ref->replace (new LDGibberish (ref->getContents (), "Could not open referred file")); |
722 } |
811 } |
723 } |
812 } |
724 |
813 |
725 // Reparse gibberish files. It could be that they are invalid because |
814 // Reparse gibberish files. It could be that they are invalid because |
726 // the file could not be opened. Circumstances may be different now. |
815 // of loading errors. Circumstances may be different now. |
727 if (obj->getType() == LDObject::Gibberish) |
816 if (obj->getType() == LDObject::Gibberish) |
728 obj->replace (parseLine (static_cast<LDGibberish*> (obj)->contents)); |
817 obj->replace (parseLine (static_cast<LDGibberish*> (obj)->contents)); |
729 } |
818 } |
730 } |
819 } |
731 |
820 |