+ dcp::File f(from, "rb");
+ if (!f) {
+ throw OpenFileError (from, errno, OpenFileError::READ);
+ }
+ dcp::File t(to, "wb");
+ if (!t) {
+ throw OpenFileError (to, errno, OpenFileError::WRITE);
+ }
+
+ /* on the order of a second's worth of copying */
+ boost::uintmax_t const chunk = 20 * 1024 * 1024;
+
+ std::vector<uint8_t> buffer(chunk);
+
+ boost::uintmax_t const total = boost::filesystem::file_size (from);
+ boost::uintmax_t remaining = total;
+
+ while (remaining) {
+ boost::uintmax_t this_time = min (chunk, remaining);
+ size_t N = f.read(buffer.data(), 1, chunk);
+ if (N < this_time) {
+ throw ReadFileError (from, errno);
+ }
+
+ N = t.write(buffer.data(), 1, this_time);
+ if (N < this_time) {
+ throw WriteFileError (to, errno);
+ }
+
+ progress (1 - float(remaining) / total);
+ remaining -= this_time;
+ }
+}
+
+
+dcp::Size
+scale_for_display (dcp::Size s, dcp::Size display_container, dcp::Size film_container, PixelQuanta quanta)
+{
+ /* Now scale it down if the display container is smaller than the film container */
+ if (display_container != film_container) {
+ float const scale = min (
+ float (display_container.width) / film_container.width,
+ float (display_container.height) / film_container.height
+ );
+
+ s.width = lrintf (s.width * scale);
+ s.height = lrintf (s.height * scale);
+ s = quanta.round (s);
+ }
+
+ return s;
+}
+
+
+dcp::DecryptedKDM
+decrypt_kdm_with_helpful_error (dcp::EncryptedKDM kdm)
+{
+ try {
+ return dcp::DecryptedKDM (kdm, Config::instance()->decryption_chain()->key().get());
+ } catch (dcp::KDMDecryptionError& e) {
+ /* Try to flesh out the error a bit */
+ auto const kdm_subject_name = kdm.recipient_x509_subject_name();
+ bool on_chain = false;
+ auto dc = Config::instance()->decryption_chain();
+ for (auto i: dc->root_to_leaf()) {
+ if (i.subject() == kdm_subject_name) {
+ on_chain = true;
+ }
+ }
+ if (!on_chain) {
+ throw KDMError (_("This KDM was not made for DCP-o-matic's decryption certificate."), e.what());
+ } else if (kdm_subject_name != dc->leaf().subject()) {
+ throw KDMError (_("This KDM was made for DCP-o-matic but not for its leaf certificate."), e.what());