2 Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 /** @file src/lib/file_group.cc
23 * @brief FileGroup class.
27 #include "compose.hpp"
29 #include "dcpomatic_assert.h"
30 #include "exceptions.h"
31 #include "file_group.h"
32 #include <dcp/filesystem.h>
40 /** Construct a FileGroup with no files */
41 FileGroup::FileGroup ()
47 /** Construct a FileGroup with a single file */
48 FileGroup::FileGroup (boost::filesystem::path p)
56 /** Construct a FileGroup with multiple files */
57 FileGroup::FileGroup (vector<boost::filesystem::path> const & p)
66 FileGroup::set_paths (vector<boost::filesystem::path> const & p)
74 /** Ensure that the given path index in the content is the _current_file */
76 FileGroup::ensure_open_path (size_t p) const
78 if (_current_file && _current_path == p) {
84 _current_file->close();
88 _current_file = dcp::File(_paths[_current_path], "rb");
90 throw OpenFileError (_paths[_current_path], errno, OpenFileError::READ);
92 _current_size = dcp::filesystem::file_size(_paths[_current_path]);
97 FileGroup::seek (int64_t pos, int whence) const
107 _position = length() - pos;
111 /* Find an offset within one of the files, if _position is within a file */
113 int64_t sub_pos = _position;
114 while (i < _paths.size()) {
115 boost::uintmax_t len = dcp::filesystem::file_size(_paths[i]);
116 if (sub_pos < int64_t(len)) {
119 sub_pos -= int64_t(len);
123 if (i < _paths.size()) {
124 ensure_open_path (i);
125 _current_file->seek(sub_pos, SEEK_SET);
127 ensure_open_path (_paths.size() - 1);
128 _current_file->seek(_current_size, SEEK_SET);
135 /** Try to read some data from the current position into a buffer.
136 * @param buffer Buffer to write data into.
137 * @param amount Number of bytes to read.
140 FileGroup::read (uint8_t* buffer, int amount) const
142 DCPOMATIC_ASSERT (_current_file);
148 size_t to_read = amount - read;
150 DCPOMATIC_ASSERT (_current_file);
152 auto const current_position = _current_file->tell();
153 if (current_position == -1) {
156 } else if ((current_position + to_read) > _current_size) {
157 to_read = _current_size - current_position;
161 int const this_time = _current_file->read(buffer + read, 1, to_read);
163 _position += this_time;
164 if (read == amount) {
169 if (_current_file->error()) {
170 throw FileError (String::compose("fread error %1", errno), _paths[_current_path]);
174 /* See if there is another file to use */
175 if ((_current_path + 1) >= _paths.size()) {
176 return { read, true };
178 ensure_open_path (_current_path + 1);
182 return { read, false };
186 /** @return Combined length of all the files */
188 FileGroup::length () const
191 for (size_t i = 0; i < _paths.size(); ++i) {
192 len += dcp::filesystem::file_size(_paths[i]);