summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2022-04-12 22:34:04 +0200
committerCarl Hetherington <cth@carlh.net>2022-04-20 20:04:21 +0200
commit05bfa3d1fe9e274ed195647c6f74cb272f00c23d (patch)
tree1372760463b288ff4e10ef7fb6e7414e202829f5 /src
parent0338e7a7c19617f9ebb64ee02fbf3cceab8cf03f (diff)
Add and use new File class.master
It was always a bit troubling that fopen_boost wasn't exception safe, and this also fixes a leak where load_ratings_list would never close the ratings file.
Diffstat (limited to 'src')
-rw-r--r--src/array_data.cc11
-rw-r--r--src/data.cc8
-rw-r--r--src/encrypted_kdm.cc13
-rw-r--r--src/file.cc106
-rw-r--r--src/file.h78
-rw-r--r--src/interop_subtitle_asset.cc6
-rw-r--r--src/language_tag.cc14
-rw-r--r--src/mono_picture_frame.cc8
-rw-r--r--src/rating.cc11
-rw-r--r--src/util.cc19
-rw-r--r--src/util.h10
-rw-r--r--src/wscript2
12 files changed, 221 insertions, 65 deletions
diff --git a/src/array_data.cc b/src/array_data.cc
index 2df53830..1234ba22 100644
--- a/src/array_data.cc
+++ b/src/array_data.cc
@@ -38,10 +38,11 @@
#include "array_data.h"
-#include "util.h"
+#include "file.h"
#include "exceptions.h"
-#include <cstdio>
+#include "util.h"
#include <cerrno>
+#include <cstdio>
using boost::shared_array;
@@ -83,14 +84,12 @@ ArrayData::ArrayData (boost::filesystem::path file)
_size = boost::filesystem::file_size (file);
_data.reset (new uint8_t[_size]);
- auto f = fopen_boost (file, "rb");
+ File f(file, "rb");
if (!f) {
throw FileError ("could not open file for reading", file, errno);
}
- auto const r = fread (_data.get(), 1, _size, f);
- fclose (f);
- if (r != static_cast<size_t>(_size)) {
+ if (f.read(_data.get(), 1, _size) != static_cast<size_t>(_size)) {
throw FileError ("could not read from file", file, errno);
}
}
diff --git a/src/data.cc b/src/data.cc
index 79f58f93..a26d4d1b 100644
--- a/src/data.cc
+++ b/src/data.cc
@@ -38,8 +38,8 @@
#include "data.h"
+#include "file.h"
#include "exceptions.h"
-#include "util.h"
#include <cstdio>
#include <cerrno>
@@ -50,13 +50,11 @@ using namespace dcp;
void
Data::write (boost::filesystem::path file) const
{
- auto f = fopen_boost (file, "wb");
+ File f(file, "wb");
if (!f) {
throw FileError ("could not write to file", file, errno);
}
- size_t const r = fwrite (data(), 1, size(), f);
- fclose (f);
- if (r != size_t(size())) {
+ if (f.write(data(), 1, size()) != size_t(size())) {
throw FileError ("could not write to file", file, errno);
}
}
diff --git a/src/encrypted_kdm.cc b/src/encrypted_kdm.cc
index 986f82e4..5e5f9fe4 100644
--- a/src/encrypted_kdm.cc
+++ b/src/encrypted_kdm.cc
@@ -37,11 +37,12 @@
*/
-#include "encrypted_kdm.h"
-#include "util.h"
#include "certificate_chain.h"
-#include "exceptions.h"
#include "compose.hpp"
+#include "encrypted_kdm.h"
+#include "exceptions.h"
+#include "file.h"
+#include "util.h"
#include <libcxml/cxml.h>
#include <libxml++/document.h>
#include <libxml++/nodes/element.h>
@@ -730,14 +731,12 @@ EncryptedKDM::~EncryptedKDM ()
void
EncryptedKDM::as_xml (boost::filesystem::path path) const
{
- auto f = fopen_boost (path, "w");
+ File f(path, "w");
if (!f) {
throw FileError ("Could not open KDM file for writing", path, errno);
}
auto const x = as_xml ();
- size_t const written = fwrite (x.c_str(), 1, x.length(), f);
- fclose (f);
- if (written != x.length()) {
+ if (f.write(x.c_str(), 1, x.length()) != x.length()) {
throw FileError ("Could not write to KDM file", path, errno);
}
}
diff --git a/src/file.cc b/src/file.cc
new file mode 100644
index 00000000..fceb905b
--- /dev/null
+++ b/src/file.cc
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "dcp_assert.h"
+#include "file.h"
+
+
+using namespace dcp;
+
+
+File::~File()
+{
+ close();
+}
+
+
+File::File(boost::filesystem::path path, std::string mode)
+{
+#ifdef LIBDCP_WINDOWS
+ std::wstring mode_wide(mode.begin(), mode.end());
+ /* c_str() here should give a UTF-16 string */
+ _file = _wfopen(path.c_str(), mode_wide.c_str());
+#else
+ _file = fopen(path.c_str(), mode.c_str());
+#endif
+}
+
+
+void
+File::close()
+{
+ if (_file) {
+ fclose(_file);
+ _file = nullptr;
+ }
+}
+
+
+size_t
+File::write(const void *ptr, size_t size, size_t nmemb)
+{
+ DCP_ASSERT(_file);
+ return fwrite(ptr, size, nmemb, _file);
+}
+
+
+size_t
+File::read(void *ptr, size_t size, size_t nmemb)
+{
+ DCP_ASSERT(_file);
+ return fread(ptr, size, nmemb, _file);
+}
+
+
+int
+File::eof()
+{
+ DCP_ASSERT(_file);
+ return feof(_file);
+}
+
+
+char *
+File::gets(char *s, int size)
+{
+ DCP_ASSERT(_file);
+ return fgets(s, size, _file);
+}
+
+
+File::operator bool() const
+{
+ return _file != nullptr;
+}
+
diff --git a/src/file.h b/src/file.h
new file mode 100644
index 00000000..e50c6005
--- /dev/null
+++ b/src/file.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp 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.
+
+ libdcp 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 libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include <boost/filesystem/path.hpp>
+
+
+namespace dcp {
+
+
+/** A wrapper for stdio files that gives RAII and allows us to open files with
+ * UTF-8 names on Windows.
+ */
+class File
+{
+public:
+ /** @param path Path to open
+ * @param mode mode flags, as for fopen(3)
+ */
+ File(boost::filesystem::path, std::string mode);
+ ~File();
+
+ File(File const&) = delete;
+ File& operator=(File const&) = delete;
+
+ operator bool() const;
+
+ /** fwrite() wrapper */
+ size_t write(const void *ptr, size_t size, size_t nmemb);
+ /** fread() wrapper */
+ size_t read(void *ptr, size_t size, size_t nmemb);
+ /** feof() wrapper */
+ int eof();
+ /** fgets() wrapper */
+ char *gets(char *s, int size);
+
+ /** Close the file; it is not necessary to call this as the
+ * destructor will do it if required.
+ */
+ void close();
+
+private:
+ FILE* _file = nullptr;
+};
+
+
+}
+
diff --git a/src/interop_subtitle_asset.cc b/src/interop_subtitle_asset.cc
index bb0cad70..798f1cda 100644
--- a/src/interop_subtitle_asset.cc
+++ b/src/interop_subtitle_asset.cc
@@ -40,6 +40,7 @@
#include "compose.hpp"
#include "dcp_assert.h"
#include "font_asset.h"
+#include "file.h"
#include "interop_load_font_node.h"
#include "interop_subtitle_asset.h"
#include "raw_convert.h"
@@ -191,15 +192,14 @@ InteropSubtitleAsset::load_font_nodes () const
void
InteropSubtitleAsset::write (boost::filesystem::path p) const
{
- auto f = fopen_boost (p, "w");
+ File f(p, "w");
if (!f) {
throw FileError ("Could not open file for writing", p, -1);
}
_raw_xml = xml_as_string ();
/* length() here gives bytes not characters */
- fwrite (_raw_xml->c_str(), 1, _raw_xml->length(), f);
- fclose (f);
+ f.write(_raw_xml->c_str(), 1, _raw_xml->length());
_file = p;
diff --git a/src/language_tag.cc b/src/language_tag.cc
index 8520a571..532dd557 100644
--- a/src/language_tag.cc
+++ b/src/language_tag.cc
@@ -40,6 +40,7 @@
#include "compose.hpp"
#include "dcp_assert.h"
#include "exceptions.h"
+#include "file.h"
#include "language_tag.h"
#include <boost/algorithm/string.hpp>
#include <string>
@@ -50,8 +51,8 @@ using std::ostream;
using std::pair;
using std::string;
using std::vector;
-using boost::optional;
using boost::algorithm::trim;
+using boost::optional;
using namespace dcp;
@@ -452,23 +453,22 @@ LanguageTag::get_subtag_description (LanguageTag::SubtagType type, string subtag
void
load_language_tag_list (boost::filesystem::path tags_directory, string name, std::function<void (std::string, std::string)> add)
{
- auto f = fopen_boost (tags_directory / name, "r");
+ File f(tags_directory / name, "r");
if (!f) {
throw FileError ("Could not open tags file", tags_directory / name, errno);
}
char buffer[512];
int i = 0;
- while (!feof(f)) {
- char* r = fgets (buffer, sizeof(buffer), f);
+ while (!f.eof()) {
+ char* r = f.gets(buffer, sizeof(buffer));
if (r == 0) {
break;
}
string a = buffer;
trim (a);
- r = fgets (buffer, sizeof(buffer), f);
+ r = f.gets(buffer, sizeof(buffer));
if (r == 0) {
- fclose (f);
throw FileError ("Bad tags file", tags_directory / name, -1);
}
string b = buffer;
@@ -476,8 +476,6 @@ load_language_tag_list (boost::filesystem::path tags_directory, string name, std
add (a, b);
++i;
}
-
- fclose (f);
}
diff --git a/src/mono_picture_frame.cc b/src/mono_picture_frame.cc
index df75126c..ddaed983 100644
--- a/src/mono_picture_frame.cc
+++ b/src/mono_picture_frame.cc
@@ -41,6 +41,7 @@
#include "compose.hpp"
#include "crypto_context.h"
#include "exceptions.h"
+#include "file.h"
#include "j2k_transcode.h"
#include "mono_picture_frame.h"
#include "rgb_xyz.h"
@@ -60,15 +61,12 @@ MonoPictureFrame::MonoPictureFrame (boost::filesystem::path path)
{
auto const size = boost::filesystem::file_size (path);
_buffer.reset(new ASDCP::JP2K::FrameBuffer(size));
- auto f = fopen_boost (path, "rb");
+ File f(path, "rb");
if (!f) {
boost::throw_exception (FileError("could not open JPEG2000 file", path, errno));
}
- size_t n = fread (data(), 1, size, f);
- fclose (f);
-
- if (n != size) {
+ if (f.read(data(), 1, size) != size) {
boost::throw_exception (FileError("could not read from JPEG2000 file", path, errno));
}
diff --git a/src/rating.cc b/src/rating.cc
index dc32ec9c..21960365 100644
--- a/src/rating.cc
+++ b/src/rating.cc
@@ -33,6 +33,7 @@
#include "exceptions.h"
+#include "file.h"
#include "rating.h"
#include "util.h"
#include <libcxml/cxml.h>
@@ -82,14 +83,14 @@ dcp::rating_systems()
void
dcp::load_rating_list(boost::filesystem::path ratings_file)
{
- auto f = fopen_boost (ratings_file, "r");
+ File f(ratings_file, "r");
if (!f) {
throw FileError ("Could not open ratings file", ratings_file, errno);
}
- auto get_line_no_throw = [f, ratings_file]() -> optional<string> {
+ auto get_line_no_throw = [&f, ratings_file]() -> optional<string> {
char buffer[512];
- char* r = fgets(buffer, sizeof(buffer), f);
+ char* r = f.gets(buffer, sizeof(buffer));
if (r == 0) {
return {};
}
@@ -108,7 +109,7 @@ dcp::load_rating_list(boost::filesystem::path ratings_file)
optional<string> agency;
- while (!feof(f)) {
+ while (!f.eof()) {
if (!agency) {
agency = get_line();
}
@@ -117,7 +118,7 @@ dcp::load_rating_list(boost::filesystem::path ratings_file)
auto country_code = get_line();
RatingSystem system(*agency, name, country_and_region_names, country_code);
- while (!feof(f)) {
+ while (!f.eof()) {
auto rating = get_line_no_throw();
if (!rating) {
/* End of the file */
diff --git a/src/util.cc b/src/util.cc
index ed3fb772..6ae69387 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -41,6 +41,7 @@
#include "compose.hpp"
#include "dcp_assert.h"
#include "exceptions.h"
+#include "file.h"
#include "language_tag.h"
#include "openjpeg_image.h"
#include "rating.h"
@@ -228,19 +229,6 @@ dcp::base64_decode (string const & in, unsigned char* out, int out_length)
}
-FILE *
-dcp::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
-}
-
-
optional<boost::filesystem::path>
dcp::relative_to_root (boost::filesystem::path root, boost::filesystem::path file)
{
@@ -284,15 +272,14 @@ dcp::file_to_string (boost::filesystem::path p, uintmax_t max_length)
throw MiscError (String::compose("Unexpectedly long file (%1)", p.string()));
}
- auto f = fopen_boost (p, "r");
+ File f(p, "r");
if (!f) {
throw FileError ("could not open file", p, errno);
}
char* c = new char[len];
/* This may read less than `len' if we are on Windows and we have CRLF in the file */
- int const N = fread (c, 1, len, f);
- fclose (f);
+ int const N = f.read(c, 1, len);
string s (c, N);
delete[] c;
diff --git a/src/util.h b/src/util.h
index 89278f92..451957d8 100644
--- a/src/util.h
+++ b/src/util.h
@@ -115,16 +115,6 @@ extern int base64_decode (std::string const & in, unsigned char* out, int out_le
extern boost::optional<boost::filesystem::path> relative_to_root (boost::filesystem::path root, boost::filesystem::path file);
-/** @param p Path to open
- * @param t mode flags, as for fopen(3)
- * @return FILE pointer or 0 on error
- *
- * 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.
- */
-extern FILE * fopen_boost (boost::filesystem::path, std::string);
-
extern std::string file_to_string (boost::filesystem::path, uintmax_t max_length = 1048576);
/** @param key RSA private key in PEM format (optionally with -----BEGIN... / -----END...)
diff --git a/src/wscript b/src/wscript
index 15e34379..da4d0d1e 100644
--- a/src/wscript
+++ b/src/wscript
@@ -54,6 +54,7 @@ def build(bld):
decrypted_kdm_key.cc
encrypted_kdm.cc
exceptions.cc
+ file.cc
font_asset.cc
fsk.cc
gamma_transfer_function.cc
@@ -144,6 +145,7 @@ def build(bld):
decrypted_kdm_key.h
encrypted_kdm.h
exceptions.h
+ file.h
font_asset.h
frame.h
fsk.h