diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-11-23 12:33:13 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-11-23 12:33:13 +0000 |
| commit | 5a999debb53087de8188603ea9b9d928b2293978 (patch) | |
| tree | f00f5e8e604bda3fec11a8b269ff8ecff4c2ad68 /src/lib | |
| parent | a0c0e609f7fbff8513135428378cc16684bae937 (diff) | |
Add FileGroup.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/file_group.cc | 160 | ||||
| -rw-r--r-- | src/lib/file_group.h | 46 |
2 files changed, 206 insertions, 0 deletions
diff --git a/src/lib/file_group.cc b/src/lib/file_group.cc new file mode 100644 index 000000000..5f9531f4c --- /dev/null +++ b/src/lib/file_group.cc @@ -0,0 +1,160 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + This program 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, + 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. + +*/ + +#include <cstdio> +extern "C" { +#include <libavformat/avio.h> +} +#include <sndfile.h> +#include "file_group.h" +#include "exceptions.h" + +using std::vector; +using std::cout; + +FileGroup::FileGroup (boost::filesystem::path p) + : _current_path (0) + , _current_file (0) +{ + _paths.push_back (p); + seek (0, SEEK_SET); +} + +FileGroup::FileGroup (vector<boost::filesystem::path> const & p) + : _paths (p) + , _current_path (0) + , _current_file (0) +{ + ensure_open_path (0); + seek (0, SEEK_SET); +} + +FileGroup::~FileGroup () +{ + if (_current_file) { + fclose (_current_file); + } +} + + +/** Ensure that the given path index in the content is the _current_file */ +void +FileGroup::ensure_open_path (size_t p) const +{ + if (_current_file && _current_path == p) { + /* Already open */ + return; + } + + if (_current_file) { + fclose (_current_file); + } + + _current_path = p; + _current_file = fopen (_paths[_current_path].string().c_str(), "rb"); + if (_current_file == 0) { + throw OpenFileError (_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; + 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; + break; + case SEEK_END: + full_pos = len - pos; + break; + case AVSEEK_SIZE: + return len; + } + + /* Seek to full_pos */ + size_t i = 0; + int64_t sub_pos = full_pos; + while (i < _paths.size ()) { + boost::uintmax_t len = boost::filesystem::file_size (_paths[i]); + if (sub_pos < int64_t (len)) { + break; + } + sub_pos -= len; + ++i; + } + + if (i == _paths.size ()) { + return -1; + } + + ensure_open_path (i); + 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. + */ +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); + read += this_time; + if (read == amount) { + /* Done */ + break; + } + + /* See if there is another file to use */ + if ((_current_path + 1) >= _paths.size()) { + break; + } + ensure_open_path (_current_path + 1); + } + + return read; +} + +int64_t +FileGroup::length () const +{ + int64_t len = 0; + for (size_t i = 0; i < _paths.size(); ++i) { + len += boost::filesystem::file_size (_paths[i]); + } + + return len; +} diff --git a/src/lib/file_group.h b/src/lib/file_group.h new file mode 100644 index 000000000..99803d386 --- /dev/null +++ b/src/lib/file_group.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> + + This program 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, + 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. + +*/ + +#ifndef DCPOMATIC_FILE_GROUP_H +#define DCPOMATIC_FILE_GROUP_H + +#include <vector> +#include <boost/filesystem.hpp> + +class FileGroup +{ +public: + FileGroup (boost::filesystem::path); + FileGroup (std::vector<boost::filesystem::path> const &); + ~FileGroup (); + + int64_t seek (int64_t, int) const; + int read (uint8_t*, int) const; + int64_t length () const; + +private: + void ensure_open_path (size_t) const; + + std::vector<boost::filesystem::path> _paths; + /** Index of path that we are currently reading from */ + mutable size_t _current_path; + mutable FILE* _current_file; +}; + +#endif |
