Be more careful with fread in various places.
[dcpomatic.git] / src / lib / util.cc
index 4ffe3bd12bb8ed4f76092286f8aad08ce4fe0691..5eba8d73a0f214f07339998c9a6c4543f5f86e2f 100644 (file)
@@ -49,9 +49,6 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 }
 #include <curl/curl.h>
-#ifdef DCPOMATIC_GRAPHICS_MAGICK
-#include <Magick++.h>
-#endif
 #include <glib.h>
 #include <pangomm/init.h>
 #include <boost/algorithm/string.hpp>
@@ -104,6 +101,7 @@ using dcp::locale_convert;
  *  in during App::onInit().
  */
 string program_name;
+bool is_batch_converter = false;
 static boost::thread::id ui_thread;
 static boost::filesystem::path backtrace_file;
 
@@ -127,6 +125,22 @@ seconds_to_hms (int s)
        return buffer;
 }
 
+string
+time_to_hmsf (DCPTime time, Frame rate)
+{
+       Frame f = time.frames_round (rate);
+       int s = f / rate;
+       f -= (s * rate);
+       int m = s / 60;
+       s -= m * 60;
+       int h = m / 60;
+       m -= h * 60;
+
+       char buffer[64];
+       snprintf (buffer, sizeof(buffer), "%d:%02d:%02d.%d", h, m, s, static_cast<int>(f));
+       return buffer;
+}
+
 /** @param s Number of seconds.
  *  @return String containing an approximate description of s (e.g. "about 2 hours")
  */
@@ -140,18 +154,27 @@ seconds_to_approximate_hms (int s)
 
        string ap;
 
-       bool const hours = h > 0;
-       bool const minutes = h < 6 && m > 0;
-       bool const seconds = h == 0 && m < 10 && s > 0;
+       bool hours = h > 0;
+       bool minutes = h < 6 && m > 0;
+       bool seconds = h == 0 && m < 10 && s > 0;
 
-       if (hours) {
-               if (m > 30 && !minutes) {
-                       /// TRANSLATORS: h here is an abbreviation for hours
-                       ap += locale_convert<string>(h + 1) + _("h");
-               } else {
-                       /// TRANSLATORS: h here is an abbreviation for hours
-                       ap += locale_convert<string>(h) + _("h");
+       if (m > 30 && !minutes) {
+               /* round up the hours */
+               ++h;
+       }
+       if (s > 30 && !seconds) {
+               /* round up the minutes */
+               ++m;
+               if (m == 60) {
+                       m = 0;
+                       minutes = false;
+                       ++h;
                }
+       }
+
+       if (hours) {
+               /// TRANSLATORS: h here is an abbreviation for hours
+               ap += locale_convert<string>(h) + _("h");
 
                if (minutes || seconds) {
                        ap += N_(" ");
@@ -159,14 +182,8 @@ seconds_to_approximate_hms (int s)
        }
 
        if (minutes) {
-               /* Minutes */
-               if (s > 30 && !seconds) {
-                       /// TRANSLATORS: m here is an abbreviation for minutes
-                       ap += locale_convert<string>(m + 1) + _("m");
-               } else {
-                       /// TRANSLATORS: m here is an abbreviation for minutes
-                       ap += locale_convert<string>(m) + _("m");
-               }
+               /// TRANSLATORS: m here is an abbreviation for minutes
+               ap += locale_convert<string>(m) + _("m");
 
                if (seconds) {
                        ap += N_(" ");
@@ -329,11 +346,11 @@ dcpomatic_setup ()
        avfilter_register_all ();
 
 #ifdef DCPOMATIC_OSX
-       /* Add our lib directory to the libltdl search path so that
+       /* Add our library directory to the libltdl search path so that
           xmlsec can find xmlsec1-openssl.
        */
        boost::filesystem::path lib = app_contents ();
-       lib /= "lib";
+       lib /= "Frameworks";
        setenv ("LTDL_LIBRARY_PATH", lib.c_str (), 1);
 #endif
 
@@ -352,10 +369,6 @@ dcpomatic_setup ()
 
        curl_global_init (CURL_GLOBAL_ALL);
 
-#ifdef DCPOMATIC_GRAPHICS_MAGICK
-       Magick::InitializeMagick (0);
-#endif
-
        ui_thread = boost::this_thread::get_id ();
 }
 
@@ -431,7 +444,7 @@ digest_head_tail (vector<boost::filesystem::path> files, boost::uintmax_t size)
                }
 
                boost::uintmax_t this_time = min (to_do, boost::filesystem::file_size (files[i]));
-               fread (p, 1, this_time, f);
+               checked_fread (p, this_time, f, files[i]);
                p += this_time;
                to_do -= this_time;
                fclose (f);
@@ -452,7 +465,7 @@ digest_head_tail (vector<boost::filesystem::path> files, boost::uintmax_t size)
 
                boost::uintmax_t this_time = min (to_do, boost::filesystem::file_size (files[i]));
                dcpomatic_fseek (f, -this_time, SEEK_END);
-               fread (p, 1, this_time, f);
+               checked_fread (p, this_time, f, files[i]);
                p += this_time;
                to_do -= this_time;
                fclose (f);
@@ -557,7 +570,8 @@ valid_image_file (boost::filesystem::path f)
        return (
                ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" ||
                ext == ".png" || ext == ".bmp" || ext == ".tga" || ext == ".dpx" ||
-               ext == ".j2c" || ext == ".j2k" || ext == ".jp2"
+               ext == ".j2c" || ext == ".j2k" || ext == ".jp2" || ext == ".exr" ||
+               ext == ".jpf"
                );
 }
 
@@ -701,7 +715,7 @@ careful_string_filter (string s)
        */
 
        string out;
-       string const allowed = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_%.";
+       string const allowed = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_%.+";
        for (size_t i = 0; i < s.size(); ++i) {
                if (allowed.find (s[i]) != string::npos) {
                        out += s[i];
@@ -758,3 +772,26 @@ remap (shared_ptr<const AudioBuffers> input, int output_channels, AudioMapping m
 
        return mapped;
 }
+
+Eyes
+increment_eyes (Eyes e)
+{
+       if (e == EYES_LEFT) {
+               return EYES_RIGHT;
+       }
+
+       return EYES_LEFT;
+}
+
+void
+checked_fread (void* ptr, size_t size, FILE* stream, boost::filesystem::path path)
+{
+       size_t N = fread (ptr, 1, size, stream);
+       if (N != size) {
+               if (ferror(stream)) {
+                       throw FileError (String::compose("fread error %1", errno), path);
+               } else {
+                       throw FileError ("Unexpected short read", path);
+               }
+       }
+}