Hand-apply 63b62aa703c2628b27b577114081b265f237dadb from master;
[dcpomatic.git] / src / lib / util.cc
index 60953b544d1a0c26b3816c674db3f9612b4ee181..bf4c7424417e92dde0de6a1127415a72fe061ee5 100644 (file)
@@ -22,7 +22,6 @@
  *  @brief Some utility functions and classes.
  */
 
-#include <sstream>
 #include <iomanip>
 #include <iostream>
 #include <fstream>
 #include <glib.h>
 #include <openjpeg.h>
 #include <pangomm/init.h>
+#ifdef DCPOMATIC_IMAGE_MAGICK
 #include <magick/MagickCore.h>
+#else
+#include <magick/common.h>
+#include <magick/magick_config.h>
+#endif
 #include <magick/version.h>
 #include <dcp/version.h>
 #include <dcp/util.h>
@@ -72,6 +76,7 @@ extern "C" {
 #include "rect.h"
 #include "md5_digester.h"
 #include "audio_processor.h"
+#include "safe_stringstream.h"
 #ifdef DCPOMATIC_WINDOWS
 #include "stack.hpp"
 #endif
@@ -79,7 +84,6 @@ extern "C" {
 #include "i18n.h"
 
 using std::string;
-using std::stringstream;
 using std::setfill;
 using std::ostream;
 using std::endl;
@@ -123,7 +127,7 @@ seconds_to_hms (int s)
        int h = m / 60;
        m -= (h * 60);
 
-       stringstream hms;
+       SafeStringStream hms;
        hms << h << N_(":");
        hms.width (2);
        hms << std::setfill ('0') << m << N_(":");
@@ -144,7 +148,7 @@ seconds_to_approximate_hms (int s)
        int h = m / 60;
        m -= (h * 60);
 
-       stringstream ap;
+       SafeStringStream ap;
 
        bool const hours = h > 0;
        bool const minutes = h < 10 && m > 0;
@@ -152,14 +156,11 @@ seconds_to_approximate_hms (int s)
 
        if (hours) {
                if (m > 30 && !minutes) {
-                       ap << (h + 1) << N_(" ") << _("hours");
+                       /// TRANSLATORS: h here is an abbreviation for hours
+                       ap << (h + 1) << _("h");
                } else {
-                       ap << h << N_(" ");
-                       if (h == 1) {
-                               ap << _("hour");
-                       } else {
-                               ap << _("hours");
-                       }
+                       /// TRANSLATORS: h here is an abbreviation for hours
+                       ap << h << _("h");
                }
 
                if (minutes | seconds) {
@@ -170,14 +171,11 @@ seconds_to_approximate_hms (int s)
        if (minutes) {
                /* Minutes */
                if (s > 30 && !seconds) {
-                       ap << (m + 1) << N_(" ") << _("minutes");
+                       /// TRANSLATORS: m here is an abbreviation for minutes
+                       ap << (m + 1) << _("m");
                } else {
-                       ap << m << N_(" ");
-                       if (m == 1) {
-                               ap << _("minute");
-                       } else {
-                               ap << _("minutes");
-                       }
+                       /// TRANSLATORS: m here is an abbreviation for minutes
+                       ap << m << _("m");
                }
 
                if (seconds) {
@@ -187,12 +185,8 @@ seconds_to_approximate_hms (int s)
 
        if (seconds) {
                /* Seconds */
-               ap << s << N_(" ");
-               if (s == 1) {
-                       ap << _("second");
-               } else {
-                       ap << _("seconds");
-               }
+               /// TRANSLATORS: s here is an abbreviation for seconds
+               ap << s << _("s");
        }
 
        return ap.str ();
@@ -263,7 +257,7 @@ stacktrace (ostream& out, int levels)
 static string
 ffmpeg_version_to_string (int v)
 {
-       stringstream s;
+       SafeStringStream s;
        s << ((v & 0xff0000) >> 16) << N_(".") << ((v & 0xff00) >> 8) << N_(".") << (v & 0xff);
        return s.str ();
 }
@@ -288,6 +282,12 @@ LONG WINAPI exception_handler(struct _EXCEPTION_POINTERS *)
 }
 #endif
 
+void
+set_backtrace_file (boost::filesystem::path p)
+{
+       backtrace_file = p;
+}
+
 /* From http://stackoverflow.com/questions/2443135/how-do-i-find-where-an-exception-was-thrown-in-c */
 void
 terminate ()
@@ -323,8 +323,9 @@ void
 dcpomatic_setup ()
 {
 #ifdef DCPOMATIC_WINDOWS
-       backtrace_file /= g_get_user_config_dir ();
-       backtrace_file /= "backtrace.txt";
+       boost::filesystem::path p = g_get_user_config_dir ();
+       p /= "backtrace.txt";
+       set_backtrace_file (p);
        SetUnhandledExceptionFilter(exception_handler);
 
        /* Dark voodoo which, I think, gets boost::filesystem::path to
@@ -384,35 +385,42 @@ mo_path ()
 }
 #endif
 
+#ifdef DCPOMATIC_OSX
+boost::filesystem::path
+mo_path ()
+{
+       return "DCP-o-matic 2.app/Contents/Resources";
+}
+#endif
+
 void
 dcpomatic_setup_gettext_i18n (string lang)
 {
-#ifdef DCPOMATIC_POSIX
+#ifdef DCPOMATIC_LINUX
        lang += ".UTF8";
 #endif
 
        if (!lang.empty ()) {
-               /* Override our environment language; this is essential on
-                  Windows.
+               /* Override our environment language.  Note that the caller must not
+                  free the string passed into putenv().
                */
-               char cmd[64];
-               snprintf (cmd, sizeof(cmd), "LANGUAGE=%s", lang.c_str ());
-               putenv (cmd);
-               snprintf (cmd, sizeof(cmd), "LANG=%s", lang.c_str ());
-               putenv (cmd);
-               snprintf (cmd, sizeof(cmd), "LC_ALL=%s", lang.c_str ());
-               putenv (cmd);
+               string s = String::compose ("LANGUAGE=%1", lang);
+               putenv (strdup (s.c_str ()));
+               s = String::compose ("LANG=%1", lang);
+               putenv (strdup (s.c_str ()));
+               s = String::compose ("LC_ALL=%1", lang);
+               putenv (strdup (s.c_str ()));
        }
 
        setlocale (LC_ALL, "");
        textdomain ("libdcpomatic");
 
-#ifdef DCPOMATIC_WINDOWS
+#if defined(DCPOMATIC_WINDOWS) || defined(DCPOMATIC_OSX)
        bindtextdomain ("libdcpomatic", mo_path().string().c_str());
        bind_textdomain_codeset ("libdcpomatic", "UTF8");
 #endif 
 
-#ifdef DCPOMATIC_POSIX
+#ifdef DCPOMATIC_LINUX
        bindtextdomain ("libdcpomatic", POSIX_LOCALE_PREFIX);
 #endif
 }
@@ -466,7 +474,10 @@ md5_digest (vector<boost::filesystem::path> files, shared_ptr<Job> job)
 
                while (remaining > 0) {
                        int const t = min (remaining, buffer_size);
-                       fread (buffer, 1, t, f);
+                       int const r = fread (buffer, 1, t, f);
+                       if (r != t) {
+                               throw ReadFileError (files[i], errno);
+                       }
                        digester.add (buffer, t);
                        remaining -= t;
 
@@ -556,7 +567,7 @@ Socket::accept (int port)
        _acceptor->async_accept (_socket, boost::lambda::var(ec) = boost::lambda::_1);
        do {
                _io_service.run_one ();
-       } while (ec == boost::asio::error::would_block );
+       } while (ec == boost::asio::error::would_block);
 
        delete _acceptor;
        _acceptor = 0;
@@ -756,10 +767,9 @@ audio_channel_name (int c)
 {
        assert (MAX_DCP_AUDIO_CHANNELS == 12);
 
-       /* TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency
-          enhancement channel (sub-woofer).  HI is the hearing-impaired audio track and
-          VI is the visually-impaired audio track (audio describe).
-       */
+       /// TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency
+       /// enhancement channel (sub-woofer).  HI is the hearing-impaired audio track and
+       /// VI is the visually-impaired audio track (audio describe).
        string const channels[] = {
                _("Left"),
                _("Right"),
@@ -783,7 +793,19 @@ valid_image_file (boost::filesystem::path f)
 {
        string ext = f.extension().string();
        transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
-       return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp" || ext == ".tga" || ext == ".dpx");
+       return (
+               ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" ||
+               ext == ".png" || ext == ".bmp" || ext == ".tga" || ext == ".dpx" ||
+               ext == ".j2c" || ext == ".j2k"
+               );
+}
+
+bool
+valid_j2k_file (boost::filesystem::path f)
+{
+       string ext = f.extension().string();
+       transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
+       return (ext == ".j2k" || ext == ".j2c");
 }
 
 string
@@ -889,7 +911,7 @@ divide_with_round (int64_t a, int64_t b)
 string
 dependency_version_summary ()
 {
-       stringstream s;
+       SafeStringStream s;
        s << N_("libopenjpeg ") << opj_version () << N_(", ")
          << N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ")
          << N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ")