Hopefully fix up gettext in both libdvdomatic and the wx code.
[dcpomatic.git] / src / lib / util.cc
index 872985024ac9a5779bfab4f9fa6fdd4988984047..3d70a3122166bce4f66b1f50f58fea05bb822954 100644 (file)
@@ -61,6 +61,8 @@ extern "C" {
 #include "sound_processor.h"
 #include "config.h"
 
+#include "i18n.h"
+
 using namespace std;
 using namespace boost;
 using libdcp::Size;
@@ -83,9 +85,9 @@ seconds_to_hms (int s)
        m -= (h * 60);
 
        stringstream hms;
-       hms << h << ":";
+       hms << h << N_(":");
        hms.width (2);
-       hms << setfill ('0') << m << ":";
+       hms << setfill ('0') << m << N_(":");
        hms.width (2);
        hms << setfill ('0') << s;
 
@@ -107,22 +109,22 @@ seconds_to_approximate_hms (int s)
        
        if (h > 0) {
                if (m > 30) {
-                       ap << (h + 1) << " hours";
+                       ap << (h + 1) << N_(" ") << _("hours");
                } else {
                        if (h == 1) {
-                               ap << "1 hour";
+                               ap << N_("1 ") << _("hour");
                        } else {
-                               ap << h << " hours";
+                               ap << h << N_(" ") << _("hours");
                        }
                }
        } else if (m > 0) {
                if (m == 1) {
-                       ap << "1 minute";
+                       ap << N_("1 ") << _("minute");
                } else {
-                       ap << m << " minutes";
+                       ap << m << N_(" ") << _("minutes");
                }
        } else {
-               ap << s << " seconds";
+               ap << s << N_(" ") << _("seconds");
        }
 
        return ap.str ();
@@ -135,12 +137,12 @@ seconds_to_approximate_hms (int s)
 static string
 demangle (string l)
 {
-       string::size_type const b = l.find_first_of ("(");
+       string::size_type const b = l.find_first_of (N_("("));
        if (b == string::npos) {
                return l;
        }
 
-       string::size_type const p = l.find_last_of ("+");
+       string::size_type const p = l.find_last_of (N_("+"));
        if (p == string::npos) {
                return l;
        }
@@ -183,7 +185,7 @@ stacktrace (ostream& out, int levels)
      
        if (strings) {
                for (i = 0; i < size && (levels == 0 || i < size_t(levels)); i++) {
-                       out << "  " << demangle (strings[i]) << endl;
+                       out << N_("  ") << demangle (strings[i]) << endl;
                }
                
                free (strings);
@@ -198,7 +200,7 @@ static string
 ffmpeg_version_to_string (int v)
 {
        stringstream s;
-       s << ((v & 0xff0000) >> 16) << "." << ((v & 0xff00) >> 8) << "." << (v & 0xff);
+       s << ((v & 0xff0000) >> 16) << N_(".") << ((v & 0xff00) >> 8) << N_(".") << (v & 0xff);
        return s.str ();
 }
 
@@ -207,16 +209,16 @@ string
 dependency_version_summary ()
 {
        stringstream s;
-       s << "libopenjpeg " << opj_version () << ", "
-         << "libavcodec " << ffmpeg_version_to_string (avcodec_version()) << ", "
-         << "libavfilter " << ffmpeg_version_to_string (avfilter_version()) << ", "
-         << "libavformat " << ffmpeg_version_to_string (avformat_version()) << ", "
-         << "libavutil " << ffmpeg_version_to_string (avutil_version()) << ", "
-         << "libpostproc " << ffmpeg_version_to_string (postproc_version()) << ", "
-         << "libswscale " << ffmpeg_version_to_string (swscale_version()) << ", "
-         << MagickVersion << ", "
-         << "libssh " << ssh_version (0) << ", "
-         << "libdcp " << libdcp::version << " git " << libdcp::git_commit;
+       s << N_("libopenjpeg ") << opj_version () << N_(", ")
+         << N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ")
+         << N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ")
+         << N_("libavformat ") << ffmpeg_version_to_string (avformat_version()) << N_(", ")
+         << N_("libavutil ") << ffmpeg_version_to_string (avutil_version()) << N_(", ")
+         << N_("libpostproc ") << ffmpeg_version_to_string (postproc_version()) << N_(", ")
+         << N_("libswscale ") << ffmpeg_version_to_string (swscale_version()) << N_(", ")
+         << MagickVersion << N_(", ")
+         << N_("libssh ") << ssh_version (0) << N_(", ")
+         << N_("libdcp ") << libdcp::version << N_(" git ") << libdcp::git_commit;
 
        return s.str ();
 }
@@ -233,6 +235,11 @@ seconds (struct timeval t)
 void
 dvdomatic_setup ()
 {
+       bindtextdomain ("libdvdomatic", LOCALE_PREFIX);
+       setlocale (LC_ALL, "");
+       
+       avfilter_register_all ();
+       
        Format::setup_formats ();
        DCPContentType::setup_dcp_content_types ();
        Scaler::setup_scalers ();
@@ -250,7 +257,7 @@ string
 crop_string (Position start, libdcp::Size size)
 {
        stringstream s;
-       s << "crop=" << size.width << ":" << size.height << ":" << start.x << ":" << start.y;
+       s << N_("crop=") << size.width << N_(":") << size.height << N_(":") << start.x << N_(":") << start.y;
        return s.str ();
 }
 
@@ -266,7 +273,7 @@ split_at_spaces_considering_quotes (string s)
        for (string::size_type i = 0; i < s.length(); ++i) {
                if (s[i] == ' ' && !in_quotes) {
                        out.push_back (c);
-                       c = "";
+                       c = N_("");
                } else if (s[i] == '"') {
                        in_quotes = !in_quotes;
                } else {
@@ -333,7 +340,8 @@ md5_digest (string file)
        return s.str ();
 }
 
-static bool about_equal (float a, float b)
+static bool
+about_equal (float a, float b)
 {
        /* A film of F seconds at f FPS will be Ff frames;
           Consider some delta FPS d, so if we run the same
@@ -420,7 +428,7 @@ DCPFrameRate::DCPFrameRate (float source_fps)
        }
 
        if (!best) {
-               throw EncodeError ("cannot find a suitable DCP frame rate for this source");
+               throw EncodeError (_("cannot find a suitable DCP frame rate for this source"));
        }
 
        frames_per_second = best->dcp;
@@ -473,19 +481,19 @@ colour_lut_index_to_name (int index)
 {
        switch (index) {
        case 0:
-               return "sRGB";
+               return _("sRGB");
        case 1:
-               return "Rec 709";
+               return _("Rec 709");
        }
 
        assert (false);
-       return "";
+       return N_("");
 }
 
-Socket::Socket ()
+Socket::Socket (int timeout)
        : _deadline (_io_service)
        , _socket (_io_service)
-       , _buffer_data (0)
+       , _timeout (timeout)
 {
        _deadline.expires_at (posix_time::pos_infin);
        check ();
@@ -502,14 +510,13 @@ Socket::check ()
        _deadline.async_wait (boost::bind (&Socket::check, this));
 }
 
-/** Blocking connect with timeout.
+/** Blocking connect.
  *  @param endpoint End-point to connect to.
- *  @param timeout Time-out in seconds.
  */
 void
-Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint, int timeout)
+Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint)
 {
-       _deadline.expires_from_now (posix_time::seconds (timeout));
+       _deadline.expires_from_now (posix_time::seconds (_timeout));
        system::error_code ec = asio::error::would_block;
        _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1);
        do {
@@ -517,133 +524,65 @@ Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint,
        } while (ec == asio::error::would_block);
 
        if (ec || !_socket.is_open ()) {
-               throw NetworkError ("connect timed out");
+               throw NetworkError (_("connect timed out"));
        }
 }
 
-/** Blocking write with timeout.
+/** Blocking write.
  *  @param data Buffer to write.
  *  @param size Number of bytes to write.
- *  @param timeout Time-out, in seconds.
  */
 void
-Socket::write (uint8_t const * data, int size, int timeout)
+Socket::write (uint8_t const * data, int size)
 {
-       _deadline.expires_from_now (posix_time::seconds (timeout));
+       _deadline.expires_from_now (posix_time::seconds (_timeout));
        system::error_code ec = asio::error::would_block;
 
        asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1);
+       
        do {
                _io_service.run_one ();
        } while (ec == asio::error::would_block);
 
        if (ec) {
-               throw NetworkError ("write timed out");
+               throw NetworkError (ec.message ());
        }
 }
 
-/** Blocking read with timeout.
+void
+Socket::write (uint32_t v)
+{
+       v = htonl (v);
+       write (reinterpret_cast<uint8_t*> (&v), 4);
+}
+
+/** Blocking read.
  *  @param data Buffer to read to.
  *  @param size Number of bytes to read.
- *  @param timeout Time-out, in seconds.
  */
-int
-Socket::read (uint8_t* data, int size, int timeout)
+void
+Socket::read (uint8_t* data, int size)
 {
-       _deadline.expires_from_now (posix_time::seconds (timeout));
+       _deadline.expires_from_now (posix_time::seconds (_timeout));
        system::error_code ec = asio::error::would_block;
 
-       int amount_read = 0;
-
-       _socket.async_read_some (
-               asio::buffer (data, size),
-               (lambda::var(ec) = lambda::_1, lambda::var(amount_read) = lambda::_2)
-               );
+       asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1);
 
        do {
                _io_service.run_one ();
        } while (ec == asio::error::would_block);
        
        if (ec) {
-               amount_read = 0;
+               throw NetworkError (ec.message ());
        }
-
-       return amount_read;
 }
 
-/** Mark some data as being `consumed', so that it will not be returned
- *  as data again.
- *  @param size Amount of data to consume, in bytes.
- */
-void
-Socket::consume (int size)
+uint32_t
+Socket::read_uint32 ()
 {
-       assert (_buffer_data >= size);
-       
-       _buffer_data -= size;
-       if (_buffer_data > 0) {
-               /* Shift still-valid data to the start of the buffer */
-               memmove (_buffer, _buffer + size, _buffer_data);
-       }
-}
-
-/** Read a definite amount of data from our socket, and mark
- *  it as consumed.
- *  @param data Where to put the data.
- *  @param size Number of bytes to read.
- */
-void
-Socket::read_definite_and_consume (uint8_t* data, int size, int timeout)
-{
-       int const from_buffer = min (_buffer_data, size);
-       if (from_buffer > 0) {
-               /* Get data from our buffer */
-               memcpy (data, _buffer, from_buffer);
-               consume (from_buffer);
-               /* Update our output state */
-               data += from_buffer;
-               size -= from_buffer;
-       }
-
-       /* read() the rest */
-       while (size > 0) {
-               int const n = read (data, size, timeout);
-               if (n <= 0) {
-                       throw NetworkError ("could not read");
-               }
-
-               data += n;
-               size -= n;
-       }
-}
-
-/** Read as much data as is available, up to some limit.
- *  @param data Where to put the data.
- *  @param size Maximum amount of data to read.
- */
-void
-Socket::read_indefinite (uint8_t* data, int size, int timeout)
-{
-       assert (size < int (sizeof (_buffer)));
-
-       /* Amount of extra data we need to read () */
-       int to_read = size - _buffer_data;
-       while (to_read > 0) {
-               /* read as much of it as we can (into our buffer) */
-               int const n = read (_buffer + _buffer_data, to_read, timeout);
-               if (n <= 0) {
-                       throw NetworkError ("could not read");
-               }
-
-               to_read -= n;
-               _buffer_data += n;
-       }
-
-       assert (_buffer_data >= size);
-
-       /* copy data into the output buffer */
-       assert (size >= _buffer_data);
-       memcpy (data, _buffer, size);
+       uint32_t v;
+       read (reinterpret_cast<uint8_t *> (&v), 4);
+       return ntohl (v);
 }
 
 /** @param other A Rect.
@@ -722,13 +661,13 @@ string
 get_required_string (multimap<string, string> const & kv, string k)
 {
        if (kv.count (k) > 1) {
-               throw StringError ("unexpected multiple keys in key-value set");
+               throw StringError (N_("unexpected multiple keys in key-value set"));
        }
 
        multimap<string, string>::const_iterator i = kv.find (k);
        
        if (i == kv.end ()) {
-               throw StringError (String::compose ("missing key %1 in key-value set", k));
+               throw StringError (String::compose (_("missing key %1 in key-value set"), k));
        }
 
        return i->second;
@@ -752,12 +691,12 @@ string
 get_optional_string (multimap<string, string> const & kv, string k)
 {
        if (kv.count (k) > 1) {
-               throw StringError ("unexpected multiple keys in key-value set");
+               throw StringError (N_("unexpected multiple keys in key-value set"));
        }
 
        multimap<string, string>::const_iterator i = kv.find (k);
        if (i == kv.end ()) {
-               return "";
+               return N_("");
        }
 
        return i->second;
@@ -767,7 +706,7 @@ int
 get_optional_int (multimap<string, string> const & kv, string k)
 {
        if (kv.count (k) > 1) {
-               throw StringError ("unexpected multiple keys in key-value set");
+               throw StringError (N_("unexpected multiple keys in key-value set"));
        }
 
        multimap<string, string>::const_iterator i = kv.find (k);
@@ -932,15 +871,11 @@ video_frames_to_audio_frames (SourceFrame v, float audio_sample_rate, float fram
 bool
 still_image_file (string f)
 {
-#if BOOST_FILESYSTEM_VERSION == 3
        string ext = boost::filesystem::path(f).extension().string();
-#else
-       string ext = boost::filesystem::path(f).extension();
-#endif
 
        transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
        
-       return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png");
+       return (ext == N_(".tif") || ext == N_(".tiff") || ext == N_(".jpg") || ext == N_(".jpeg") || ext == N_(".png") || ext == N_(".bmp"));
 }
 
 /** @return A pair containing CPU model name and the number of processors */
@@ -951,16 +886,16 @@ cpu_info ()
        info.second = 0;
        
 #ifdef DVDOMATIC_POSIX
-       ifstream f ("/proc/cpuinfo");
+       ifstream f (N_("/proc/cpuinfo"));
        while (f.good ()) {
                string l;
                getline (f, l);
-               if (boost::algorithm::starts_with (l, "model name")) {
+               if (boost::algorithm::starts_with (l, N_("model name"))) {
                        string::size_type const c = l.find (':');
                        if (c != string::npos) {
                                info.first = l.substr (c + 2);
                        }
-               } else if (boost::algorithm::starts_with (l, "processor")) {
+               } else if (boost::algorithm::starts_with (l, N_("processor"))) {
                        ++info.second;
                }
        }