Bump version
[libdcp.git] / src / util.cc
index 11052df6be293e1ab9008d1b3b6a9d49928937d1..4ac3685c4cd9ab9c5087ce20ac5c45d6cc85d89c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 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
@@ -27,6 +27,7 @@
 #include <iomanip>
 #include <boost/filesystem.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/date_time/c_local_time_adjustor.hpp>
 #include <openssl/sha.h>
 #include <libxml++/nodes/element.h>
 #include <libxml++/document.h>
@@ -46,6 +47,7 @@
 #include "xyz_frame.h"
 
 using std::string;
+using std::wstring;
 using std::cout;
 using std::stringstream;
 using std::min;
@@ -81,8 +83,9 @@ string
 libdcp::make_digest (string filename, boost::function<void (float)>* progress)
 {
        Kumu::FileReader reader;
-       if (ASDCP_FAILURE (reader.OpenRead (filename.c_str ()))) {
-               boost::throw_exception (FileError ("could not open file to compute digest", filename));
+       Kumu::Result_t r = reader.OpenRead (filename.c_str ());
+       if (ASDCP_FAILURE (r)) {
+               boost::throw_exception (FileError ("could not open file to compute digest", filename, r));
        }
        
        SHA_CTX sha;
@@ -100,7 +103,7 @@ libdcp::make_digest (string filename, boost::function<void (float)>* progress)
                if (r == Kumu::RESULT_ENDOFFILE) {
                        break;
                } else if (ASDCP_FAILURE (r)) {
-                       boost::throw_exception (FileError ("could not read file to compute digest", filename));
+                       boost::throw_exception (FileError ("could not read file to compute digest", filename, r));
                }
                
                SHA1_Update (&sha, read_buffer.Data(), read);
@@ -111,11 +114,11 @@ libdcp::make_digest (string filename, boost::function<void (float)>* progress)
                }
        }
 
-       byte_t byte_buffer[20];
+       byte_t byte_buffer[SHA_DIGEST_LENGTH];
        SHA1_Final (byte_buffer, &sha);
 
        char digest[64];
-       return Kumu::base64encode (byte_buffer, 20, digest, 64);
+       return Kumu::base64encode (byte_buffer, SHA_DIGEST_LENGTH, digest, 64);
 }
 
 /** Convert a content kind to a string which can be used in a
@@ -160,13 +163,13 @@ libdcp::content_kind_to_string (ContentKind kind)
 libdcp::ContentKind
 libdcp::content_kind_from_string (string type)
 {
-       /* XXX: should probably just convert type to lower-case and have done with it */
+       transform (type.begin(), type.end(), type.begin(), ::tolower);
        
        if (type == "feature") {
                return FEATURE;
        } else if (type == "short") {
                return SHORT;
-       } else if (type == "trailer" || type == "Trailer") {
+       } else if (type == "trailer") {
                return TRAILER;
        } else if (type == "test") {
                return TEST;
@@ -174,7 +177,7 @@ libdcp::content_kind_from_string (string type)
                return TRANSITIONAL;
        } else if (type == "rating") {
                return RATING;
-       } else if (type == "teaser" || type == "Teaser") {
+       } else if (type == "teaser") {
                return TEASER;
        } else if (type == "policy") {
                return POLICY;
@@ -212,6 +215,7 @@ libdcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
                boost::throw_exception (DCPReadError ("could not decode JPEG2000 codestream of " + lexical_cast<string> (size) + " bytes."));
        }
 
+       opj_destroy_decompress (decoder);
        opj_cio_close (cio);
 
        image->x1 = rint (float(image->x1) / pow (2, reduce));
@@ -294,36 +298,33 @@ libdcp::base64_decode (string const & in, unsigned char* out, int out_length)
        return N;
 }
 
+/** @param tm Local time.
+ *  @return String of the form 2014-04-02T18:05:23+04:00, where the UTC offset is derived
+ *  from the current system time zone.
+ */
 string
 libdcp::tm_to_string (struct tm* tm)
 {
        char buffer[64];
-       strftime (buffer, 64, "%Y-%m-%dT%I:%M:%S", tm);
+       strftime (buffer, 64, "%Y-%m-%dT%H:%M:%S", tm);
 
-       int offset = 0;
+       /* Compute current UTC offset */
+       boost::posix_time::ptime const utc_now = boost::posix_time::second_clock::universal_time ();
+       boost::posix_time::ptime const now = boost::date_time::c_local_adjustor<boost::posix_time::ptime>::utc_to_local (utc_now);
 
-#ifdef LIBDCP_POSIX
-       offset = tm->tm_gmtoff / 60;
-#else
-       TIME_ZONE_INFORMATION tz;
-       GetTimeZoneInformation (&tz);
-       offset = tz.Bias;
-#endif
-       
-       return string (buffer) + utc_offset_to_string (offset);
+       return string (buffer) + utc_offset_to_string (now - utc_now);
 }
 
-/** @param b Offset from UTC to local time in minutes.
+/** @param b Offset from UTC to local time.
  *  @return string of the form e.g. -01:00.
  */
 string
-libdcp::utc_offset_to_string (int b)
+libdcp::utc_offset_to_string (boost::posix_time::time_duration b)
 {
-       bool const negative = (b < 0);
-       b = negative ? -b : b;
-
-       int const hours = b / 60;
-       int const minutes = b % 60;
+       bool const negative = b.is_negative ();
+       if (negative) {
+               b = boost::posix_time::time_duration (-b.hours(), b.minutes(), 0, 0);
+       }
 
        stringstream o;
        if (negative) {
@@ -332,7 +333,7 @@ libdcp::utc_offset_to_string (int b)
                o << "+";
        }
 
-       o << setw(2) << setfill('0') << hours << ":" << setw(2) << setfill('0') << minutes;
+       o << setw(2) << setfill('0') << b.hours() << ":" << setw(2) << setfill('0') << b.minutes();
        return o.str ();
 }
 
@@ -342,3 +343,20 @@ libdcp::ptime_to_string (boost::posix_time::ptime t)
        struct tm t_tm = boost::posix_time::to_tm (t);
        return tm_to_string (&t_tm);
 }
+
+
+/* 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 *
+libdcp::fopen_boost (boost::filesystem::path p, string t)
+{
+#ifdef LIBDCP_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
+}