A whole load of UTF-8/-16 confusion fixes for Windows.
authorCarl Hetherington <cth@carlh.net>
Tue, 26 Nov 2013 22:23:15 +0000 (22:23 +0000)
committerCarl Hetherington <cth@carlh.net>
Tue, 26 Nov 2013 22:23:15 +0000 (22:23 +0000)
25 files changed:
ChangeLog
cscript
doc/manual/diagrams/file-structure.svg
platform/windows/installer.nsi.32.in
platform/windows/installer.nsi.64.in
src/lib/audio_analysis.cc
src/lib/audio_analysis.h
src/lib/config.cc
src/lib/cross.cc
src/lib/cross.h
src/lib/dcp_video_frame.cc
src/lib/film.cc
src/lib/log.cc
src/lib/still_image_examiner.cc
src/lib/util.cc
src/lib/writer.cc
src/lib/wscript
src/tools/dcpomatic.cc
src/wx/film_editor.cc
src/wx/new_film_dialog.cc
src/wx/new_film_dialog.h
src/wx/wx_util.cc
test/audio_analysis_test.cc [new file with mode: 0644]
test/wscript
wscript

index 6b9a3e43543aab67820bfbe2a0dd62c25bff2fc2..779871d9ba7a449bf901dad5de08209778441916 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2013-11-26  Carl Hetherington  <cth@carlh.net>
+
+       * A whole load of fixes for lots of bugs when handling filenames
+       using non-Latin characters on Windows.
+
 2013-11-22  Carl Hetherington  <cth@carlh.net>
 
        * Version 1.34 released.
diff --git a/cscript b/cscript
index 125a4d34c645bc74c531bdf896f8fbff1bd5f6bb..3830cdc8193974c83bdd1886b1ffe0eb50101ea1 100644 (file)
--- a/cscript
+++ b/cscript
@@ -4,7 +4,7 @@ import os
 
 def dependencies(target):
     return (('ffmpeg-cdist', '0b7ef017aca8b572914518c759db1e234d8fc505'),
-            ('libdcp', 'f38137b21051ce770bbb4d829ae9d6229e97508f'))
+            ('libdcp', 'd0b7892cbab3618fca85a4c95d70d8a1c26a5c4d'))
 
 def build(target):
     cmd = './waf configure --prefix=%s' % target.work_dir_cscript()
index e726369032add1f07a37bf5058431b91f293464c..c19a6f023d4164e229a5957b1c100af79d67ffd4 100644 (file)
@@ -15,7 +15,7 @@
    id="svg2"
    version="1.1"
    inkscape:version="0.48.4 r9939"
-   sodipodi:docname="New document 1">
+   sodipodi:docname="file-structure.svg">
   <defs
      id="defs4">
     <marker
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
-     inkscape:window-width="1280"
-     inkscape:window-height="961"
-     inkscape:window-x="1912"
-     inkscape:window-y="-8"
+     inkscape:window-width="1366"
+     inkscape:window-height="714"
+     inkscape:window-x="0"
+     inkscape:window-y="283"
      inkscape:window-maximized="1" />
   <metadata
      id="metadata7">
         <dc:format>image/svg+xml</dc:format>
         <dc:type
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <dc:title></dc:title>
+        <dc:title />
       </cc:Work>
     </rdf:RDF>
   </metadata>
        sodipodi:nodetypes="cc" />
     <path
        style="color:#000000;fill:none;stroke:#8f5902;stroke-width:1.25;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
-       d="m 181.68106,157.3527 12.5586,0 0,192.56519 -13.39584,0"
+       d="m 201.68106,157.3527 12.5586,0 0,192.56519 -13.39584,0"
        id="path9382"
        inkscape:connector-curvature="0" />
     <text
        xml:space="preserve"
        style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Inconsolata;-inkscape-font-specification:Inconsolata"
-       x="205.96103"
+       x="225.96103"
        y="241.07671"
        id="text9384"
        sodipodi:linespacing="125%"><tspan
          sodipodi:role="line"
          id="tspan9386"
