X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Ffile_group.cc;h=9863a21cbd37617c5f69fa14be7aae7bb5b55dc5;hb=e5277d4042b896c4b50c694fba0f1afb47337f45;hp=dfe336b8f87eae4a9a568251aa8c735316acb61f;hpb=6219882009ffd499b4b8000697b17a659c834212;p=dcpomatic.git diff --git a/src/lib/file_group.cc b/src/lib/file_group.cc index dfe336b8f..9863a21cb 100644 --- a/src/lib/file_group.cc +++ b/src/lib/file_group.cc @@ -1,46 +1,59 @@ /* - Copyright (C) 2013 Carl Hetherington + Copyright (C) 2013-2018 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 +/** @file src/lib/file_group.cc + * @brief FileGroup class. + */ + #include "file_group.h" #include "exceptions.h" #include "cross.h" +#include "compose.hpp" +#include +#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) { } +/** Construct a FileGroup with a single file */ FileGroup::FileGroup (boost::filesystem::path p) : _current_path (0) , _current_file (0) + , _current_size (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) @@ -50,6 +63,7 @@ FileGroup::FileGroup (vector const & p) seek (0, SEEK_SET); } +/** Destroy a FileGroup, closing any open file */ FileGroup::~FileGroup () { if (_current_file) { @@ -73,7 +87,7 @@ FileGroup::ensure_open_path (size_t p) const /* Already open */ return; } - + if (_current_file) { fclose (_current_file); } @@ -81,8 +95,9 @@ 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]); + throw OpenFileError (_paths[_current_path], errno, OpenFileError::READ); } + _current_size = boost::filesystem::file_size (_paths[_current_path]); } int64_t @@ -100,7 +115,11 @@ FileGroup::seek (int64_t pos, int whence) const 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; break; case SEEK_END: @@ -125,37 +144,52 @@ FileGroup::seek (int64_t pos, int whence) const } ensure_open_path (i); - fseek (_current_file, sub_pos, SEEK_SET); + dcpomatic_fseek (_current_file, sub_pos, SEEK_SET); return full_pos; } /** 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) { + int64_t to_read = amount - read; +#ifdef DCPOMATIC_WINDOWS + /* If we over-read from the file by too much on Windows we get a errno=22 rather than an feof condition, + * for unknown reasons. So if we're going to over-read, we need to do it by a little bit, so that feof + * still gets triggered but there is no errno=22. + */ + to_read = std::min(to_read, static_cast(_current_size - _ftelli64(_current_file) + 1)); +#endif + int const this_time = fread (buffer + read, 1, to_read, _current_file); read += 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 (feof (_current_file)) { + /* 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 {