Add exception missing from previous commit.
[libsub.git] / src / util.cc
1 /*
2     Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "util.h"
21 #include "reader.h"
22 #include "subtitle.h"
23 #include "collect.h"
24 #include <memory>
25 #include <string>
26 #include <iostream>
27 #include <cstdio>
28 #include <map>
29
30 using std::string;
31 using std::getline;
32 using std::ostream;
33 using std::map;
34 using std::list;
35 using std::shared_ptr;
36 using std::vector;
37 using boost::optional;
38 using namespace sub;
39
40 /** @param s A string.
41  *  @return true if the string contains only space, newline or tab characters, or is empty.
42  */
43 bool
44 sub::empty_or_white_space (string s)
45 {
46         for (size_t i = 0; i < s.length(); ++i) {
47                 if (s[i] != ' ' && s[i] != '\n' && s[i] != '\t') {
48                         return false;
49                 }
50         }
51
52         return true;
53 }
54
55 optional<string>
56 sub::get_line_string (string* s)
57 {
58         if (s->length() == 0) {
59                 return optional<string>();
60         }
61
62         size_t pos = s->find ("\n");
63         if (pos == string::npos) {
64                 string const c = *s;
65                 *s = "";
66                 return c;
67         }
68
69         string const c = s->substr (0, pos);
70         s->erase (0, pos + 1);
71         return c;
72 }
73
74 optional<string>
75 sub::get_line_file (FILE* f)
76 {
77         char buffer[256];
78         char* r = fgets (buffer, sizeof (buffer), f);
79         if (r == 0) {
80                 return optional<string> ();
81         }
82
83         return string (buffer);
84 }
85
86 void
87 sub::remove_unicode_bom (optional<string>& line)
88 {
89         if (
90                 line->length() >= 3 &&
91                 static_cast<unsigned char> (line.get()[0]) == 0xef &&
92                 static_cast<unsigned char> (line.get()[1]) == 0xbb &&
93                 static_cast<unsigned char> (line.get()[2]) == 0xbf
94                 ) {
95
96                 /* Skip Unicode byte order mark */
97                 line = line->substr (3);
98         }
99 }
100
101 void
102 sub::dump (shared_ptr<const Reader> reader, ostream& os)
103 {
104         auto metadata = reader->metadata ();
105         for (auto const& i: metadata) {
106                 os << i.first << ": " << i.second << "\n";
107         }
108
109         auto subs = collect<vector<sub::Subtitle>> (reader->subtitles());
110         int n = 0;
111         for (auto const& i: subs) {
112                 os << "Subtitle " << n << " at " << i.from << " -> " << i.to << "\n";
113                 for (auto const& j: i.lines) {
114
115                         os << "\t";
116
117                         if (j.vertical_position.proportional) {
118                                 os << j.vertical_position.proportional.get() << " of screen";
119                         } else if (j.vertical_position.line && j.vertical_position.lines) {
120                                 os << j.vertical_position.line.get() << " lines of " << j.vertical_position.lines.get();
121                         }
122                         if (j.vertical_position.reference) {
123                                 os << " from ";
124                                 switch (j.vertical_position.reference.get()) {
125                                 case TOP_OF_SCREEN:
126                                         os << "top";
127                                         break;
128                                 case VERTICAL_CENTRE_OF_SCREEN:
129                                         os << "centre";
130                                         break;
131                                 case BOTTOM_OF_SCREEN:
132                                         os << "bottom";
133                                         break;
134                                 case TOP_OF_SUBTITLE:
135                                         os << "top of subtitle";
136                                         break;
137                                 }
138                         }
139
140                         os << "\t";
141                         bool italic = false;
142                         bool underline = false;
143                         for (auto const& k: j.blocks) {
144                                 if (k.italic && !italic) {
145                                         os << "<i>";
146                                 } else if (italic && !k.italic) {
147                                         os << "</i>";
148                                 }
149                                 if (k.underline && !underline) {
150                                         os << "<u>";
151                                 } else if (underline && !k.underline) {
152                                         os << "</u>";
153                                 }
154
155                                 italic = k.italic;
156                                 underline = k.underline;
157
158                                 os << k.text;
159                         }
160
161                         if (italic) {
162                                 os << "</i>";
163                         }
164                         if (underline) {
165                                 os << "</u>";
166                         }
167                         os << "\n";
168                 }
169
170                 ++n;
171         }
172 }