-         x="205.96103"
+         x="225.96103"
          y="241.07671">DCP-o-matic's</tspan><tspan
          sodipodi:role="line"
-         x="205.96103"
-         y="256.07669"
+         x="225.96103"
+         y="256.07672"
          id="tspan9388">working</tspan><tspan
          sodipodi:role="line"
-         x="205.96103"
-         y="271.07669"
+         x="225.96103"
+         y="271.07672"
          id="tspan9390">files</tspan></text>
     <path
        style="color:#000000;fill:none;stroke:#8f5902;stroke-width:1.25;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
-       d="m 444.5744,360.802 12.5586,0 0,272.94023 -13.39584,0"
+       d="m 486.5744,360.802 12.5586,0 0,272.94023 -13.39584,0"
        id="path9382-3"
        inkscape:connector-curvature="0" />
     <text
        xml:space="preserve"
        style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Inconsolata;-inkscape-font-specification:Inconsolata"
-       x="468.01709"
+       x="510.01709"
        y="500.62109"
        id="text9410"
        sodipodi:linespacing="125%"><tspan
          sodipodi:role="line"
          id="tspan9412"
-         x="468.01709"
+         x="510.01709"
          y="500.62109">DCP</tspan></text>
   </g>
 </svg>
index 9b719f825b045957728e03ba92dcfa4fc1e4c0ba..629edd50cc3842c16d03f936f98b4dfa4be82543 100644 (file)
@@ -33,6 +33,7 @@ File "%static_deps%/bin/libboost_filesystem-mt.dll"
 File "%static_deps%/bin/libboost_system-mt.dll"
 File "%static_deps%/bin/libboost_thread_win32-mt.dll"
 File "%static_deps%/bin/libboost_date_time-mt.dll"
+File "%static_deps%/bin/libboost_locale-mt.dll"
 File "%static_deps%/bin/libeay32.dll"
 File "%static_deps%/bin/libgcc_s_sjlj-1.dll"
 File "%static_deps%/bin/libgio-2.0-0.dll"
@@ -40,7 +41,7 @@ File "%static_deps%/bin/libglib-2.0-0.dll"
 File "%static_deps%/bin/libgobject-2.0-0.dll"
 File "%static_deps%/bin/libiconv-2.dll"
 File "%static_deps%/bin/libjpeg-8.dll"
-File "%static_deps%/bin/libMagick++-6.Q16-2.dll"
+File "%static_deps%/bin/libMagick++-6.Q16-3.dll"
 File "%static_deps%/bin/libMagickCore-6.Q16-1.dll"
 File "%static_deps%/bin/libMagickWand-6.Q16-1.dll"
 File "%static_deps%/bin/libpng15-15.dll"
index c53c2caccf975c7a0b52d21327f8794f23724404..de1e091076158f9cd4df7894a617257df94a21d7 100644 (file)
@@ -43,6 +43,7 @@ File "%static_deps%/bin/libboost_filesystem-mt.dll"
 File "%static_deps%/bin/libboost_system-mt.dll"
 File "%static_deps%/bin/libboost_thread_win32-mt.dll"
 File "%static_deps%/bin/libboost_date_time-mt.dll"
+File "%static_deps%/bin/libboost_locale-mt.dll"
 File "%static_deps%/bin/libeay32.dll"
 File "%static_deps%/bin/libgcc_s_sjlj-1.dll"
 File "%static_deps%/bin/libgio-2.0-0.dll"
@@ -50,7 +51,7 @@ File "%static_deps%/bin/libglib-2.0-0.dll"
 File "%static_deps%/bin/libgobject-2.0-0.dll"
 File "%static_deps%/bin/libiconv-2.dll"
 File "%static_deps%/bin/libjpeg-8.dll"
-File "%static_deps%/bin/libMagick++-6.Q16-2.dll"
+File "%static_deps%/bin/libMagick++-6.Q16-3.dll"
 File "%static_deps%/bin/libMagickCore-6.Q16-1.dll"
 File "%static_deps%/bin/libMagickWand-6.Q16-1.dll"
 File "%static_deps%/bin/libpng15-15.dll"
