Cleanup: 0 -> nullptr.
[dcpomatic.git] / src / lib / config.cc
1 /*
2     Copyright (C) 2012-2022 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "cinema.h"
23 #include "colour_conversion.h"
24 #include "compose.hpp"
25 #include "config.h"
26 #include "constants.h"
27 #include "cross.h"
28 #include "dcp_content_type.h"
29 #include "dkdm_recipient.h"
30 #include "dkdm_wrapper.h"
31 #include "film.h"
32 #include "filter.h"
33 #include "log.h"
34 #include "ratio.h"
35 #include "zipper.h"
36 #include <dcp/certificate_chain.h>
37 #include <dcp/name_format.h>
38 #include <dcp/raw_convert.h>
39 #include <libcxml/cxml.h>
40 #include <glib.h>
41 #include <libxml++/libxml++.h>
42 #include <boost/filesystem.hpp>
43 #include <boost/algorithm/string.hpp>
44 #include <boost/thread.hpp>
45 #include <cstdlib>
46 #include <fstream>
47 #include <iostream>
48
49 #include "i18n.h"
50
51
52 using std::cout;
53 using std::dynamic_pointer_cast;
54 using std::ifstream;
55 using std::list;
56 using std::make_shared;
57 using std::max;
58 using std::min;
59 using std::remove;
60 using std::shared_ptr;
61 using std::string;
62 using std::vector;
63 using boost::algorithm::trim;
64 using boost::optional;
65 using dcp::raw_convert;
66
67
68 Config* Config::_instance = 0;
69 int const Config::_current_version = 3;
70 boost::signals2::signal<void (Config::LoadFailure)> Config::FailedToLoad;
71 boost::signals2::signal<void (string)> Config::Warning;
72 boost::signals2::signal<bool (Config::BadReason)> Config::Bad;
73
74
75 /** Construct default configuration */
76 Config::Config ()
77         /* DKDMs are not considered a thing to reset on set_defaults() */
78         : _dkdms (new DKDMGroup ("root"))
79         , _default_kdm_duration (1, RoughDuration::Unit::WEEKS)
80         , _export(this)
81 {
82         set_defaults ();
83 }
84
85 void
86 Config::set_defaults ()
87 {
88         _master_encoding_threads = max (2U, boost::thread::hardware_concurrency ());
89         _server_encoding_threads = max (2U, boost::thread::hardware_concurrency ());
90         _server_port_base = 6192;
91         _use_any_servers = true;
92         _servers.clear ();
93         _only_servers_encode = false;
94         _tms_protocol = FileTransferProtocol::SCP;
95         _tms_passive = true;
96         _tms_ip = "";
97         _tms_path = ".";
98         _tms_user = "";
99         _tms_password = "";
100         _allow_any_dcp_frame_rate = false;
101         _allow_any_container = false;
102         _allow_96khz_audio = false;
103         _use_all_audio_channels = false;
104         _show_experimental_audio_processors = false;
105         _language = optional<string> ();
106         _default_still_length = 10;
107         _default_dcp_content_type = DCPContentType::from_isdcf_name ("FTR");
108         _default_dcp_audio_channels = 8;
109         _default_j2k_bandwidth = 150000000;
110         _default_audio_delay = 0;
111         _default_interop = false;
112         _default_metadata.clear ();
113         _upload_after_make_dcp = false;
114         _mail_server = "";
115         _mail_port = 25;
116         _mail_protocol = EmailProtocol::AUTO;
117         _mail_user = "";
118         _mail_password = "";
119         _kdm_from = "";
120         _kdm_cc.clear ();
121         _kdm_bcc = "";
122         _notification_from = "";
123         _notification_to = "";
124         _notification_cc.clear ();
125         _notification_bcc = "";
126         _check_for_updates = false;
127         _check_for_test_updates = false;
128         _maximum_j2k_bandwidth = 250000000;
129         _log_types = LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR | LogEntry::TYPE_DISK;
130         _analyse_ebur128 = true;
131         _automatic_audio_analysis = false;
132 #ifdef DCPOMATIC_WINDOWS
133         _win32_console = false;
134 #endif
135         /* At the moment we don't write these files anywhere new after a version change, so they will be read from
136          * ~/.config/dcpomatic2 (or equivalent) and written back there.
137          */
138         _cinemas_file = read_path ("cinemas.xml");
139         _dkdm_recipients_file = read_path ("dkdm_recipients.xml");
140         _show_hints_before_make_dcp = true;
141         _confirm_kdm_email = true;
142         _kdm_container_name_format = dcp::NameFormat("KDM_%f_%c");
143         _kdm_filename_format = dcp::NameFormat("KDM_%f_%c_%s");
144         _dkdm_filename_format = dcp::NameFormat("DKDM_%f_%c_%s");
145         _dcp_metadata_filename_format = dcp::NameFormat ("%t");
146         _dcp_asset_filename_format = dcp::NameFormat ("%t");
147         _jump_to_selected = true;
148         for (int i = 0; i < NAG_COUNT; ++i) {
149                 _nagged[i] = false;
150         }
151         _sound = true;
152         _sound_output = optional<string> ();
153         _last_kdm_write_type = KDM_WRITE_FLAT;
154         _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
155         _default_add_file_location = DefaultAddFileLocation::SAME_AS_LAST_TIME;
156
157         /* I think the scaling factor here should be the ratio of the longest frame
158            encode time to the shortest; if the thread count is T, longest time is L
159            and the shortest time S we could encode L/S frames per thread whilst waiting
160            for the L frame to encode so we might have to store LT/S frames.
161
162            However we don't want to use too much memory, so keep it a bit lower than we'd
163            perhaps like.  A J2K frame is typically about 1Mb so 3 here will mean we could
164            use about 240Mb with 72 encoding threads.
165         */
166         _frames_in_memory_multiplier = 3;
167         _decode_reduction = optional<int>();
168         _default_notify = false;
169         for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
170                 _notification[i] = false;
171         }
172         _barco_username = optional<string>();
173         _barco_password = optional<string>();
174         _christie_username = optional<string>();
175         _christie_password = optional<string>();
176         _gdc_username = optional<string>();
177         _gdc_password = optional<string>();
178         _player_mode = PLAYER_MODE_WINDOW;
179         _image_display = 0;
180         _video_view_type = VIDEO_VIEW_SIMPLE;
181         _respect_kdm_validity_periods = true;
182         _player_debug_log_file = boost::none;
183         _player_content_directory = boost::none;
184         _player_playlist_directory = boost::none;
185         _player_kdm_directory = boost::none;
186         _audio_mapping = boost::none;
187         _custom_languages.clear ();
188         _initial_paths.clear();
189         _initial_paths["AddFilesPath"] = boost::none;
190         _initial_paths["AddKDMPath"] = boost::none;
191         _initial_paths["AddDKDMPath"] = boost::none;
192         _initial_paths["SelectCertificatePath"] = boost::none;
193         _initial_paths["AddCombinerInputPath"] = boost::none;
194         _initial_paths["ExportSubtitlesPath"] = boost::none;
195         _initial_paths["ExportVideoPath"] = boost::none;
196         _initial_paths["DebugLogPath"] = boost::none;
197         _initial_paths["CinemaDatabasePath"] = boost::none;
198         _initial_paths["ConfigFilePath"] = boost::none;
199         _use_isdcf_name_by_default = true;
200         _write_kdms_to_disk = true;
201         _email_kdms = false;
202         _default_kdm_type = dcp::Formulation::MODIFIED_TRANSITIONAL_1;
203         _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
204         _auto_crop_threshold = 0.1;
205         _last_release_notes_version = boost::none;
206         _allow_smpte_bv20 = false;
207         _isdcf_name_part_length = 14;
208
209         _allowed_dcp_frame_rates.clear ();
210         _allowed_dcp_frame_rates.push_back (24);
211         _allowed_dcp_frame_rates.push_back (25);
212         _allowed_dcp_frame_rates.push_back (30);
213         _allowed_dcp_frame_rates.push_back (48);
214         _allowed_dcp_frame_rates.push_back (50);
215         _allowed_dcp_frame_rates.push_back (60);
216
217         set_kdm_email_to_default ();
218         set_notification_email_to_default ();
219         set_cover_sheet_to_default ();
220
221         _main_divider_sash_position = {};
222         _main_content_divider_sash_position = {};
223
224         _export.set_defaults();
225 }
226
227 void
228 Config::restore_defaults ()
229 {
230         Config::instance()->set_defaults ();
231         Config::instance()->changed ();
232 }
233
234 shared_ptr<dcp::CertificateChain>
235 Config::create_certificate_chain ()
236 {
237         return make_shared<dcp::CertificateChain> (
238                 openssl_path(),
239                 CERTIFICATE_VALIDITY_PERIOD,
240                 "dcpomatic.com",
241                 "dcpomatic.com",
242                 ".dcpomatic.smpte-430-2.ROOT",
243                 ".dcpomatic.smpte-430-2.INTERMEDIATE",
244                 "CS.dcpomatic.smpte-430-2.LEAF"
245                 );
246 }
247
248 void
249 Config::backup ()
250 {
251         using namespace boost::filesystem;
252
253         auto copy_adding_number = [](path const& path_to_copy) {
254
255                 auto add_number = [](path const& path, int number) {
256                         return String::compose("%1.%2", path, number);
257                 };
258
259                 int n = 1;
260                 while (n < 100 && exists(add_number(path_to_copy, n))) {
261                         ++n;
262                 }
263                 boost::system::error_code ec;
264                 copy_file(path_to_copy, add_number(path_to_copy, n), ec);
265         };
266
267         /* Make a backup copy of any config.xml, cinemas.xml, dkdm_recipients.xml that we might be about
268          * to write over.  This is more intended for the situation where we have a corrupted config.xml,
269          * and decide to overwrite it with a new one (possibly losing important details in the corrupted
270          * file).  But we might as well back up the other files while we're about it.
271          */
272
273         /* This uses the State::write_path stuff so, e.g. for a current version 2.16 we might copy
274          * ~/.config/dcpomatic2/2.16/config.xml to ~/.config/dcpomatic2/2.16/config.xml.1
275          */
276         copy_adding_number (config_write_file());
277
278         /* These do not use State::write_path, so whatever path is in the Config we will copy
279          * adding a number.
280          */
281         copy_adding_number (_cinemas_file);
282         copy_adding_number (_dkdm_recipients_file);
283 }
284
285 void
286 Config::read ()
287 {
288         read_config();
289         read_cinemas();
290         read_dkdm_recipients();
291 }
292
293
294 void
295 Config::read_config()
296 try
297 {
298         cxml::Document f ("Config");
299         f.read_file(dcp::filesystem::fix_long_path(config_read_file()));
300
301         auto version = f.optional_number_child<int> ("Version");
302         if (version && *version < _current_version) {
303                 /* Back up the old config before we re-write it in a back-incompatible way */
304                 backup ();
305         }
306
307         if (f.optional_number_child<int>("NumLocalEncodingThreads")) {
308                 _master_encoding_threads = _server_encoding_threads = f.optional_number_child<int>("NumLocalEncodingThreads").get();
309         } else {
310                 _master_encoding_threads = f.number_child<int>("MasterEncodingThreads");
311                 _server_encoding_threads = f.number_child<int>("ServerEncodingThreads");
312         }
313
314         _default_directory = f.optional_string_child ("DefaultDirectory");
315         if (_default_directory && _default_directory->empty ()) {
316                 /* We used to store an empty value for this to mean "none set" */
317                 _default_directory = boost::optional<boost::filesystem::path> ();
318         }
319
320         auto b = f.optional_number_child<int> ("ServerPort");
321         if (!b) {
322                 b = f.optional_number_child<int> ("ServerPortBase");
323         }
324         _server_port_base = b.get ();
325
326         auto u = f.optional_bool_child ("UseAnyServers");
327         _use_any_servers = u.get_value_or (true);
328
329         for (auto i: f.node_children("Server")) {
330                 if (i->node_children("HostName").size() == 1) {
331                         _servers.push_back (i->string_child ("HostName"));
332                 } else {
333                         _servers.push_back (i->content ());
334                 }
335         }
336
337         _only_servers_encode = f.optional_bool_child ("OnlyServersEncode").get_value_or (false);
338         _tms_protocol = static_cast<FileTransferProtocol>(f.optional_number_child<int>("TMSProtocol").get_value_or(static_cast<int>(FileTransferProtocol::SCP)));
339         _tms_passive = f.optional_bool_child("TMSPassive").get_value_or(true);
340         _tms_ip = f.string_child ("TMSIP");
341         _tms_path = f.string_child ("TMSPath");
342         _tms_user = f.string_child ("TMSUser");
343         _tms_password = f.string_child ("TMSPassword");
344
345         _language = f.optional_string_child ("Language");
346
347         _default_dcp_content_type = DCPContentType::from_isdcf_name(f.optional_string_child("DefaultDCPContentType").get_value_or("FTR"));
348         _default_dcp_audio_channels = f.optional_number_child<int>("DefaultDCPAudioChannels").get_value_or (6);
349
350         if (f.optional_string_child ("DCPMetadataIssuer")) {
351                 _dcp_issuer = f.string_child ("DCPMetadataIssuer");
352         } else if (f.optional_string_child ("DCPIssuer")) {
353                 _dcp_issuer = f.string_child ("DCPIssuer");
354         }
355
356         auto up = f.optional_bool_child("UploadAfterMakeDCP");
357         if (!up) {
358                 up = f.optional_bool_child("DefaultUploadAfterMakeDCP");
359         }
360         _upload_after_make_dcp = up.get_value_or (false);
361         _dcp_creator = f.optional_string_child ("DCPCreator").get_value_or ("");
362         _dcp_company_name = f.optional_string_child("DCPCompanyName").get_value_or("");
363         _dcp_product_name = f.optional_string_child("DCPProductName").get_value_or("");
364         _dcp_product_version = f.optional_string_child("DCPProductVersion").get_value_or("");
365         _dcp_j2k_comment = f.optional_string_child("DCPJ2KComment").get_value_or("");
366
367         _default_still_length = f.optional_number_child<int>("DefaultStillLength").get_value_or (10);
368         _default_j2k_bandwidth = f.optional_number_child<int>("DefaultJ2KBandwidth").get_value_or (200000000);
369         _default_audio_delay = f.optional_number_child<int>("DefaultAudioDelay").get_value_or (0);
370         _default_interop = f.optional_bool_child("DefaultInterop").get_value_or (false);
371
372         try {
373                 auto al = f.optional_string_child("DefaultAudioLanguage");
374                 if (al) {
375                         _default_audio_language = dcp::LanguageTag(*al);
376                 }
377         } catch (std::runtime_error&) {}
378
379         try {
380                 auto te = f.optional_string_child("DefaultTerritory");
381                 if (te) {
382                         _default_territory = dcp::LanguageTag::RegionSubtag(*te);
383                 }
384         } catch (std::runtime_error&) {}
385
386         for (auto const& i: f.node_children("DefaultMetadata")) {
387                 _default_metadata[i->string_attribute("key")] = i->content();
388         }
389
390         _default_kdm_directory = f.optional_string_child("DefaultKDMDirectory");
391
392         /* Read any cinemas that are still lying around in the config file
393          * from an old version.
394          */
395         read_cinemas (f);
396
397         _mail_server = f.string_child ("MailServer");
398         _mail_port = f.optional_number_child<int> ("MailPort").get_value_or (25);
399
400         {
401                 /* Make sure this matches the code in write_config */
402                 string const protocol = f.optional_string_child("MailProtocol").get_value_or("Auto");
403                 if (protocol == "Auto") {
404                         _mail_protocol = EmailProtocol::AUTO;
405                 } else if (protocol == "Plain") {
406                         _mail_protocol = EmailProtocol::PLAIN;
407                 } else if (protocol == "STARTTLS") {
408                         _mail_protocol = EmailProtocol::STARTTLS;
409                 } else if (protocol == "SSL") {
410                         _mail_protocol = EmailProtocol::SSL;
411                 }
412         }
413
414         _mail_user = f.optional_string_child("MailUser").get_value_or ("");
415         _mail_password = f.optional_string_child("MailPassword").get_value_or ("");
416
417         _kdm_subject = f.optional_string_child ("KDMSubject").get_value_or (_("KDM delivery: $CPL_NAME"));
418         _kdm_from = f.string_child ("KDMFrom");
419         for (auto i: f.node_children("KDMCC")) {
420                 if (!i->content().empty()) {
421                         _kdm_cc.push_back (i->content ());
422                 }
423         }
424         _kdm_bcc = f.optional_string_child ("KDMBCC").get_value_or ("");
425         _kdm_email = f.string_child ("KDMEmail");
426
427         _notification_subject = f.optional_string_child("NotificationSubject").get_value_or(_("DCP-o-matic notification"));
428         _notification_from = f.optional_string_child("NotificationFrom").get_value_or("");
429         _notification_to = f.optional_string_child("NotificationTo").get_value_or("");
430         for (auto i: f.node_children("NotificationCC")) {
431                 if (!i->content().empty()) {
432                         _notification_cc.push_back (i->content ());
433                 }
434         }
435         _notification_bcc = f.optional_string_child("NotificationBCC").get_value_or("");
436         if (f.optional_string_child("NotificationEmail")) {
437                 _notification_email = f.string_child("NotificationEmail");
438         }
439
440         _check_for_updates = f.optional_bool_child("CheckForUpdates").get_value_or (false);
441         _check_for_test_updates = f.optional_bool_child("CheckForTestUpdates").get_value_or (false);
442
443         _maximum_j2k_bandwidth = f.optional_number_child<int> ("MaximumJ2KBandwidth").get_value_or (250000000);
444         _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate").get_value_or (false);
445         _allow_any_container = f.optional_bool_child ("AllowAnyContainer").get_value_or (false);
446         _allow_96khz_audio = f.optional_bool_child("Allow96kHzAudio").get_value_or(false);
447         _use_all_audio_channels = f.optional_bool_child("UseAllAudioChannels").get_value_or(false);
448         _show_experimental_audio_processors = f.optional_bool_child ("ShowExperimentalAudioProcessors").get_value_or (false);
449
450         _log_types = f.optional_number_child<int> ("LogTypes").get_value_or (LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR);
451         _analyse_ebur128 = f.optional_bool_child("AnalyseEBUR128").get_value_or (true);
452         _automatic_audio_analysis = f.optional_bool_child ("AutomaticAudioAnalysis").get_value_or (false);
453 #ifdef DCPOMATIC_WINDOWS
454         _win32_console = f.optional_bool_child ("Win32Console").get_value_or (false);
455 #endif
456
457         for (auto i: f.node_children("History")) {
458                 _history.push_back (i->content ());
459         }
460
461         for (auto i: f.node_children("PlayerHistory")) {
462                 _player_history.push_back (i->content ());
463         }
464
465         auto signer = f.optional_node_child ("Signer");
466         if (signer) {
467                 auto c = make_shared<dcp::CertificateChain>();
468                 /* Read the signing certificates and private key in from the config file */
469                 for (auto i: signer->node_children ("Certificate")) {
470                         c->add (dcp::Certificate (i->content ()));
471                 }
472                 c->set_key (signer->string_child ("PrivateKey"));
473                 _signer_chain = c;
474         } else {
475                 /* Make a new set of signing certificates and key */
476                 _signer_chain = create_certificate_chain ();
477         }
478
479         auto decryption = f.optional_node_child ("Decryption");
480         if (decryption) {
481                 auto c = make_shared<dcp::CertificateChain>();
482                 for (auto i: decryption->node_children ("Certificate")) {
483                         c->add (dcp::Certificate (i->content ()));
484                 }
485                 c->set_key (decryption->string_child ("PrivateKey"));
486                 _decryption_chain = c;
487         } else {
488                 _decryption_chain = create_certificate_chain ();
489         }
490
491         /* These must be done before we call Bad as that might set one
492            of the nags.
493         */
494         for (auto i: f.node_children("Nagged")) {
495                 auto const id = i->number_attribute<int>("Id");
496                 if (id >= 0 && id < NAG_COUNT) {
497                         _nagged[id] = raw_convert<int>(i->content());
498                 }
499         }
500
501         auto bad = check_certificates ();
502         if (bad) {
503                 auto const remake = Bad(*bad);
504                 if (remake && *remake) {
505                         switch (*bad) {
506                         case BAD_SIGNER_UTF8_STRINGS:
507                         case BAD_SIGNER_INCONSISTENT:
508                         case BAD_SIGNER_VALIDITY_TOO_LONG:
509                         case BAD_SIGNER_DN_QUALIFIER:
510                                 _signer_chain = create_certificate_chain ();
511                                 break;
512                         case BAD_DECRYPTION_INCONSISTENT:
513                                 _decryption_chain = create_certificate_chain ();
514                                 break;
515                         }
516                 }
517         }
518
519         if (f.optional_node_child("DKDMGroup")) {
520                 /* New-style: all DKDMs in a group */
521                 _dkdms = dynamic_pointer_cast<DKDMGroup> (DKDMBase::read (f.node_child("DKDMGroup")));
522         } else {
523                 /* Old-style: one or more DKDM nodes */
524                 _dkdms = make_shared<DKDMGroup>("root");
525                 for (auto i: f.node_children("DKDM")) {
526                         _dkdms->add (DKDMBase::read (i));
527                 }
528         }
529         _cinemas_file = f.optional_string_child("CinemasFile").get_value_or(read_path("cinemas.xml").string());
530         _dkdm_recipients_file = f.optional_string_child("DKDMRecipientsFile").get_value_or(read_path("dkdm_recipients.xml").string());
531         _show_hints_before_make_dcp = f.optional_bool_child("ShowHintsBeforeMakeDCP").get_value_or (true);
532         _confirm_kdm_email = f.optional_bool_child("ConfirmKDMEmail").get_value_or (true);
533         _kdm_container_name_format = dcp::NameFormat (f.optional_string_child("KDMContainerNameFormat").get_value_or ("KDM %f %c"));
534         _kdm_filename_format = dcp::NameFormat (f.optional_string_child("KDMFilenameFormat").get_value_or ("KDM %f %c %s"));
535         _dkdm_filename_format = dcp::NameFormat (f.optional_string_child("DKDMFilenameFormat").get_value_or("DKDM %f %c %s"));
536         _dcp_metadata_filename_format = dcp::NameFormat (f.optional_string_child("DCPMetadataFilenameFormat").get_value_or ("%t"));
537         _dcp_asset_filename_format = dcp::NameFormat (f.optional_string_child("DCPAssetFilenameFormat").get_value_or ("%t"));
538         _jump_to_selected = f.optional_bool_child("JumpToSelected").get_value_or (true);
539         /* The variable was renamed but not the XML tag */
540         _sound = f.optional_bool_child("PreviewSound").get_value_or (true);
541         _sound_output = f.optional_string_child("PreviewSoundOutput");
542         if (f.optional_string_child("CoverSheet")) {
543                 _cover_sheet = f.optional_string_child("CoverSheet").get();
544         }
545         _last_player_load_directory = f.optional_string_child("LastPlayerLoadDirectory");
546         if (f.optional_string_child("LastKDMWriteType")) {
547                 if (f.optional_string_child("LastKDMWriteType").get() == "flat") {
548                         _last_kdm_write_type = KDM_WRITE_FLAT;
549                 } else if (f.optional_string_child("LastKDMWriteType").get() == "folder") {
550                         _last_kdm_write_type = KDM_WRITE_FOLDER;
551                 } else if (f.optional_string_child("LastKDMWriteType").get() == "zip") {
552                         _last_kdm_write_type = KDM_WRITE_ZIP;
553                 }
554         }
555         if (f.optional_string_child("LastDKDMWriteType")) {
556                 if (f.optional_string_child("LastDKDMWriteType").get() == "internal") {
557                         _last_dkdm_write_type = DKDM_WRITE_INTERNAL;
558                 } else if (f.optional_string_child("LastDKDMWriteType").get() == "file") {
559                         _last_dkdm_write_type = DKDM_WRITE_FILE;
560                 }
561         }
562         _frames_in_memory_multiplier = f.optional_number_child<int>("FramesInMemoryMultiplier").get_value_or(3);
563         _decode_reduction = f.optional_number_child<int>("DecodeReduction");
564         _default_notify = f.optional_bool_child("DefaultNotify").get_value_or(false);
565
566         for (auto i: f.node_children("Notification")) {
567                 int const id = i->number_attribute<int>("Id");
568                 if (id >= 0 && id < NOTIFICATION_COUNT) {
569                         _notification[id] = raw_convert<int>(i->content());
570                 }
571         }
572
573         _barco_username = f.optional_string_child("BarcoUsername");
574         _barco_password = f.optional_string_child("BarcoPassword");
575         _christie_username = f.optional_string_child("ChristieUsername");
576         _christie_password = f.optional_string_child("ChristiePassword");
577         _gdc_username = f.optional_string_child("GDCUsername");
578         _gdc_password = f.optional_string_child("GDCPassword");
579
580         auto pm = f.optional_string_child("PlayerMode");
581         if (pm && *pm == "window") {
582                 _player_mode = PLAYER_MODE_WINDOW;
583         } else if (pm && *pm == "full") {
584                 _player_mode = PLAYER_MODE_FULL;
585         } else if (pm && *pm == "dual") {
586                 _player_mode = PLAYER_MODE_DUAL;
587         }
588
589         _image_display = f.optional_number_child<int>("ImageDisplay").get_value_or(0);
590         auto vc = f.optional_string_child("VideoViewType");
591         if (vc && *vc == "opengl") {
592                 _video_view_type = VIDEO_VIEW_OPENGL;
593         } else if (vc && *vc == "simple") {
594                 _video_view_type = VIDEO_VIEW_SIMPLE;
595         }
596         _respect_kdm_validity_periods = f.optional_bool_child("RespectKDMValidityPeriods").get_value_or(true);
597         _player_debug_log_file = f.optional_string_child("PlayerDebugLogFile");
598         _player_content_directory = f.optional_string_child("PlayerContentDirectory");
599         _player_playlist_directory = f.optional_string_child("PlayerPlaylistDirectory");
600         _player_kdm_directory = f.optional_string_child("PlayerKDMDirectory");
601
602         if (f.optional_node_child("AudioMapping")) {
603                 _audio_mapping = AudioMapping (f.node_child("AudioMapping"), Film::current_state_version);
604         }
605
606         for (auto i: f.node_children("CustomLanguage")) {
607                 try {
608                         /* This will fail if it's called before dcp::init() as it won't recognise the
609                          * tag.  That's OK because the Config will be reloaded again later.
610                          */
611                         _custom_languages.push_back (dcp::LanguageTag(i->content()));
612                 } catch (std::runtime_error& e) {}
613         }
614
615         for (auto& initial: _initial_paths) {
616                 initial.second = f.optional_string_child(initial.first);
617         }
618         _use_isdcf_name_by_default = f.optional_bool_child("UseISDCFNameByDefault").get_value_or(true);
619         _write_kdms_to_disk = f.optional_bool_child("WriteKDMsToDisk").get_value_or(true);
620         _email_kdms = f.optional_bool_child("EmailKDMs").get_value_or(false);
621         _default_kdm_type = dcp::string_to_formulation(f.optional_string_child("DefaultKDMType").get_value_or("modified-transitional-1"));
622         if (auto duration = f.optional_node_child("DefaultKDMDuration")) {
623                 _default_kdm_duration = RoughDuration(duration);
624         } else {
625                 _default_kdm_duration = RoughDuration(1, RoughDuration::Unit::WEEKS);
626         }
627         _auto_crop_threshold = f.optional_number_child<double>("AutoCropThreshold").get_value_or(0.1);
628         _last_release_notes_version = f.optional_string_child("LastReleaseNotesVersion");
629         _main_divider_sash_position = f.optional_number_child<int>("MainDividerSashPosition");
630         _main_content_divider_sash_position = f.optional_number_child<int>("MainContentDividerSashPosition");
631
632         if (auto loc = f.optional_string_child("DefaultAddFileLocation")) {
633                 if (*loc == "last") {
634                         _default_add_file_location = DefaultAddFileLocation::SAME_AS_LAST_TIME;
635                 } else if (*loc == "project") {
636                         _default_add_file_location = DefaultAddFileLocation::SAME_AS_PROJECT;
637                 }
638         }
639
640         _allow_smpte_bv20 = f.optional_bool_child("AllowSMPTEBv20").get_value_or(false);
641         _isdcf_name_part_length = f.optional_number_child<int>("ISDCFNamePartLength").get_value_or(14);
642
643         _export.read(f.optional_node_child("Export"));
644 }
645 catch (...) {
646         if (have_existing("config.xml")) {
647                 backup ();
648                 /* We have a config file but it didn't load */
649                 FailedToLoad(LoadFailure::CONFIG);
650         }
651         set_defaults ();
652         /* Make a new set of signing certificates and key */
653         _signer_chain = create_certificate_chain ();
654         /* And similar for decryption of KDMs */
655         _decryption_chain = create_certificate_chain ();
656         write_config();
657 }
658
659
660 void
661 Config::read_cinemas()
662 {
663         if (dcp::filesystem::exists(_cinemas_file)) {
664                 try {
665                         cxml::Document f("Cinemas");
666                         f.read_file(dcp::filesystem::fix_long_path(_cinemas_file));
667                         read_cinemas(f);
668                 } catch (...) {
669                         backup();
670                         FailedToLoad(LoadFailure::CINEMAS);
671                         write_cinemas();
672                 }
673         }
674 }
675
676
677 void
678 Config::read_dkdm_recipients()
679 {
680         if (dcp::filesystem::exists(_dkdm_recipients_file)) {
681                 try {
682                         cxml::Document f("DKDMRecipients");
683                         f.read_file(dcp::filesystem::fix_long_path(_dkdm_recipients_file));
684                         read_dkdm_recipients(f);
685                 } catch (...) {
686                         backup();
687                         FailedToLoad(LoadFailure::DKDM_RECIPIENTS);
688                         write_dkdm_recipients();
689                 }
690         }
691 }
692
693
694 /** @return Singleton instance */
695 Config *
696 Config::instance ()
697 {
698         if (_instance == nullptr) {
699                 _instance = new Config;
700                 _instance->read ();
701         }
702
703         return _instance;
704 }
705
706 /** Write our configuration to disk */
707 void
708 Config::write () const
709 {
710         write_config ();
711         write_cinemas ();
712         write_dkdm_recipients ();
713 }
714
715 void
716 Config::write_config () const
717 {
718         xmlpp::Document doc;
719         auto root = doc.create_root_node ("Config");
720
721         /* [XML] Version The version number of the configuration file format. */
722         root->add_child("Version")->add_child_text (raw_convert<string>(_current_version));
723         /* [XML] MasterEncodingThreads Number of encoding threads to use when running as master. */
724         root->add_child("MasterEncodingThreads")->add_child_text (raw_convert<string> (_master_encoding_threads));
725         /* [XML] ServerEncodingThreads Number of encoding threads to use when running as server. */
726         root->add_child("ServerEncodingThreads")->add_child_text (raw_convert<string> (_server_encoding_threads));
727         if (_default_directory) {
728                 /* [XML:opt] DefaultDirectory Default directory when creating a new film in the GUI. */
729                 root->add_child("DefaultDirectory")->add_child_text (_default_directory->string ());
730         }
731         /* [XML] ServerPortBase Port number to use for frame encoding requests.  <code>ServerPortBase</code> + 1 and
732            <code>ServerPortBase</code> + 2 are used for querying servers.  <code>ServerPortBase</code> + 3 is used
733            by the batch converter to listen for job requests.
734         */
735         root->add_child("ServerPortBase")->add_child_text (raw_convert<string> (_server_port_base));
736         /* [XML] UseAnyServers 1 to broadcast to look for encoding servers to use, 0 to use only those configured. */
737         root->add_child("UseAnyServers")->add_child_text (_use_any_servers ? "1" : "0");
738
739         for (auto i: _servers) {
740                 /* [XML:opt] Server IP address or hostname of an encoding server to use; you can use as many of these tags
741                    as you like.
742                 */
743                 root->add_child("Server")->add_child_text (i);
744         }
745
746         /* [XML] OnlyServersEncode 1 to set the master to do decoding of source content no JPEG2000 encoding; all encoding
747            is done by the encoding servers.  0 to set the master to do some encoding as well as coordinating the job.
748         */
749         root->add_child("OnlyServersEncode")->add_child_text (_only_servers_encode ? "1" : "0");
750         /* [XML] TMSProtocol Protocol to use to copy files to a TMS; 0 to use SCP, 1 for FTP. */
751         root->add_child("TMSProtocol")->add_child_text (raw_convert<string> (static_cast<int> (_tms_protocol)));
752         /* [XML] TMSPassive True to use PASV mode with TMS FTP connections. */
753         root->add_child("TMSPassive")->add_child_text(_tms_passive ? "1" : "0");
754         /* [XML] TMSIP IP address of TMS. */
755         root->add_child("TMSIP")->add_child_text (_tms_ip);
756         /* [XML] TMSPath Path on the TMS to copy files to. */
757         root->add_child("TMSPath")->add_child_text (_tms_path);
758         /* [XML] TMSUser Username to log into the TMS with. */
759         root->add_child("TMSUser")->add_child_text (_tms_user);
760         /* [XML] TMSPassword Password to log into the TMS with. */
761         root->add_child("TMSPassword")->add_child_text (_tms_password);
762         if (_language) {
763                 /* [XML:opt] Language Language to use in the GUI e.g. <code>fr_FR</code>. */
764                 root->add_child("Language")->add_child_text (_language.get());
765         }
766         if (_default_dcp_content_type) {
767                 /* [XML:opt] DefaultDCPContentType Default content type to use when creating new films (<code>FTR</code>, <code>SHR</code>,
768                    <code>TLR</code>, <code>TST</code>, <code>XSN</code>, <code>RTG</code>, <code>TSR</code>, <code>POL</code>,
769                    <code>PSA</code> or <code>ADV</code>). */
770                 root->add_child("DefaultDCPContentType")->add_child_text (_default_dcp_content_type->isdcf_name ());
771         }
772         /* [XML] DefaultDCPAudioChannels Default number of audio channels to use when creating new films. */
773         root->add_child("DefaultDCPAudioChannels")->add_child_text (raw_convert<string> (_default_dcp_audio_channels));
774         /* [XML] DCPIssuer Issuer text to write into CPL files. */
775         root->add_child("DCPIssuer")->add_child_text (_dcp_issuer);
776         /* [XML] DCPCreator Creator text to write into CPL files. */
777         root->add_child("DCPCreator")->add_child_text (_dcp_creator);
778         /* [XML] Company name to write into MXF files. */
779         root->add_child("DCPCompanyName")->add_child_text (_dcp_company_name);
780         /* [XML] Product name to write into MXF files. */
781         root->add_child("DCPProductName")->add_child_text (_dcp_product_name);
782         /* [XML] Product version to write into MXF files. */
783         root->add_child("DCPProductVersion")->add_child_text (_dcp_product_version);
784         /* [XML] Comment to write into JPEG2000 data. */
785         root->add_child("DCPJ2KComment")->add_child_text (_dcp_j2k_comment);
786         /* [XML] UploadAfterMakeDCP 1 to upload to a TMS after making a DCP, 0 for no upload. */
787         root->add_child("UploadAfterMakeDCP")->add_child_text (_upload_after_make_dcp ? "1" : "0");
788
789         /* [XML] DefaultStillLength Default length (in seconds) for still images in new films. */
790         root->add_child("DefaultStillLength")->add_child_text (raw_convert<string> (_default_still_length));
791         /* [XML] DefaultJ2KBandwidth Default bitrate (in bits per second) for JPEG2000 data in new films. */
792         root->add_child("DefaultJ2KBandwidth")->add_child_text (raw_convert<string> (_default_j2k_bandwidth));
793         /* [XML] DefaultAudioDelay Default delay to apply to audio (positive moves audio later) in milliseconds. */
794         root->add_child("DefaultAudioDelay")->add_child_text (raw_convert<string> (_default_audio_delay));
795         /* [XML] DefaultInterop 1 to default new films to Interop, 0 for SMPTE. */
796         root->add_child("DefaultInterop")->add_child_text (_default_interop ? "1" : "0");
797         if (_default_audio_language) {
798                 /* [XML] DefaultAudioLanguage Default audio language to use for new films */
799                 root->add_child("DefaultAudioLanguage")->add_child_text(_default_audio_language->to_string());
800         }
801         if (_default_territory) {
802                 /* [XML] DefaultTerritory Default territory to use for new films */
803                 root->add_child("DefaultTerritory")->add_child_text(_default_territory->subtag());
804         }
805         for (auto const& i: _default_metadata) {
806                 auto c = root->add_child("DefaultMetadata");
807                 c->set_attribute("key", i.first);
808                 c->add_child_text(i.second);
809         }
810         if (_default_kdm_directory) {
811                 /* [XML:opt] DefaultKDMDirectory Default directory to write KDMs to. */
812                 root->add_child("DefaultKDMDirectory")->add_child_text (_default_kdm_directory->string ());
813         }
814         _default_kdm_duration.as_xml(root->add_child("DefaultKDMDuration"));
815         /* [XML] MailServer Hostname of SMTP server to use. */
816         root->add_child("MailServer")->add_child_text (_mail_server);
817         /* [XML] MailPort Port number to use on SMTP server. */
818         root->add_child("MailPort")->add_child_text (raw_convert<string> (_mail_port));
819         /* [XML] MailProtocol Protocol to use on SMTP server (Auto, Plain, STARTTLS or SSL) */
820         switch (_mail_protocol) {
821         case EmailProtocol::AUTO:
822                 root->add_child("MailProtocol")->add_child_text("Auto");
823                 break;
824         case EmailProtocol::PLAIN:
825                 root->add_child("MailProtocol")->add_child_text("Plain");
826                 break;
827         case EmailProtocol::STARTTLS:
828                 root->add_child("MailProtocol")->add_child_text("STARTTLS");
829                 break;
830         case EmailProtocol::SSL:
831                 root->add_child("MailProtocol")->add_child_text("SSL");
832                 break;
833         }
834         /* [XML] MailUser Username to use on SMTP server. */
835         root->add_child("MailUser")->add_child_text (_mail_user);
836         /* [XML] MailPassword Password to use on SMTP server. */
837         root->add_child("MailPassword")->add_child_text (_mail_password);
838
839         /* [XML] KDMSubject Subject to use for KDM emails. */
840         root->add_child("KDMSubject")->add_child_text (_kdm_subject);
841         /* [XML] KDMFrom From address to use for KDM emails. */
842         root->add_child("KDMFrom")->add_child_text (_kdm_from);
843         for (auto i: _kdm_cc) {
844                 /* [XML] KDMCC CC address to use for KDM emails; you can use as many of these tags as you like. */
845                 root->add_child("KDMCC")->add_child_text (i);
846         }
847         /* [XML] KDMBCC BCC address to use for KDM emails. */
848         root->add_child("KDMBCC")->add_child_text (_kdm_bcc);
849         /* [XML] KDMEmail Text of KDM email. */
850         root->add_child("KDMEmail")->add_child_text (_kdm_email);
851
852         /* [XML] NotificationSubject Subject to use for notification emails. */
853         root->add_child("NotificationSubject")->add_child_text (_notification_subject);
854         /* [XML] NotificationFrom From address to use for notification emails. */
855         root->add_child("NotificationFrom")->add_child_text (_notification_from);
856         /* [XML] NotificationFrom To address to use for notification emails. */
857         root->add_child("NotificationTo")->add_child_text (_notification_to);
858         for (auto i: _notification_cc) {
859                 /* [XML] NotificationCC CC address to use for notification emails; you can use as many of these tags as you like. */
860                 root->add_child("NotificationCC")->add_child_text (i);
861         }
862         /* [XML] NotificationBCC BCC address to use for notification emails. */
863         root->add_child("NotificationBCC")->add_child_text (_notification_bcc);
864         /* [XML] NotificationEmail Text of notification email. */
865         root->add_child("NotificationEmail")->add_child_text (_notification_email);
866
867         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new versions, 0 to check only on request. */
868         root->add_child("CheckForUpdates")->add_child_text (_check_for_updates ? "1" : "0");
869         /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request. */
870         root->add_child("CheckForTestUpdates")->add_child_text (_check_for_test_updates ? "1" : "0");
871
872         /* [XML] MaximumJ2KBandwidth Maximum J2K bandwidth (in bits per second) that can be specified in the GUI. */
873         root->add_child("MaximumJ2KBandwidth")->add_child_text (raw_convert<string> (_maximum_j2k_bandwidth));
874         /* [XML] AllowAnyDCPFrameRate 1 to allow users to specify any frame rate when creating DCPs, 0 to limit the GUI to standard rates. */
875         root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0");
876         /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to DCI Flat/Scope */
877         root->add_child("AllowAnyContainer")->add_child_text (_allow_any_container ? "1" : "0");
878         /* [XML] Allow96kHzAudio 1 to allow users to make DCPs with 96kHz audio, 0 to always make 48kHz DCPs */
879         root->add_child("Allow96kHzAudio")->add_child_text(_allow_96khz_audio ? "1" : "0");
880         /* [XML] UseAllAudioChannels 1 to allow users to map audio to all 16 DCP channels, 0 to limit to the channels used in standard DCPs */
881         root->add_child("UseAllAudioChannels")->add_child_text(_use_all_audio_channels ? "1" : "0");
882         /* [XML] ShowExperimentalAudioProcessors 1 to offer users the (experimental) audio upmixer processors, 0 to hide them */
883         root->add_child("ShowExperimentalAudioProcessors")->add_child_text (_show_experimental_audio_processors ? "1" : "0");
884         /* [XML] LogTypes Types of logging to write; a bitfield where 1 is general notes, 2 warnings, 4 errors, 8 debug information related
885            to 3D, 16 debug information related to encoding, 32 debug information for timing purposes, 64 debug information related
886            to sending email, 128 debug information related to the video view, 256 information about disk writing, 512 debug information
887            related to the player, 1024 debug information related to audio analyses.
888         */
889         root->add_child("LogTypes")->add_child_text (raw_convert<string> (_log_types));
890         /* [XML] AnalyseEBUR128 1 to do EBUR128 analyses when analysing audio, otherwise 0. */
891         root->add_child("AnalyseEBUR128")->add_child_text (_analyse_ebur128 ? "1" : "0");
892         /* [XML] AutomaticAudioAnalysis 1 to run audio analysis automatically when audio content is added to the film, otherwise 0. */
893         root->add_child("AutomaticAudioAnalysis")->add_child_text (_automatic_audio_analysis ? "1" : "0");
894 #ifdef DCPOMATIC_WINDOWS
895         if (_win32_console) {
896                 /* [XML] Win32Console 1 to open a console when running on Windows, otherwise 0.
897                  * We only write this if it's true, which is a bit of a hack to allow unit tests to work
898                  * more easily on Windows (without a platform-specific reference in config_write_utf8_test)
899                  */
900                 root->add_child("Win32Console")->add_child_text ("1");
901         }
902 #endif
903
904         /* [XML] Signer Certificate chain and private key to use when signing DCPs and KDMs.  Should contain <code>&lt;Certificate&gt;</code>
905            tags in order and a <code>&lt;PrivateKey&gt;</code> tag all containing PEM-encoded certificates or private keys as appropriate.
906         */
907         auto signer = root->add_child ("Signer");
908         DCPOMATIC_ASSERT (_signer_chain);
909         for (auto const& i: _signer_chain->unordered()) {
910                 signer->add_child("Certificate")->add_child_text (i.certificate (true));
911         }
912         signer->add_child("PrivateKey")->add_child_text (_signer_chain->key().get ());
913
914         /* [XML] Decryption Certificate chain and private key to use when decrypting KDMs */
915         auto decryption = root->add_child ("Decryption");
916         DCPOMATIC_ASSERT (_decryption_chain);
917         for (auto const& i: _decryption_chain->unordered()) {
918                 decryption->add_child("Certificate")->add_child_text (i.certificate (true));
919         }
920         decryption->add_child("PrivateKey")->add_child_text (_decryption_chain->key().get ());
921
922         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the GUI; there can be more than one
923            of these tags.
924         */
925         for (auto i: _history) {
926                 root->add_child("History")->add_child_text (i.string ());
927         }
928
929         /* [XML] History Filename of DCP to present in the <guilabel>File</guilabel> menu of the player; there can be more than one
930            of these tags.
931         */
932         for (auto i: _player_history) {
933                 root->add_child("PlayerHistory")->add_child_text (i.string ());
934         }
935
936         /* [XML] DKDMGroup A group of DKDMs, each with a <code>Name</code> attribute, containing other <code>&lt;DKDMGroup&gt;</code>
937            or <code>&lt;DKDM&gt;</code> tags.
938         */
939         /* [XML] DKDM A DKDM as XML */
940         _dkdms->as_xml (root);
941
942         /* [XML] CinemasFile Filename of cinemas list file. */
943         root->add_child("CinemasFile")->add_child_text (_cinemas_file.string());
944         /* [XML] DKDMRecipientsFile Filename of DKDM recipients list file. */
945         root->add_child("DKDMRecipientsFile")->add_child_text (_dkdm_recipients_file.string());
946         /* [XML] ShowHintsBeforeMakeDCP 1 to show hints in the GUI before making a DCP, otherwise 0. */
947         root->add_child("ShowHintsBeforeMakeDCP")->add_child_text (_show_hints_before_make_dcp ? "1" : "0");
948         /* [XML] ConfirmKDMEmail 1 to confirm before sending KDM emails in the GUI, otherwise 0. */
949         root->add_child("ConfirmKDMEmail")->add_child_text (_confirm_kdm_email ? "1" : "0");
950         /* [XML] KDMFilenameFormat Format for KDM filenames. */
951         root->add_child("KDMFilenameFormat")->add_child_text (_kdm_filename_format.specification ());
952         /* [XML] KDMFilenameFormat Format for DKDM filenames. */
953         root->add_child("DKDMFilenameFormat")->add_child_text(_dkdm_filename_format.specification());
954         /* [XML] KDMContainerNameFormat Format for KDM containers (directories or ZIP files). */
955         root->add_child("KDMContainerNameFormat")->add_child_text (_kdm_container_name_format.specification ());
956         /* [XML] DCPMetadataFilenameFormat Format for DCP metadata filenames. */
957         root->add_child("DCPMetadataFilenameFormat")->add_child_text (_dcp_metadata_filename_format.specification ());
958         /* [XML] DCPAssetFilenameFormat Format for DCP asset filenames. */
959         root->add_child("DCPAssetFilenameFormat")->add_child_text (_dcp_asset_filename_format.specification ());
960         /* [XML] JumpToSelected 1 to make the GUI jump to the start of content when it is selected, otherwise 0. */
961         root->add_child("JumpToSelected")->add_child_text (_jump_to_selected ? "1" : "0");
962         /* [XML] Nagged 1 if a particular nag screen has been shown and should not be shown again, otherwise 0. */
963         for (int i = 0; i < NAG_COUNT; ++i) {
964                 xmlpp::Element* e = root->add_child ("Nagged");
965                 e->set_attribute ("Id", raw_convert<string>(i));
966                 e->add_child_text (_nagged[i] ? "1" : "0");
967         }
968         /* [XML] PreviewSound 1 to use sound in the GUI preview and player, otherwise 0. */
969         root->add_child("PreviewSound")->add_child_text (_sound ? "1" : "0");
970         if (_sound_output) {
971                 /* [XML:opt] PreviewSoundOutput Name of the audio output to use. */
972                 root->add_child("PreviewSoundOutput")->add_child_text (_sound_output.get());
973         }
974         /* [XML] CoverSheet Text of the cover sheet to write when making DCPs. */
975         root->add_child("CoverSheet")->add_child_text (_cover_sheet);
976         if (_last_player_load_directory) {
977                 root->add_child("LastPlayerLoadDirectory")->add_child_text(_last_player_load_directory->string());
978         }
979         /* [XML] LastKDMWriteType Last type of KDM-write: <code>flat</code> for a flat file, <code>folder</code> for a folder or <code>zip</code> for a ZIP file. */
980         if (_last_kdm_write_type) {
981                 switch (_last_kdm_write_type.get()) {
982                 case KDM_WRITE_FLAT:
983                         root->add_child("LastKDMWriteType")->add_child_text("flat");
984                         break;
985                 case KDM_WRITE_FOLDER:
986                         root->add_child("LastKDMWriteType")->add_child_text("folder");
987                         break;
988                 case KDM_WRITE_ZIP:
989                         root->add_child("LastKDMWriteType")->add_child_text("zip");
990                         break;
991                 }
992         }
993         /* [XML] LastDKDMWriteType Last type of DKDM-write: <code>file</code> for a file, <code>internal</code> to add to DCP-o-matic's list. */
994         if (_last_dkdm_write_type) {
995                 switch (_last_dkdm_write_type.get()) {
996                 case DKDM_WRITE_INTERNAL:
997                         root->add_child("LastDKDMWriteType")->add_child_text("internal");
998                         break;
999                 case DKDM_WRITE_FILE:
1000                         root->add_child("LastDKDMWriteType")->add_child_text("file");
1001                         break;
1002                 }
1003         }
1004         /* [XML] FramesInMemoryMultiplier value to multiply the encoding threads count by to get the maximum number of
1005            frames to be held in memory at once.
1006         */
1007         root->add_child("FramesInMemoryMultiplier")->add_child_text(raw_convert<string>(_frames_in_memory_multiplier));
1008
1009         /* [XML] DecodeReduction power of 2 to reduce DCP images by before decoding in the player. */
1010         if (_decode_reduction) {
1011                 root->add_child("DecodeReduction")->add_child_text(raw_convert<string>(_decode_reduction.get()));
1012         }
1013
1014         /* [XML] DefaultNotify 1 to default jobs to notify when complete, otherwise 0. */
1015         root->add_child("DefaultNotify")->add_child_text(_default_notify ? "1" : "0");
1016
1017         /* [XML] Notification 1 if a notification type is enabled, otherwise 0. */
1018         for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
1019                 xmlpp::Element* e = root->add_child ("Notification");
1020                 e->set_attribute ("Id", raw_convert<string>(i));
1021                 e->add_child_text (_notification[i] ? "1" : "0");
1022         }
1023
1024         if (_barco_username) {
1025                 /* [XML] BarcoUsername Username for logging into Barco's servers when downloading server certificates. */
1026                 root->add_child("BarcoUsername")->add_child_text(*_barco_username);
1027         }
1028         if (_barco_password) {
1029                 /* [XML] BarcoPassword Password for logging into Barco's servers when downloading server certificates. */
1030                 root->add_child("BarcoPassword")->add_child_text(*_barco_password);
1031         }
1032
1033         if (_christie_username) {
1034                 /* [XML] ChristieUsername Username for logging into Christie's servers when downloading server certificates. */
1035                 root->add_child("ChristieUsername")->add_child_text(*_christie_username);
1036         }
1037         if (_christie_password) {
1038                 /* [XML] ChristiePassword Password for logging into Christie's servers when downloading server certificates. */
1039                 root->add_child("ChristiePassword")->add_child_text(*_christie_password);
1040         }
1041
1042         if (_gdc_username) {
1043                 /* [XML] GDCUsername Username for logging into GDC's servers when downloading server certificates. */
1044                 root->add_child("GDCUsername")->add_child_text(*_gdc_username);
1045         }
1046         if (_gdc_password) {
1047                 /* [XML] GDCPassword Password for logging into GDC's servers when downloading server certificates. */
1048                 root->add_child("GDCPassword")->add_child_text(*_gdc_password);
1049         }
1050
1051         /* [XML] PlayerMode <code>window</code> for a single window, <code>full</code> for full-screen and <code>dual</code> for full screen playback
1052            with separate (advanced) controls.
1053         */
1054         switch (_player_mode) {
1055         case PLAYER_MODE_WINDOW:
1056                 root->add_child("PlayerMode")->add_child_text("window");
1057                 break;
1058         case PLAYER_MODE_FULL:
1059                 root->add_child("PlayerMode")->add_child_text("full");
1060                 break;
1061         case PLAYER_MODE_DUAL:
1062                 root->add_child("PlayerMode")->add_child_text("dual");
1063                 break;
1064         }
1065
1066         /* [XML] ImageDisplay Screen number to put image on in dual-screen player mode. */
1067         root->add_child("ImageDisplay")->add_child_text(raw_convert<string>(_image_display));
1068         switch (_video_view_type) {
1069         case VIDEO_VIEW_SIMPLE:
1070                 root->add_child("VideoViewType")->add_child_text("simple");
1071                 break;
1072         case VIDEO_VIEW_OPENGL:
1073                 root->add_child("VideoViewType")->add_child_text("opengl");
1074                 break;
1075         }
1076         /* [XML] RespectKDMValidityPeriods 1 to refuse to use KDMs that are out of date, 0 to ignore KDM dates. */
1077         root->add_child("RespectKDMValidityPeriods")->add_child_text(_respect_kdm_validity_periods ? "1" : "0");
1078         if (_player_debug_log_file) {
1079                 /* [XML] PlayerLogFile Filename to use for player debug logs. */
1080                 root->add_child("PlayerDebugLogFile")->add_child_text(_player_debug_log_file->string());
1081         }
1082         if (_player_content_directory) {
1083                 /* [XML] PlayerContentDirectory Directory to use for player content in the dual-screen mode. */
1084                 root->add_child("PlayerContentDirectory")->add_child_text(_player_content_directory->string());
1085         }
1086         if (_player_playlist_directory) {
1087                 /* [XML] PlayerPlaylistDirectory Directory to use for player playlists in the dual-screen mode. */
1088                 root->add_child("PlayerPlaylistDirectory")->add_child_text(_player_playlist_directory->string());
1089         }
1090         if (_player_kdm_directory) {
1091                 /* [XML] PlayerKDMDirectory Directory to use for player KDMs in the dual-screen mode. */
1092                 root->add_child("PlayerKDMDirectory")->add_child_text(_player_kdm_directory->string());
1093         }
1094         if (_audio_mapping) {
1095                 _audio_mapping->as_xml (root->add_child("AudioMapping"));
1096         }
1097         for (auto const& i: _custom_languages) {
1098                 root->add_child("CustomLanguage")->add_child_text(i.to_string());
1099         }
1100         for (auto const& initial: _initial_paths) {
1101                 if (initial.second) {
1102                         root->add_child(initial.first)->add_child_text(initial.second->string());
1103                 }
1104         }
1105         root->add_child("UseISDCFNameByDefault")->add_child_text(_use_isdcf_name_by_default ? "1" : "0");
1106         root->add_child("WriteKDMsToDisk")->add_child_text(_write_kdms_to_disk ? "1" : "0");
1107         root->add_child("EmailKDMs")->add_child_text(_email_kdms ? "1" : "0");
1108         root->add_child("DefaultKDMType")->add_child_text(dcp::formulation_to_string(_default_kdm_type));
1109         root->add_child("AutoCropThreshold")->add_child_text(raw_convert<string>(_auto_crop_threshold));
1110         if (_last_release_notes_version) {
1111                 root->add_child("LastReleaseNotesVersion")->add_child_text(*_last_release_notes_version);
1112         }
1113         if (_main_divider_sash_position) {
1114                 root->add_child("MainDividerSashPosition")->add_child_text(raw_convert<string>(*_main_divider_sash_position));
1115         }
1116         if (_main_content_divider_sash_position) {
1117                 root->add_child("MainContentDividerSashPosition")->add_child_text(raw_convert<string>(*_main_content_divider_sash_position));
1118         }
1119
1120         root->add_child("DefaultAddFileLocation")->add_child_text(
1121                 _default_add_file_location == DefaultAddFileLocation::SAME_AS_LAST_TIME ? "last" : "project"
1122                 );
1123
1124         /* [XML] AllowSMPTEBv20 1 to allow the user to choose SMPTE (Bv2.0 only) as a standard, otherwise 0 */
1125         root->add_child("AllowSMPTEBv20")->add_child_text(_allow_smpte_bv20 ? "1" : "0");
1126         /* [XML] ISDCFNamePartLength Maximum length of the "name" part of an ISDCF name, which should be 14 according to the standard */
1127         root->add_child("ISDCFNamePartLength")->add_child_text(raw_convert<string>(_isdcf_name_part_length));
1128
1129         _export.write(root->add_child("Export"));
1130
1131         auto target = config_write_file();
1132
1133         try {
1134                 auto const s = doc.write_to_string_formatted ();
1135                 boost::filesystem::path tmp (string(target.string()).append(".tmp"));
1136                 dcp::File f(tmp, "w");
1137                 if (!f) {
1138                         throw FileError (_("Could not open file for writing"), tmp);
1139                 }
1140                 f.checked_write(s.c_str(), s.bytes());
1141                 f.close();
1142                 dcp::filesystem::remove(target);
1143                 dcp::filesystem::rename(tmp, target);
1144         } catch (xmlpp::exception& e) {
1145                 string s = e.what ();
1146                 trim (s);
1147                 throw FileError (s, target);
1148         }
1149 }
1150
1151
1152 template <class T>
1153 void
1154 write_file (string root_node, string node, string version, list<shared_ptr<T>> things, boost::filesystem::path file)
1155 {
1156         xmlpp::Document doc;
1157         auto root = doc.create_root_node (root_node);
1158         root->add_child("Version")->add_child_text(version);
1159
1160         for (auto i: things) {
1161                 i->as_xml (root->add_child(node));
1162         }
1163
1164         try {
1165                 doc.write_to_file_formatted (file.string() + ".tmp");
1166                 dcp::filesystem::remove(file);
1167                 dcp::filesystem::rename(file.string() + ".tmp", file);
1168         } catch (xmlpp::exception& e) {
1169                 string s = e.what ();
1170                 trim (s);
1171                 throw FileError (s, file);
1172         }
1173 }
1174
1175
1176 void
1177 Config::write_cinemas () const
1178 {
1179         write_file ("Cinemas", "Cinema", "1", _cinemas, _cinemas_file);
1180 }
1181
1182
1183 void
1184 Config::write_dkdm_recipients () const
1185 {
1186         write_file ("DKDMRecipients", "DKDMRecipient", "1", _dkdm_recipients, _dkdm_recipients_file);
1187 }
1188
1189
1190 boost::filesystem::path
1191 Config::default_directory_or (boost::filesystem::path a) const
1192 {
1193         return directory_or (_default_directory, a);
1194 }
1195
1196 boost::filesystem::path
1197 Config::default_kdm_directory_or (boost::filesystem::path a) const
1198 {
1199         return directory_or (_default_kdm_directory, a);
1200 }
1201
1202 boost::filesystem::path
1203 Config::directory_or (optional<boost::filesystem::path> dir, boost::filesystem::path a) const
1204 {
1205         if (!dir) {
1206                 return a;
1207         }
1208
1209         boost::system::error_code ec;
1210         auto const e = dcp::filesystem::exists(*dir, ec);
1211         if (ec || !e) {
1212                 return a;
1213         }
1214
1215         return *dir;
1216 }
1217
1218 void
1219 Config::drop ()
1220 {
1221         delete _instance;
1222         _instance = nullptr;
1223 }
1224
1225 void
1226 Config::changed (Property what)
1227 {
1228         Changed (what);
1229 }
1230
1231 void
1232 Config::set_kdm_email_to_default ()
1233 {
1234         _kdm_subject = _("KDM delivery: $CPL_NAME");
1235
1236         _kdm_email = _(
1237                 "Dear Projectionist\n\n"
1238                 "Please find attached KDMs for $CPL_NAME.\n\n"
1239                 "Cinema: $CINEMA_NAME\n"
1240                 "Screen(s): $SCREENS\n\n"
1241                 "The KDMs are valid from $START_TIME until $END_TIME.\n\n"
1242                 "Best regards,\nDCP-o-matic"
1243                 );
1244 }
1245
1246 void
1247 Config::set_notification_email_to_default ()
1248 {
1249         _notification_subject = _("DCP-o-matic notification");
1250
1251         _notification_email = _(
1252                 "$JOB_NAME: $JOB_STATUS"
1253                 );
1254 }
1255
1256 void
1257 Config::reset_kdm_email ()
1258 {
1259         set_kdm_email_to_default ();
1260         changed ();
1261 }
1262
1263 void
1264 Config::reset_notification_email ()
1265 {
1266         set_notification_email_to_default ();
1267         changed ();
1268 }
1269
1270 void
1271 Config::set_cover_sheet_to_default ()
1272 {
1273         _cover_sheet = _(
1274                 "$CPL_NAME\n\n"
1275                 "CPL Filename: $CPL_FILENAME\n"
1276                 "Type: $TYPE\n"
1277                 "Format: $CONTAINER\n"
1278                 "Audio: $AUDIO\n"
1279                 "Audio Language: $AUDIO_LANGUAGE\n"
1280                 "Subtitle Language: $SUBTITLE_LANGUAGE\n"
1281                 "Length: $LENGTH\n"
1282                 "Size: $SIZE\n"
1283                 );
1284 }
1285
1286 void
1287 Config::add_to_history (boost::filesystem::path p)
1288 {
1289         add_to_history_internal (_history, p);
1290 }
1291
1292 /** Remove non-existent items from the history */
1293 void
1294 Config::clean_history ()
1295 {
1296         clean_history_internal (_history);
1297 }
1298
1299 void
1300 Config::add_to_player_history (boost::filesystem::path p)
1301 {
1302         add_to_history_internal (_player_history, p);
1303 }
1304
1305 /** Remove non-existent items from the player history */
1306 void
1307 Config::clean_player_history ()
1308 {
1309         clean_history_internal (_player_history);
1310 }
1311
1312 void
1313 Config::add_to_history_internal (vector<boost::filesystem::path>& h, boost::filesystem::path p)
1314 {
1315         /* Remove existing instances of this path in the history */
1316         h.erase (remove (h.begin(), h.end(), p), h.end ());
1317
1318         h.insert (h.begin (), p);
1319         if (h.size() > HISTORY_SIZE) {
1320                 h.pop_back ();
1321         }
1322
1323         changed (HISTORY);
1324 }
1325
1326 void
1327 Config::clean_history_internal (vector<boost::filesystem::path>& h)
1328 {
1329         auto old = h;
1330         h.clear ();
1331         for (auto i: old) {
1332                 try {
1333                         if (dcp::filesystem::is_directory(i)) {
1334                                 h.push_back (i);
1335                         }
1336                 } catch (...) {
1337                         /* We couldn't find out if it's a directory for some reason; just ignore it */
1338                 }
1339         }
1340 }
1341
1342
1343 bool
1344 Config::have_existing (string file)
1345 {
1346         return dcp::filesystem::exists(read_path(file));
1347 }
1348
1349
1350 void
1351 Config::read_cinemas (cxml::Document const & f)
1352 {
1353         _cinemas.clear ();
1354         for (auto i: f.node_children("Cinema")) {
1355                 /* Slightly grotty two-part construction of Cinema here so that we can use
1356                    shared_from_this.
1357                 */
1358                 auto cinema = make_shared<Cinema>(i);
1359                 cinema->read_screens (i);
1360                 _cinemas.push_back (cinema);
1361         }
1362 }
1363
1364 void
1365 Config::set_cinemas_file (boost::filesystem::path file)
1366 {
1367         if (file == _cinemas_file) {
1368                 return;
1369         }
1370
1371         _cinemas_file = file;
1372
1373         if (dcp::filesystem::exists(_cinemas_file)) {
1374                 /* Existing file; read it in */
1375                 cxml::Document f ("Cinemas");
1376                 f.read_file(dcp::filesystem::fix_long_path(_cinemas_file));
1377                 read_cinemas (f);
1378         }
1379
1380         changed (CINEMAS);
1381         changed (OTHER);
1382 }
1383
1384
1385 void
1386 Config::read_dkdm_recipients (cxml::Document const & f)
1387 {
1388         _dkdm_recipients.clear ();
1389         for (auto i: f.node_children("DKDMRecipient")) {
1390                 _dkdm_recipients.push_back (make_shared<DKDMRecipient>(i));
1391         }
1392 }
1393
1394
1395 void
1396 Config::save_template (shared_ptr<const Film> film, string name) const
1397 {
1398         film->write_template (template_write_path(name));
1399 }
1400
1401
1402 list<string>
1403 Config::templates () const
1404 {
1405         if (!dcp::filesystem::exists(read_path("templates"))) {
1406                 return {};
1407         }
1408
1409         list<string> n;
1410         for (auto const& i: dcp::filesystem::directory_iterator(read_path("templates"))) {
1411                 n.push_back (i.path().filename().string());
1412         }
1413         return n;
1414 }
1415
1416 bool
1417 Config::existing_template (string name) const
1418 {
1419         return dcp::filesystem::exists(template_read_path(name));
1420 }
1421
1422
1423 boost::filesystem::path
1424 Config::template_read_path (string name) const
1425 {
1426         return read_path("templates") / tidy_for_filename (name);
1427 }
1428
1429
1430 boost::filesystem::path
1431 Config::template_write_path (string name) const
1432 {
1433         return write_path("templates") / tidy_for_filename (name);
1434 }
1435
1436
1437 void
1438 Config::rename_template (string old_name, string new_name) const
1439 {
1440         dcp::filesystem::rename(template_read_path(old_name), template_write_path(new_name));
1441 }
1442
1443 void
1444 Config::delete_template (string name) const
1445 {
1446         dcp::filesystem::remove(template_write_path(name));
1447 }
1448
1449 /** @return Path to the config.xml containing the actual settings, following a link if required */
1450 boost::filesystem::path
1451 config_file (boost::filesystem::path main)
1452 {
1453         cxml::Document f ("Config");
1454         if (!dcp::filesystem::exists(main)) {
1455                 /* It doesn't exist, so there can't be any links; just return it */
1456                 return main;
1457         }
1458
1459         /* See if there's a link */
1460         try {
1461                 f.read_file(dcp::filesystem::fix_long_path(main));
1462                 auto link = f.optional_string_child("Link");
1463                 if (link) {
1464                         return *link;
1465                 }
1466         } catch (xmlpp::exception& e) {
1467                 /* There as a problem reading the main configuration file,
1468                    so there can't be a link.
1469                 */
1470         }
1471
1472         return main;
1473 }
1474
1475
1476 boost::filesystem::path
1477 Config::config_read_file ()
1478 {
1479         return config_file (read_path("config.xml"));
1480 }
1481
1482
1483 boost::filesystem::path
1484 Config::config_write_file ()
1485 {
1486         return config_file (write_path("config.xml"));
1487 }
1488
1489
1490 void
1491 Config::reset_cover_sheet ()
1492 {
1493         set_cover_sheet_to_default ();
1494         changed ();
1495 }
1496
1497 void
1498 Config::link (boost::filesystem::path new_file) const
1499 {
1500         xmlpp::Document doc;
1501         doc.create_root_node("Config")->add_child("Link")->add_child_text(new_file.string());
1502         try {
1503                 doc.write_to_file_formatted(write_path("config.xml").string());
1504         } catch (xmlpp::exception& e) {
1505                 string s = e.what ();
1506                 trim (s);
1507                 throw FileError (s, write_path("config.xml"));
1508         }
1509 }
1510
1511 void
1512 Config::copy_and_link (boost::filesystem::path new_file) const
1513 {
1514         write ();
1515         dcp::filesystem::copy_file(config_read_file(), new_file, boost::filesystem::copy_option::overwrite_if_exists);
1516         link (new_file);
1517 }
1518
1519 bool
1520 Config::have_write_permission () const
1521 {
1522         dcp::File f(config_write_file(), "r+");
1523         return static_cast<bool>(f);
1524 }
1525
1526 /** @param  output_channels Number of output channels in use.
1527  *  @return Audio mapping for this output channel count (may be a default).
1528  */
1529 AudioMapping
1530 Config::audio_mapping (int output_channels)
1531 {
1532         if (!_audio_mapping || _audio_mapping->output_channels() != output_channels) {
1533                 /* Set up a default */
1534                 _audio_mapping = AudioMapping (MAX_DCP_AUDIO_CHANNELS, output_channels);
1535                 if (output_channels == 2) {
1536                         /* Special case for stereo output.
1537                            Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
1538                            Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
1539                         */
1540                         _audio_mapping->set (dcp::Channel::LEFT,   0, 1 / sqrt(2));  // L   -> Lt
1541                         _audio_mapping->set (dcp::Channel::RIGHT,  1, 1 / sqrt(2));  // R   -> Rt
1542                         _audio_mapping->set (dcp::Channel::CENTRE, 0, 1 / 2.0);      // C   -> Lt
1543                         _audio_mapping->set (dcp::Channel::CENTRE, 1, 1 / 2.0);      // C   -> Rt
1544                         _audio_mapping->set (dcp::Channel::LFE,    0, 1 / sqrt(10)); // Lfe -> Lt
1545                         _audio_mapping->set (dcp::Channel::LFE,    1, 1 / sqrt(10)); // Lfe -> Rt
1546                         _audio_mapping->set (dcp::Channel::LS,     0, 1 / sqrt(2));  // Ls  -> Lt
1547                         _audio_mapping->set (dcp::Channel::RS,     1, 1 / sqrt(2));  // Rs  -> Rt
1548                 } else {
1549                         /* 1:1 mapping */
1550                         for (int i = 0; i < min (MAX_DCP_AUDIO_CHANNELS, output_channels); ++i) {
1551                                 _audio_mapping->set (i, i, 1);
1552                         }
1553                 }
1554         }
1555
1556         return *_audio_mapping;
1557 }
1558
1559 void
1560 Config::set_audio_mapping (AudioMapping m)
1561 {
1562         _audio_mapping = m;
1563         changed (AUDIO_MAPPING);
1564 }
1565
1566 void
1567 Config::set_audio_mapping_to_default ()
1568 {
1569         DCPOMATIC_ASSERT (_audio_mapping);
1570         auto const ch = _audio_mapping->output_channels ();
1571         _audio_mapping = boost::none;
1572         _audio_mapping = audio_mapping (ch);
1573         changed (AUDIO_MAPPING);
1574 }
1575
1576
1577 void
1578 Config::add_custom_language (dcp::LanguageTag tag)
1579 {
1580         if (find(_custom_languages.begin(), _custom_languages.end(), tag) == _custom_languages.end()) {
1581                 _custom_languages.push_back (tag);
1582                 changed ();
1583         }
1584 }
1585
1586
1587 optional<Config::BadReason>
1588 Config::check_certificates () const
1589 {
1590         optional<BadReason> bad;
1591
1592         for (auto const& i: _signer_chain->unordered()) {
1593                 if (i.has_utf8_strings()) {
1594                         bad = BAD_SIGNER_UTF8_STRINGS;
1595                 }
1596                 if ((i.not_after().year() - i.not_before().year()) > 15) {
1597                         bad = BAD_SIGNER_VALIDITY_TOO_LONG;
1598                 }
1599                 if (dcp::escape_digest(i.subject_dn_qualifier()) != dcp::public_key_digest(i.public_key())) {
1600                         bad = BAD_SIGNER_DN_QUALIFIER;
1601                 }
1602         }
1603
1604         if (!_signer_chain->chain_valid() || !_signer_chain->private_key_valid()) {
1605                 bad = BAD_SIGNER_INCONSISTENT;
1606         }
1607
1608         if (!_decryption_chain->chain_valid() || !_decryption_chain->private_key_valid()) {
1609                 bad = BAD_DECRYPTION_INCONSISTENT;
1610         }
1611
1612         return bad;
1613 }
1614
1615
1616 void
1617 save_all_config_as_zip (boost::filesystem::path zip_file)
1618 {
1619         Zipper zipper (zip_file);
1620
1621         auto config = Config::instance();
1622         zipper.add ("config.xml", dcp::file_to_string(config->config_read_file()));
1623         if (dcp::filesystem::exists(config->cinemas_file())) {
1624                 zipper.add ("cinemas.xml", dcp::file_to_string(config->cinemas_file()));
1625         }
1626         if (dcp::filesystem::exists(config->dkdm_recipients_file())) {
1627                 zipper.add ("dkdm_recipients.xml", dcp::file_to_string(config->dkdm_recipients_file()));
1628         }
1629
1630         zipper.close ();
1631 }
1632
1633
1634 void
1635 Config::set_initial_path(string id, boost::filesystem::path path)
1636 {
1637         auto iter = _initial_paths.find(id);
1638         DCPOMATIC_ASSERT(iter != _initial_paths.end());
1639         iter->second = path;
1640         changed();
1641 }
1642
1643
1644 optional<boost::filesystem::path>
1645 Config::initial_path(string id) const
1646 {
1647         auto iter = _initial_paths.find(id);
1648         if (iter == _initial_paths.end()) {
1649                 return {};
1650         }
1651         return iter->second;
1652 }
1653