diff options
| author | Carl Hetherington <cth@carlh.net> | 2014-10-06 00:58:02 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2014-10-06 00:58:02 +0100 |
| commit | d68bb2ae0e6a3a19c627f9005eed7aca206349cd (patch) | |
| tree | 4217b30f04131f6a4b14dbe6dbdc1edd9758c264 /src | |
| parent | 385a64deea15f8cf360d342fbc62c17ce86c2859 (diff) | |
Basic and scruffy Subrip read support.
Diffstat (limited to 'src')
| -rw-r--r-- | src/exceptions.h | 46 | ||||
| -rw-r--r-- | src/subrip_reader.cc | 191 | ||||
| -rw-r--r-- | src/subrip_reader.h | 36 | ||||
| -rw-r--r-- | src/time_pair.h | 10 | ||||
| -rw-r--r-- | src/wscript | 1 |
5 files changed, 267 insertions, 17 deletions
diff --git a/src/exceptions.h b/src/exceptions.h index f2f1246..cb49d86 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -22,14 +22,12 @@ namespace sub { -/** @class XMLError - * @brief An error raised when reading an XML file. - */ -class XMLError : public std::exception +class MessageError : public std::exception { public: - XMLError (std::string const & message) : _message (message) {} - ~XMLError () throw () {} + MessageError (std::string const & message) + : _message (message) {} + ~MessageError () throw () {} /** @return error message */ char const * what () const throw () { @@ -41,23 +39,37 @@ private: std::string _message; }; +/** @class XMLError + * @brief An error raised when reading an XML file. + */ +class XMLError : public MessageError +{ +public: + XMLError (std::string const & message) + : MessageError (message) + {} +}; + /** @class STLError * @brief An error raised when reading a binary STL file. */ -class STLError : public std::exception +class STLError : public MessageError { public: - STLError (std::string const & message) : _message (message) {} - ~STLError () throw () {} - - /** @return error message */ - char const * what () const throw () { - return _message.c_str (); - } + STLError (std::string const & message) + : MessageError (message) + {} +}; -private: - /** error message */ - std::string _message; +/** @class SubripError + * @brief An error raised when reading a Subrip file. + */ +class SubripError : public MessageError +{ +public: + SubripError (std::string saw, std::string expecting) + : MessageError ("Error in SubRip file: saw " + saw + " while expecting " + expecting) + {} }; } diff --git a/src/subrip_reader.cc b/src/subrip_reader.cc new file mode 100644 index 0000000..873a6f1 --- /dev/null +++ b/src/subrip_reader.cc @@ -0,0 +1,191 @@ +/* + Copyright (C) 2014 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 "subrip_reader.h" +#include "exceptions.h" +#include <boost/algorithm/string.hpp> +#include <boost/lexical_cast.hpp> +#include <cstdio> +#include <vector> + +using std::string; +using std::vector; +using boost::lexical_cast; +using namespace sub; + +SubripReader::SubripReader (FILE* f) +{ + enum { + COUNTER, + METADATA, + CONTENT + } state = COUNTER; + + char buffer[256]; + + TimePair from; + TimePair to; + + string line; + int line_number = 0; + + while (!feof (f)) { + fgets (buffer, sizeof (buffer), f); + if (feof (f)) { + break; + } + + line = string (buffer); + trim_right_if (line, boost::is_any_of ("\n\r")); + + switch (state) { + case COUNTER: + { + if (line.empty ()) { + /* a blank line at the start is ok */ + break; + } + + state = METADATA; + } + break; + case METADATA: + { + vector<string> p; + boost::algorithm::split (p, line, boost::algorithm::is_any_of (" ")); + if (p.size() != 3 && p.size() != 7) { + throw SubripError (line, "a time/position line"); + } + + from = convert_time (p[0]); + to = convert_time (p[2]); + + /* XXX: should not ignore coordinate specifications */ + + state = CONTENT; + break; + } + case CONTENT: + if (line.empty ()) { + state = COUNTER; + line_number = 0; + } else { + convert_line (line, line_number, from, to); + line_number++; + } + break; + } + } +} + +TimePair +SubripReader::convert_time (string t) +{ + vector<string> a; + boost::algorithm::split (a, t, boost::is_any_of (":")); + if (a.size() != 3) { + throw SubripError (t, "time in the format h:m:s,ms"); + } + + vector<string> b; + boost::algorithm::split (b, a[2], boost::is_any_of (",")); + + return TimePair ( + MetricTime ( + lexical_cast<int> (a[0]), + lexical_cast<int> (a[1]), + lexical_cast<int> (b[0]), + lexical_cast<int> (b[1]) + ) + ); +} + +void +SubripReader::convert_line (string t, int line_number, TimePair from, TimePair to) +{ + enum { + TEXT, + TAG + } state = TEXT; + + string tag; + + RawSubtitle p; + p.font = "Arial"; + p.font_size.set_points (48); + p.from = from; + p.to = to; + p.vertical_position.proportional = 0.7 + line_number * 0.1; + p.vertical_position.reference = TOP; + + /* XXX: missing <font> support */ + /* XXX: nesting of tags e.g. <b>foo<i>bar<b>baz</b>fred</i>jim</b> might + not work, I think. + */ + + for (size_t i = 0; i < t.size(); ++i) { + switch (state) { + case TEXT: + if (t[i] == '<' || t[i] == '{') { + state = TAG; + } else { + p.text += t[i]; + } + break; + case TAG: + if (t[i] == '>' || t[i] == '}') { + if (tag == "b") { + maybe_content (p); + p.bold = true; + } else if (tag == "/b") { + maybe_content (p); + p.bold = false; + } else if (tag == "i") { + maybe_content (p); + p.italic = true; + } else if (tag == "/i") { + maybe_content (p); + p.italic = false; + } else if (tag == "u") { + maybe_content (p); + p.underline = true; + } else if (tag == "/u") { + maybe_content (p); + p.underline = false; + } + tag.clear (); + state = TEXT; + } else { + tag += t[i]; + } + break; + } + } + + maybe_content (p); +} + +void +SubripReader::maybe_content (RawSubtitle& p) +{ + if (!p.text.empty ()) { + _subs.push_back (p); + p.text.clear (); + } +} diff --git a/src/subrip_reader.h b/src/subrip_reader.h new file mode 100644 index 0000000..2c69971 --- /dev/null +++ b/src/subrip_reader.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2014 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 "reader.h" +#include "time_pair.h" + +namespace sub { + +class SubripReader : public Reader +{ +public: + SubripReader (FILE* f); + +private: + TimePair convert_time (std::string t); + void convert_line (std::string t, int line_number, TimePair from, TimePair to); + void maybe_content (RawSubtitle& p); +}; + +} diff --git a/src/time_pair.h b/src/time_pair.h index a9c1a09..d4b2c09 100644 --- a/src/time_pair.h +++ b/src/time_pair.h @@ -32,6 +32,16 @@ namespace sub { class TimePair { public: + TimePair () {} + + TimePair (FrameTime t) + : _frame (t) + {} + + TimePair (MetricTime t) + : _metric (t) + {} + void set_frame (FrameTime t) { _frame = t; _metric = boost::optional<MetricTime> (); diff --git a/src/wscript b/src/wscript index ef5c787..160277f 100644 --- a/src/wscript +++ b/src/wscript @@ -28,6 +28,7 @@ def build(bld): stl_text_reader.cc stl_util.cc time_pair.cc + subrip_reader.cc subtitle.cc vertical_reference.cc vertical_position.cc |