index bc59bcccaa56539a6f8a4a1728c2d9e50e9e1a50..1488f89fcfdfb6f2ac32aaed158e36e1a9eb589d 100644 (file)
 #include <stdint.h>
 #include <cmath>
 #include <cassert>
-#include <fstream>
+#include <cstdio>
 #include <boost/filesystem.hpp>
 #include "audio_analysis.h"
+#include "cross.h"
 
 using std::ostream;
 using std::istream;
 using std::string;
-using std::ofstream;
-using std::ifstream;
 using std::vector;
 using std::cout;
 using std::max;
@@ -41,10 +40,10 @@ AudioPoint::AudioPoint ()
        }
 }
 
-AudioPoint::AudioPoint (istream& s)
+AudioPoint::AudioPoint (FILE* f)
 {
        for (int i = 0; i < COUNT; ++i) {
-               s >> _data[i];
+               fscanf (f, "%f", &_data[i]);
        }
 }
 
@@ -70,10 +69,10 @@ AudioPoint::operator= (AudioPoint const & other)
 }
 
 void
-AudioPoint::write (ostream& s) const
+AudioPoint::write (FILE* f) const
 {
        for (int i = 0; i < COUNT; ++i) {
-               s << _data[i] << "\n";
+               fprintf (f, "%f\n", _data[i]);
        }
 }
        
