X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Ffile_group.cc;h=f4d50028ecdc1037ae1547818e30248992fd64d4;hb=37d2bf172e9061f24c874d5416bd3c8f9719c823;hp=d364a395d6a6d2f5ad986e2e7c9ffcaf81fcd9e4;hpb=d302d45c2102b8fc97bbd256b43fa74119cc9332;p=dcpomatic.git diff --git a/src/lib/file_group.cc b/src/lib/file_group.cc index d364a395d..f4d50028e 100644 --- a/src/lib/file_group.cc +++ b/src/lib/file_group.cc @@ -1,52 +1,72 @@ /* - Copyright (C) 2013 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 . */ -#include -#include -#include "file_group.h" + +/** @file src/lib/file_group.cc + * @brief FileGroup class. + */ + + +#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 () +{ + +} + + +/** 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); } -FileGroup::~FileGroup () + +void +FileGroup::set_paths (vector const & p) { - if (_current_file) { - fclose (_current_file); - } + _paths = p; + ensure_open_path (0); + seek (0, SEEK_SET); } @@ -58,91 +78,111 @@ FileGroup::ensure_open_path (size_t p) const /* Already open */ return; } - + if (_current_file) { - fclose (_current_file); + _current_file->close(); } _current_path = p; - _current_file = fopen (_paths[_current_path].string().c_str(), "rb"); - if (_current_file == 0) { - throw OpenFileError (_paths[_current_path]); + _current_file = dcp::File(_paths[_current_path], "rb"); + 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 { - int64_t const len = length (); - - /* 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]); - } - full_pos += ftell (_current_file); - full_pos += pos; + _position += pos; break; case SEEK_END: - full_pos = len - 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); + _current_file->seek(sub_pos, SEEK_SET); + } else { + ensure_open_path (_paths.size() - 1); + _current_file->seek(_current_size, SEEK_SET); } - ensure_open_path (i); - 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. */ -int +FileGroup::Result FileGroup::read (uint8_t* buffer, int amount) const { + DCPOMATIC_ASSERT (_current_file); + 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); + + auto const current_position = _current_file->tell(); + 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; + } + + int const this_time = _current_file->read(buffer + read, 1, to_read); 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 (_current_file->error()) { + 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()) { + return { read, true }; + } + ensure_open_path (_current_path + 1); } - ensure_open_path (_current_path + 1); } - return read; + return { read, false }; } + +/** @return Combined length of all the files */ int64_t FileGroup::length () const {