diff options
| author | Carl Hetherington <cth@carlh.net> | 2022-04-12 22:34:04 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2022-04-20 20:04:21 +0200 |
| commit | 05bfa3d1fe9e274ed195647c6f74cb272f00c23d (patch) | |
| tree | 1372760463b288ff4e10ef7fb6e7414e202829f5 /src | |
| parent | 0338e7a7c19617f9ebb64ee02fbf3cceab8cf03f (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.cc | 11 | ||||
| -rw-r--r-- | src/data.cc | 8 | ||||
| -rw-r--r-- | src/encrypted_kdm.cc | 13 | ||||
| -rw-r--r-- | src/file.cc | 106 | ||||
| -rw-r--r-- | src/file.h | 78 | ||||
| -rw-r--r-- | src/interop_subtitle_asset.cc | 6 | ||||
| -rw-r--r-- | src/language_tag.cc | 14 | ||||
| -rw-r--r-- | src/mono_picture_frame.cc | 8 | ||||
| -rw-r--r-- | src/rating.cc | 11 | ||||
| -rw-r--r-- | src/util.cc | 19 | ||||
| -rw-r--r-- | src/util.h | 10 | ||||
| -rw-r--r-- | src/wscript | 2 |
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; @@ -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 |