@@ -85,15 +84,15 @@ AudioAnalysis::AudioAnalysis (int channels)
 
 AudioAnalysis::AudioAnalysis (boost::filesystem::path filename)
 {
-       ifstream f (filename.string().c_str ());
+       FILE* f = fopen_boost (filename, "r");
 
        int channels;
-       f >> channels;
+       fscanf (f, "%d", &channels);
        _data.resize (channels);
 
        for (int i = 0; i < channels; ++i) {
                int points;
-               f >> points;
+               fscanf (f, "%d", &points);
                for (int j = 0; j < points; ++j) {
                        _data[i].push_back (AudioPoint (f));
                }
@@ -130,17 +129,19 @@ AudioAnalysis::points (int c) const
 void
 AudioAnalysis::write (boost::filesystem::path filename)
 {
-       string tmp = filename.string() + ".tmp";
+       boost::filesystem::path tmp = filename;
+       tmp.replace_extension (".tmp");
 
-       ofstream f (tmp.c_str ());
-       f << _data.size() << "\n";
+       FILE* f = fopen_boost (tmp, "w");
+
+       fprintf (f, "%ld\n", _data.size ());
        for (vector<vector<AudioPoint> >::iterator i = _data.begin(); i != _data.end(); ++i) {
-               f << i->size () << "\n";
+               fprintf (f, "%ld\n", i->size ());
                for (vector<AudioPoint>::iterator j = i->begin(); j != i->end(); ++j) {
                        j->write (f);
                }
        }
 
-       f.close ();
+       fclose (f);
        boost::filesystem::rename (tmp, filename);
 }
index cfc170c846ae2af87e12645e3dd84e4ba7e9c13a..824472dda08c80daf1037a0f5635b5db7eefa556 100644 (file)
@@ -20,7 +20,6 @@
 #ifndef DCPOMATIC_AUDIO_ANALYSIS_H
 #define DCPOMATIC_AUDIO_ANALYSIS_H
 
-#include <iostream>
 #include <vector>
 #include <list>
 #include <boost/filesystem.hpp>
@@ -35,11 +34,11 @@ public:
        };
 
        AudioPoint ();
-       AudioPoint (std::istream &);
+       AudioPoint (FILE *);
        AudioPoint (AudioPoint const &);
        AudioPoint& operator= (AudioPoint const &);
 
-       void write (std::ostream &) const;
+       void write (FILE *) const;
        
        float& operator[] (int t) {
                return _data[t];
index 4b6455f51412ed378633f487217918676cbe156c..54b9168f2542a1bbd8ee49d0b933f4c95007ada2 100644 (file)
@@ -41,7 +41,6 @@
 using std::vector;
 using std::ifstream;
 using std::string;
-using std::ofstream;
 using std::list;
 using std::max;
 using std::exception;
@@ -182,6 +181,7 @@ Config::read ()
 void
 Config::read_old_metadata ()
 {
+       /* XXX: this won't work with non-Latin filenames */
        ifstream f (file(true).string().c_str ());
        string line;
 
index 41051ee2edf3f9fcacc8d0e59e11d1ba8cd0a745..7436dbf26a9b4582edcfb8e1702638b2e91d3416 100644 (file)
@@ -70,6 +70,9 @@ cpu_info ()
        string info;
        
 #ifdef DCPOMATIC_LINUX
+       /* This use of ifstream is ok; the filename can never
+          be non-Latin
+       */
        ifstream f ("/proc/cpuinfo");
        while (f.good ()) {
                string l;
@@ -269,3 +272,19 @@ openssl_path ()
 #endif
 
 }
+
+/* Apparently there is no way to create an ofstream using a UTF-8
+   filename under Windows.  We are hence reduced to using fopen
+   with this wrapper.
+*/
+FILE *
+fopen_boost (boost::filesystem::path p, string t)
+{
+#ifdef DCPOMATIC_WINDOWS
+        wstring w (t.begin(), t.end());
+       /* c_str() here should give a UTF-16 string */
+        return _wfopen (p.c_str(), w.c_str ());
+#else
+        return fopen (p.c_str(), t.c_str ());
+#endif
+}
index 1fe34edbe0760d9e86f00c47a6689c61acf073a0..931e7d8900792612f5781fc44b0b44f494c6cf09 100644 (file)
@@ -33,3 +33,4 @@ extern boost::filesystem::path openssl_path ();
 #ifdef DCPOMATIC_OSX
 extern boost::filesystem::path app_contents ();
 #endif
+extern FILE * fopen_boost (boost::filesystem::path, std::string);
index 25abd6f0df57ee7f9f0304e9713b919052639c00..679a0490e8850955a782e76a0ccd387c96254ba4 100644 (file)
 #include "scaler.h"
 #include "image.h"
 #include "log.h"
+#include "cross.h"
 
 #include "i18n.h"
 
 using std::string;
 using std::stringstream;
-using std::ofstream;
 using std::cout;
 using boost::shared_ptr;
 using boost::lexical_cast;
@@ -379,8 +379,9 @@ void
 EncodedData::write_info (shared_ptr<const Film> film, int frame, Eyes eyes, libdcp::FrameInfo fin) const
 {
        boost::filesystem::path const info = film->info_path (frame, eyes);
-       ofstream h (info.string().c_str());
+       FILE* h = fopen_boost (info, "w");
        fin.write (h);
+       fclose (h);
 }
 
 /** Send this data to a socket.
index eab91c7d2b26dc343f8fe7c733cf6a1186ce4fec..b1b86898403fdbb62c39b6fe1bc9e42eed0bd9c7 100644 (file)
@@ -64,8 +64,6 @@ using std::multimap;
 using std::pair;
 using std::map;
 using std::vector;
-using std::ifstream;
-using std::ofstream;
 using std::setfill;
 using std::min;
 using std::make_pair;
index 86de21bddf8f586ab00c21005ace6c079ac4f977..9ddf460d43ccc1c382270e607a7634a66be09049 100644 (file)
  *  @brief A very simple logging class.
  */
 
-#include <fstream>
 #include <time.h>
+#include <cstdio>
 #include "log.h"
+#include "cross.h"
 
 #include "i18n.h"
 
@@ -102,7 +103,8 @@ FileLog::FileLog (boost::filesystem::path file)
 void
 FileLog::do_log (string m)
 {
-       ofstream f (_file.string().c_str(), fstream::app);
-       f << m << N_("\n");
+       FILE* f = fopen_boost (_file, "a");
+       fprintf (f, "%s\n", m.c_str ());
+       fclose (f);
 }
 
index 5f45d63650bb33bbf6eb5d6883edbec2082611ff..d5e863634999c9cd955e7fc08734f95b54899ee2 100644 (file)
@@ -26,6 +26,7 @@
 #include "i18n.h"
 
 using std::cout;
+using std::string;
 using boost::shared_ptr;
 
 StillImageExaminer::StillImageExaminer (shared_ptr<const Film> f, shared_ptr<const StillImageContent> c)
@@ -33,7 +34,7 @@ StillImageExaminer::StillImageExaminer (shared_ptr<const Film> f, shared_ptr<con
        , _film (f)
 {
        using namespace MagickCore;
-       Magick::Image* image = new Magick::Image (_still_image_content->path().string());
+       Magick::Image* image = new Magick::Image (_still_image_content->path().string ());
        _video_size = libdcp::Size (image->columns(), image->rows());
        delete image;
 }
index 484c4fb9ba012edb895b0c466f484af2028bd2d8..e7044027155715f2910dd4762d7e94b9b99d5081 100644 (file)
@@ -39,6 +39,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/thread.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/locale.hpp>
 #include <glib.h>
 #include <openjpeg.h>
 #include <openssl/md5.h>
@@ -80,7 +81,6 @@ using std::endl;
 using std::vector;
 using std::hex;
 using std::setw;
-using std::ifstream;
 using std::ios;
 using std::min;
 using std::max;
@@ -89,7 +89,6 @@ using std::multimap;
 using std::istream;
 using std::numeric_limits;
 using std::pair;
-using std::ofstream;
 using std::cout;
 using boost::shared_ptr;
 using boost::thread;
@@ -260,8 +259,11 @@ seconds (struct timeval t)
 LONG WINAPI exception_handler(struct _EXCEPTION_POINTERS *)
 {
        dbg::stack s;
-       ofstream f (backtrace_file.string().c_str());
-       std::copy(s.begin(), s.end(), std::ostream_iterator<dbg::stack_frame>(f, "\n"));
+       FILE* f = fopen_boost (backtrace_file, "w");
+       for (dbg::stack::const_iterator i = s.begin(); i != s.end(); ++i) {
+               fprintf (f, "%p %s %d %s", i->instruction, i->function.c_str(), i->line, i->module.c_str());
+       }
+       fclose (f);
        return EXCEPTION_CONTINUE_SEARCH;
 }
 #endif
@@ -276,6 +278,21 @@ dcpomatic_setup ()
        backtrace_file /= g_get_user_config_dir ();
        backtrace_file /= "backtrace.txt";
        SetUnhandledExceptionFilter(exception_handler);
+
+       /* Dark voodoo which, I think, gets boost::filesystem::path to
+          correctly convert UTF-8 strings to paths, and also paths
+          back to UTF-8 strings (on path::string()).
+
+          After this, constructing boost::filesystem::paths from strings
+          converts from UTF-8 to UTF-16 inside the path.  Then
+          path::string().c_str() gives UTF-8 and
+          path::c_str()          gives UTF-16.
+
+          This is all Windows-only.  AFAICT Linux/OS X use UTF-8 everywhere,
+          so things are much simpler.
+       */
+       std::locale::global (boost::locale::generator().generate (""));
+       boost::filesystem::path::imbue (std::locale ());
 #endif 
        
        avfilter_register_all ();
@@ -392,29 +409,28 @@ md5_digest (void const * data, int size)
 string
 md5_digest (boost::filesystem::path file)
 {
-       ifstream f (file.string().c_str(), std::ios::binary);
-       if (!f.good ()) {
+       FILE* f = fopen_boost (file, "rb");
+       if (!f) {
                throw OpenFileError (file.string());
        }
-       
-       f.seekg (0, std::ios::end);
-       int bytes = f.tellg ();
-       f.seekg (0, std::ios::beg);
 
-       int const buffer_size = 64 * 1024;
+       boost::uintmax_t bytes = boost::filesystem::file_size (file);
+
+       boost::uintmax_t const buffer_size = 64 * 1024;
        char buffer[buffer_size];
 
        MD5_CTX md5_context;
        MD5_Init (&md5_context);
        while (bytes > 0) {
                int const t = min (bytes, buffer_size);
-               f.read (buffer, t);
+               fread (buffer, 1, t, f);
                MD5_Update (&md5_context, buffer, t);
                bytes -= t;
        }
 
        unsigned char digest[MD5_DIGEST_LENGTH];
        MD5_Final (digest, &md5_context);
+       fclose (f);
 
        stringstream s;
        for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
@@ -428,7 +444,7 @@ md5_digest (boost::filesystem::path file)
 string
 md5_digest_directory (boost::filesystem::path directory, shared_ptr<Job> job)
 {
-       int const buffer_size = 64 * 1024;
+       boost::uintmax_t const buffer_size = 64 * 1024;
        char buffer[buffer_size];
 
        MD5_CTX md5_context;
@@ -443,18 +459,16 @@ md5_digest_directory (boost::filesystem::path directory, shared_ptr<Job> job)
 
        int j = 0;
        for (boost::filesystem::directory_iterator i(directory); i != boost::filesystem::directory_iterator(); ++i) {
-               ifstream f (i->path().string().c_str(), std::ios::binary);
-               if (!f.good ()) {
+               FILE* f = fopen_boost (i->path(), "rb");
+               if (!f) {
                        throw OpenFileError (i->path().string());
                }
-       
-               f.seekg (0, std::ios::end);
-               int bytes = f.tellg ();
-               f.seekg (0, std::ios::beg);
+
+               boost::uintmax_t bytes = boost::filesystem::file_size (i->path ());
 
                while (bytes > 0) {
                        int const t = min (bytes, buffer_size);
-                       f.read (buffer, t);
+                       fread (buffer, 1, t, f);
                        MD5_Update (&md5_context, buffer, t);
                        bytes -= t;
                }
@@ -463,6 +477,8 @@ md5_digest_directory (boost::filesystem::path directory, shared_ptr<Job> job)
                        job->set_progress (float (j) / files);
                        ++j;
                }
+
+               fclose (f);
        }
 
        unsigned char digest[MD5_DIGEST_LENGTH];
index 103ac2ba135b118f63d839ad80354ff44c4b688f..f4128e6c573d6b65e81480b699fdb8626e595ee0 100644 (file)
 #include "audio_mapping.h"
 #include "config.h"
 #include "job.h"
+#include "cross.h"
 
 #include "i18n.h"
 
 using std::make_pair;
 using std::pair;
 using std::string;
-using std::ifstream;
 using std::list;
 using std::cout;
 using boost::shared_ptr;
@@ -141,8 +141,9 @@ Writer::fake_write (int frame, Eyes eyes)
 {
        boost::mutex::scoped_lock lock (_mutex);
 
-       ifstream ifi (_film->info_path (frame, eyes).string().c_str());
+       FILE* ifi = fopen_boost (_film->info_path (frame, eyes), "r");
        libdcp::FrameInfo info (ifi);
+       fclose (ifi);
        
        QueueItem qi;
        qi.type = QueueItem::FAKE;
@@ -430,8 +431,9 @@ bool
 Writer::check_existing_picture_mxf_frame (FILE* mxf, int f, Eyes eyes)
 {
        /* Read the frame info as written */
-       ifstream ifi (_film->info_path (f, eyes).string().c_str());
+       FILE* ifi = fopen_boost (_film->info_path (f, eyes), "r");
        libdcp::FrameInfo info (ifi);
+       fclose (ifi);
        if (info.size == 0) {
                _film->log()->log (String::compose ("Existing frame %1 has no info file", f));
                return false;
index 852bb1aed57e60240b3b15adf0a578c5609b1f8b..e317026f3e7aadf8157195dc5243895dde614fe1 100644 (file)
@@ -74,7 +74,7 @@ def build(bld):
     obj.export_includes = ['..']
     obj.uselib = """
                  AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE 
-                 BOOST_FILESYSTEM BOOST_THREAD BOOST_DATETIME BOOST_SIGNALS2 
+                 BOOST_FILESYSTEM BOOST_THREAD BOOST_DATETIME BOOST_SIGNALS2 BOOST_LOCALE
                  SNDFILE OPENJPEG POSTPROC TIFF MAGICK SSH DCP CXML GLIB LZMA XML++
                  CURL ZIP QUICKMAIL
                  """
index 1d01e4da8bf8b3fcead99504b9f7e8f2e311fedc..2a0cb9cd36935a1ae53d67fafd60e8d92578b7c6 100644 (file)
@@ -62,7 +62,6 @@ using std::map;
 using std::make_pair;
 using std::list;
 using std::exception;
-using std::ofstream;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 
@@ -247,6 +246,22 @@ public:
                : wxFrame (NULL, -1, title)
                , _servers_list_dialog (0)
        {
+#ifdef DCPOMATIC_WINDOWS_CONSOLE               
+                AllocConsole();
+               
+               HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
+               int hCrt = _open_osfhandle((intptr_t) handle_out, _O_TEXT);
+               FILE* hf_out = _fdopen(hCrt, "w");
+               setvbuf(hf_out, NULL, _IONBF, 1);
+               *stdout = *hf_out;
+               
+               HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
+               hCrt = _open_osfhandle((intptr_t) handle_in, _O_TEXT);
+               FILE* hf_in = _fdopen(hCrt, "r");
+               setvbuf(hf_in, NULL, _IONBF, 128);
+               *stdin = *hf_in;
+#endif
+
                wxMenuBar* bar = new wxMenuBar;
                setup_menu (bar);
                SetMenuBar (bar);
@@ -332,7 +347,7 @@ private:
                                            std_to_wx (
                                                    String::compose (wx_to_std (_("The directory %1 already exists and is not empty.  "
                                                                                  "Are you sure you want to use it?")),
-                                                                    d->get_path().c_str())
+                                                                    d->get_path().string().c_str())
                                                    )
                                            )) {
                                        return;
index 9cf840614535a7847d774977d3cdb2d396039788..ef35349390573e356ed463ed64581d64f4be22a8 100644 (file)
@@ -731,11 +731,14 @@ FilmEditor::setup_content ()
 void
 FilmEditor::content_add_file_clicked ()
 {
-       wxFileDialog* d = new wxFileDialog (this, _("Choose a file or files"), wxT (""), wxT (""), wxT ("*.*"), wxFD_MULTIPLE);
+       /* The wxFD_CHANGE_DIR here prevents a `could not set working directory' error 123 on Windows when using
+          non-Latin filenames or paths.
+       */
+       wxFileDialog* d = new wxFileDialog (this, _("Choose a file or files"), wxT (""), wxT (""), wxT ("*.*"), wxFD_MULTIPLE | wxFD_CHANGE_DIR);
        int const r = d->ShowModal ();
-       d->Destroy ();
 
        if (r != wxID_OK) {
+               d->Destroy ();
                return;
        }
 
@@ -745,8 +748,10 @@ FilmEditor::content_add_file_clicked ()
        /* XXX: check for lots of files here and do something */
 
        for (unsigned int i = 0; i < paths.GetCount(); ++i) {
-               _film->examine_and_add_content (content_factory (_film, wx_to_std (paths[i])));
+               _film->examine_and_add_content (content_factory (_film, wx_to_std (d->GetPath ())));
        }
+
+       d->Destroy ();
 }
 
 void
index 2612a6afe9afabc987847dcbc0a1547ca6c43850..be5af999e86ca42861f1b9fd73e8563962037dab 100644 (file)
@@ -74,11 +74,11 @@ NewFilmDialog::~NewFilmDialog ()
        _directory = wx_to_std (_folder->GetPath ());
 }
 
-string
+boost::filesystem::path
 NewFilmDialog::get_path () const
 {
        filesystem::path p;
        p /= wx_to_std (_folder->GetPath ());
        p /= wx_to_std (_name->GetValue ());
-       return p.string ();
+       return p;
 }
index 4176b060df1dc9081c4afa80c39f11bbff35da35..a835c7cebae4ebbfe251eb85d29af30c5120bffe 100644 (file)
@@ -29,7 +29,7 @@ public:
        NewFilmDialog (wxWindow *);
        ~NewFilmDialog ();
 
-       std::string get_path () const;
+       boost::filesystem::path get_path () const;
 
 private:
        wxTextCtrl* _name;
index 27a4554ca61d5534994cbd6f794c1f289a44060c..103d36d006d1539043f8c357fae1ebdf98ceb0f7 100644 (file)
@@ -105,7 +105,7 @@ confirm_dialog (wxWindow* parent, wxString m)
 string
 wx_to_std (wxString s)
 {
-       return string (s.mb_str ());
+       return string (s.ToUTF8 ());
 }
 
 /** @param s STL string.
diff --git a/test/audio_analysis_test.cc b/test/audio_analysis_test.cc
new file mode 100644 (file)
index 0000000..77b2aea
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/test/unit_test.hpp>
+#include "lib/audio_analysis.h"
+
+static float
+random_float ()
+{
+       return (float (rand ()) / RAND_MAX) * 2 - 1;
+}
+
+/* Check serialisation of audio analyses */
+BOOST_AUTO_TEST_CASE (audio_analysis_test)
+{
+       int const channels = 3;
+       int const points = 4096;
+       
+       srand (1);
+       
+       AudioAnalysis a (3);
+       for (int i = 0; i < channels; ++i) {
+               for (int j = 0; j < points; ++j) {
+                       AudioPoint p;
+                       p[AudioPoint::PEAK] = random_float ();
+                       p[AudioPoint::RMS] = random_float ();
+                       a.add_point (i, p);
+               }
+       }
+
+       a.write ("build/test/audio_analysis_test");
+
+       srand (1);
+
+       AudioAnalysis b ("build/test/audio_analysis_test");
+       for (int i = 0; i < channels; ++i) {
+               BOOST_CHECK (b.points(i) == points);
+               for (int j = 0; j < points; ++j) {
+                       AudioPoint p = b.get_point (i, j);
+                       BOOST_CHECK_CLOSE (p[AudioPoint::PEAK], random_float (), 1);
+                       BOOST_CHECK_CLOSE (p[AudioPoint::RMS],  random_float (), 1);
+               }
+       }
+}
index b40b6947521e913637f828428cc057148a4a8d17..76de63a523098f613d80770bfe0e67efd69e4285 100644 (file)
@@ -16,6 +16,7 @@ def build(bld):
     obj.use    = 'libdcpomatic'
     obj.source = """
                  test.cc
+                 audio_analysis_test.cc
                  scaling_test.cc
                  film_metadata_test.cc
                  frame_rate_test.cc
diff --git a/wscript b/wscript
index 9d2450d341c9bf196f6542d04aa1fee731013df3..138f947e4c5b16e0927b67d31b5585ca4065519c 100644 (file)
--- a/wscript
+++ b/wscript
@@ -185,6 +185,14 @@ def configure(conf):
                             lib=['boost_date_time%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
                             uselib_store='BOOST_DATETIME')
 
+    conf.check_cxx(fragment="""
+                           #include <boost/locale.hpp>\n
+                           int main() { std::locale::global (boost::locale::generator().generate ("")); }\n
+                           """, msg='Checking for boost locale library',
+                            libpath='/usr/local/lib',
+                            lib=['boost_locale%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
+                            uselib_store='BOOST_LOCALE')
+
     conf.check_cxx(fragment="""
                            #include <boost/signals2.hpp>\n
                            int main() { boost::signals2::signal<void (int)> x; }\n