X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Ffile_group.cc;h=7dae1da92c26690f40ccdff9c4dd7d026d3d24d1;hb=924f4edb20d14bc697956254951fb87513cf2e19;hp=942eb435d87f081e38ef5e48bf53ea0e4dd3cdea;hpb=d60fd90a6e13c727a05b629c8c4b93d4bf3b717b;p=dcpomatic.git diff --git a/src/lib/file_group.cc b/src/lib/file_group.cc index 942eb435d..7dae1da92 100644 --- a/src/lib/file_group.cc +++ b/src/lib/file_group.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2018 Carl Hetherington + Copyright (C) 2013-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,49 +18,49 @@ */ + /** @file src/lib/file_group.cc * @brief FileGroup class. */ -#include "file_group.h" -#include "exceptions.h" -#include "cross.h" + #include "compose.hpp" +#include "cross.h" +#include "dcpomatic_assert.h" +#include "exceptions.h" +#include "file_group.h" #include #include -#include + using std::vector; -using std::cout; + /** Construct a FileGroup with no files */ FileGroup::FileGroup () - : _current_path (0) - , _current_file (0) { } + /** Construct a FileGroup with a single file */ FileGroup::FileGroup (boost::filesystem::path p) - : _current_path (0) - , _current_file (0) { _paths.push_back (p); ensure_open_path (0); seek (0, SEEK_SET); } + /** Construct a FileGroup with multiple files */ FileGroup::FileGroup (vector const & p) : _paths (p) - , _current_path (0) - , _current_file (0) { ensure_open_path (0); seek (0, SEEK_SET); } + /** Destroy a FileGroup, closing any open file */ FileGroup::~FileGroup () { @@ -69,6 +69,7 @@ FileGroup::~FileGroup () } } + void FileGroup::set_paths (vector const & p) { @@ -77,6 +78,7 @@ FileGroup::set_paths (vector const & p) seek (0, SEEK_SET); } + /** Ensure that the given path index in the content is the _current_file */ void FileGroup::ensure_open_path (size_t p) const @@ -92,59 +94,52 @@ FileGroup::ensure_open_path (size_t p) const _current_path = p; _current_file = fopen_boost (_paths[_current_path], "rb"); - if (_current_file == 0) { - throw OpenFileError (_paths[_current_path], errno, true); + if (!_current_file) { + throw OpenFileError (_paths[_current_path], errno, OpenFileError::READ); } + _current_size = boost::filesystem::file_size (_paths[_current_path]); } + int64_t FileGroup::seek (int64_t pos, int whence) const { - /* Convert pos to `full_pos', which is an offset from the start - of all the files. - */ - int64_t full_pos = 0; switch (whence) { case SEEK_SET: - full_pos = pos; + _position = pos; break; case SEEK_CUR: - for (size_t i = 0; i < _current_path; ++i) { - full_pos += boost::filesystem::file_size (_paths[i]); - } -#ifdef DCPOMATIC_WINDOWS - full_pos += _ftelli64 (_current_file); -#else - full_pos += ftell (_current_file); -#endif - full_pos += pos; + _position += pos; break; case SEEK_END: - full_pos = length() - pos; + _position = length() - pos; break; } - /* Seek to full_pos */ + /* Find an offset within one of the files, if _position is within a file */ size_t i = 0; - int64_t sub_pos = full_pos; - while (i < _paths.size ()) { + int64_t sub_pos = _position; + while (i < _paths.size()) { boost::uintmax_t len = boost::filesystem::file_size (_paths[i]); - if (sub_pos < int64_t (len)) { + if (sub_pos < int64_t(len)) { break; } - sub_pos -= len; + sub_pos -= int64_t(len); ++i; } - if (i == _paths.size ()) { - return -1; + if (i < _paths.size()) { + ensure_open_path (i); + dcpomatic_fseek (_current_file, sub_pos, SEEK_SET); + } else { + ensure_open_path (_paths.size() - 1); + dcpomatic_fseek (_current_file, _current_size, SEEK_SET); } - ensure_open_path (i); - dcpomatic_fseek (_current_file, sub_pos, SEEK_SET); - return full_pos; + return _position; } + /** Try to read some data from the current position into a buffer. * @param buffer Buffer to write data into. * @param amount Number of bytes to read. @@ -155,8 +150,32 @@ FileGroup::read (uint8_t* buffer, int amount) const { int read = 0; while (true) { - int const this_time = fread (buffer + read, 1, amount - read, _current_file); + + bool eof = false; + size_t to_read = amount - read; + + DCPOMATIC_ASSERT (_current_file); + +#ifdef DCPOMATIC_WINDOWS + int64_t const current_position = _ftelli64 (_current_file); + if (current_position == -1) { + to_read = 0; + eof = true; + } else if ((current_position + to_read) > _current_size) { + to_read = _current_size - current_position; + eof = true; + } +#else + long const current_position = ftell(_current_file); + if ((current_position + to_read) > _current_size) { + to_read = _current_size - current_position; + eof = true; + } +#endif + + int const this_time = fread (buffer + read, 1, to_read, _current_file); read += this_time; + _position += this_time; if (read == amount) { /* Done */ break; @@ -166,7 +185,7 @@ FileGroup::read (uint8_t* buffer, int amount) const throw FileError (String::compose("fread error %1", errno), _paths[_current_path]); } - if (feof (_current_file)) { + if (eof) { /* See if there is another file to use */ if ((_current_path + 1) >= _paths.size()) { break; @@ -178,6 +197,7 @@ FileGroup::read (uint8_t* buffer, int amount) const return read; } + /** @return Combined length of all the files */ int64_t FileGroup::length () const