X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Flib%2Ffile_group.cc;h=7dae1da92c26690f40ccdff9c4dd7d026d3d24d1;hp=54ec8280c0a6830da2a671137dc7a4f45336b61b;hb=8963f0007af1a312017b9627c18b82ec2a577591;hpb=e6c67f4aac2ca9afc275b6f13058e1e46f2cecc3 diff --git a/src/lib/file_group.cc b/src/lib/file_group.cc index 54ec8280c..7dae1da92 100644 --- a/src/lib/file_group.cc +++ b/src/lib/file_group.cc @@ -1,63 +1,66 @@ /* - Copyright (C) 2013-2014 Carl Hetherington + Copyright (C) 2013-2021 Carl Hetherington - This program is free software; you can redistribute it and/or modify + This file is part of DCP-o-matic. + + DCP-o-matic 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, + DCP-o-matic 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. + along with DCP-o-matic. If not, see . */ + /** @file src/lib/file_group.cc * @brief FileGroup class. */ -#include -#include -#include "file_group.h" -#include "exceptions.h" + +#include "compose.hpp" #include "cross.h" +#include "dcpomatic_assert.h" +#include "exceptions.h" +#include "file_group.h" +#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 () { @@ -66,6 +69,7 @@ FileGroup::~FileGroup () } } + void FileGroup::set_paths (vector const & p) { @@ -74,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 @@ -82,93 +87,117 @@ FileGroup::ensure_open_path (size_t p) const /* Already open */ return; } - + if (_current_file) { fclose (_current_file); } _current_path = p; _current_file = fopen_boost (_paths[_current_path], "rb"); - if (_current_file == 0) { - throw OpenFileError (_paths[_current_path]); + 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. - * @return Number of bytes read, or -1 in the case of error. + * @return Number of bytes read. */ int FileGroup::read (uint8_t* buffer, int amount) const { int read = 0; - while (1) { - int const this_time = fread (buffer + read, 1, amount - read, _current_file); + while (true) { + + 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; } - /* See if there is another file to use */ - if ((_current_path + 1) >= _paths.size()) { - break; + if (ferror(_current_file)) { + throw FileError (String::compose("fread error %1", errno), _paths[_current_path]); + } + + if (eof) { + /* See if there is another file to use */ + if ((_current_path + 1) >= _paths.size()) { + break; + } + ensure_open_path (_current_path + 1); } - ensure_open_path (_current_path + 1); } return read; } + /** @return Combined length of all the files */ int64_t FileGroup::length () const