X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Ffile_group.cc;h=aaf94acf4b17a2eaf25595ba61fe9c4d5d964ed4;hb=28111007e2e6fd62f5810be780706ae1618bd33f;hp=90aa10e28beb9d86aef50479555f378bf524e39d;hpb=513947df0f421c086ac56dff48dfe540b0a380c2;p=dcpomatic.git diff --git a/src/lib/file_group.cc b/src/lib/file_group.cc index 90aa10e28..aaf94acf4 100644 --- a/src/lib/file_group.cc +++ b/src/lib/file_group.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2014 Carl Hetherington + Copyright (C) 2013-2020 Carl Hetherington This file is part of DCP-o-matic. @@ -22,20 +22,22 @@ * @brief FileGroup class. */ -#include -#include #include "file_group.h" #include "exceptions.h" #include "cross.h" -#include +#include "compose.hpp" +#include "dcpomatic_assert.h" +#include +#include using std::vector; -using std::cout; /** Construct a FileGroup with no files */ FileGroup::FileGroup () : _current_path (0) , _current_file (0) + , _current_size (0) + , _position (0) { } @@ -44,6 +46,7 @@ FileGroup::FileGroup () FileGroup::FileGroup (boost::filesystem::path p) : _current_path (0) , _current_file (0) + , _current_size (0) { _paths.push_back (p); ensure_open_path (0); @@ -92,80 +95,101 @@ 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); + 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 (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; } - /* 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;