Fix crash if saving files during save/cancel/close (#2517).
[dcpomatic.git] / src / tools / dcpomatic.cc
index 82da556980979bcede966283370f35a900af68f1..a7b3af8bce0999f44d4c420163988fccc72372ad 100644 (file)
@@ -74,6 +74,7 @@
 #include "lib/exceptions.h"
 #include "lib/ffmpeg_encoder.h"
 #include "lib/film.h"
+#include "lib/font_config.h"
 #include "lib/hints.h"
 #include "lib/job_manager.h"
 #include "lib/kdm_with_metadata.h"
@@ -567,7 +568,7 @@ private:
                } catch (boost::filesystem::filesystem_error& e) {
 #ifdef DCPOMATIC_WINDOWS
                        string bad_chars = "<>:\"/|?*";
-                       string const filename = d->path().filename().string();
+                       string const filename = dialog.path().filename().string();
                        string found_bad_chars;
                        for (size_t i = 0; i < bad_chars.length(); ++i) {
                                if (filename.find(bad_chars[i]) != string::npos && found_bad_chars.find(bad_chars[i]) == string::npos) {
@@ -614,14 +615,22 @@ private:
 
        void file_save ()
        {
-               _film->write_metadata ();
+               try {
+                       _film->write_metadata ();
+               } catch (exception& e) {
+                       error_dialog(this, _("Could not save project."), std_to_wx(e.what()));
+               }
        }
 
        void file_save_as_template ()
        {
                SaveTemplateDialog dialog(this);
                if (dialog.ShowModal() == wxID_OK) {
-                       Config::instance()->save_template(_film, dialog.name());
+                       try {
+                               Config::instance()->save_template(_film, dialog.name());
+                       } catch (exception& e) {
+                               error_dialog(this, _("Could not save template."), std_to_wx(e.what()));
+                       }
                }
        }
 
@@ -633,7 +642,11 @@ private:
                        auto film = make_shared<Film>(dialog.path());
                        film->copy_from (_film);
                        film->set_name(dialog.path().filename().generic_string());
-                       film->write_metadata ();
+                       try {
+                               film->write_metadata();
+                       } catch (exception& e) {
+                               error_dialog(this, _("Could not duplicate project."), std_to_wx(e.what()));
+                       }
                }
        }
 
@@ -645,8 +658,12 @@ private:
                        auto film = make_shared<Film>(dialog.path());
                        film->copy_from (_film);
                        film->set_name(dialog.path().filename().generic_string());
-                       film->write_metadata ();
-                       set_film (film);
+                       try {
+                               film->write_metadata ();
+                               set_film (film);
+                       } catch (exception& e) {
+                               error_dialog(this, _("Could not duplicate project."), std_to_wx(e.what()));
+                       }
                }
        }
 
@@ -944,34 +961,30 @@ private:
                dcp::LocalTime to (Config::instance()->signer_chain()->leaf().not_after());
                to.add_days (-1);
 
-               optional<dcp::EncryptedKDM> kdm;
-               try {
-                       kdm = _film->make_kdm (
-                               Config::instance()->decryption_chain()->leaf(),
-                               vector<string>(),
-                               dialog.cpl(),
-                               from, to,
-                               dcp::Formulation::MODIFIED_TRANSITIONAL_1,
-                               true,
-                               0
-                               );
-               } catch (dcp::NotEncryptedError& e) {
-                       error_dialog (this, _("CPL's content is not encrypted."));
-               } catch (exception& e) {
-                       error_dialog (this, e.what ());
-               } catch (...) {
-                       error_dialog (this, _("An unknown exception occurred."));
+               auto signer = Config::instance()->signer_chain();
+               if (!signer->valid()) {
+                       error_dialog(this, _("The certificate chain for signing is invalid"));
+                       return;
                }
 
-               if (kdm) {
+               optional<dcp::EncryptedKDM> kdm;
+               try {
+                       auto const decrypted_kdm = _film->make_kdm(dialog.cpl(), from, to);
+                       auto const kdm = decrypted_kdm.encrypt(signer, Config::instance()->decryption_chain()->leaf(), {}, dcp::Formulation::MODIFIED_TRANSITIONAL_1, true, 0);
                        if (dialog.internal()) {
                                auto dkdms = Config::instance()->dkdms();
-                               dkdms->add (make_shared<DKDM>(kdm.get()));
+                               dkdms->add(make_shared<DKDM>(kdm));
                                Config::instance()->changed ();
                        } else {
                                auto path = dialog.directory() / (_film->dcp_name(false) + "_DKDM.xml");
-                               kdm->as_xml (path);
+                               kdm.as_xml(path);
                        }
+               } catch (dcp::NotEncryptedError& e) {
+                       error_dialog (this, _("CPL's content is not encrypted."));
+               } catch (exception& e) {
+                       error_dialog (this, e.what ());
+               } catch (...) {
+                       error_dialog (this, _("An unknown exception occurred."));
                }
        }
 
@@ -1179,6 +1192,8 @@ private:
                /* Also stop hearing about analytics-related stuff */
                _analytics_message_connection.disconnect ();
 
+               FontConfig::drop();
+
                ev.Skip ();
        }
 
@@ -1254,14 +1269,20 @@ private:
                        return true;
                }
 
-               if (_film->dirty ()) {
-                       T d (_film->name ());
-                       switch (d.run ()) {
+               while (_film->dirty()) {
+                       T dialog(_film->name());
+                       switch (dialog.run()) {
                        case wxID_NO:
                                return true;
                        case wxID_YES:
-                               _film->write_metadata ();
-                               return true;
+                               try {
+                                       _film->write_metadata();
+                                       return true;
+                               } catch (exception& e) {
+                                       error_dialog(this, _("Could not save project."), std_to_wx(e.what()));
+                                       /* Go round again for another try */
+                               }
+                               break;
                        case wxID_CANCEL:
                                return false;
                        }