Use locked_sstream. Replace once parse_stream with parse_memory.
[libdcp.git] / src / types.cc
1 /*
2     Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
6     libdcp 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.
10
11     libdcp 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.
15
16     You should have received a copy of the GNU General Public License
17     along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
18
19     In addition, as a special exception, the copyright holders give
20     permission to link the code of portions of this program with the
21     OpenSSL library under certain conditions as described in each
22     individual source file, and distribute linked combinations
23     including the two.
24
25     You must obey the GNU General Public License in all respects
26     for all of the code used other than OpenSSL.  If you modify
27     file(s) with this exception, you may extend this exception to your
28     version of the file(s), but you are not obligated to do so.  If you
29     do not wish to do so, delete this exception statement from your
30     version.  If you delete this exception statement from all source
31     files in the program, then also delete it here.
32 */
33
34 #include "raw_convert.h"
35 #include "types.h"
36 #include "exceptions.h"
37 #include "compose.hpp"
38 #include <boost/algorithm/string.hpp>
39 #include <vector>
40 #include <cstdio>
41 #include <iomanip>
42
43 using namespace std;
44 using namespace dcp;
45 using namespace boost;
46
47 /** Construct a Fraction from a string of the form <numerator> <denominator>
48  *  e.g. "1 3".
49  */
50 Fraction::Fraction (string s)
51 {
52         vector<string> b;
53         split (b, s, is_any_of (" "));
54         if (b.size() != 2) {
55                 boost::throw_exception (XMLError ("malformed fraction " + s + " in XML node"));
56         }
57         numerator = raw_convert<int> (b[0]);
58         denominator = raw_convert<int> (b[1]);
59 }
60
61 string
62 Fraction::as_string () const
63 {
64         return String::compose ("%1 %2", numerator, denominator);
65 }
66
67 bool
68 dcp::operator== (Fraction const & a, Fraction const & b)
69 {
70         return (a.numerator == b.numerator && a.denominator == b.denominator);
71 }
72
73 bool
74 dcp::operator!= (Fraction const & a, Fraction const & b)
75 {
76         return (a.numerator != b.numerator || a.denominator != b.denominator);
77 }
78
79 ostream&
80 dcp::operator<< (ostream& s, Fraction const & f)
81 {
82         s << f.numerator << "/" << f.denominator;
83         return s;
84 }
85
86 /** Construct a Colour, initialising it to black. */
87 Colour::Colour ()
88         : r (0)
89         , g (0)
90         , b (0)
91 {
92
93 }
94
95 /** Construct a Colour from R, G and B.  The values run between
96  *  0 and 255.
97  */
98 Colour::Colour (int r_, int g_, int b_)
99         : r (r_)
100         , g (g_)
101         , b (b_)
102 {
103
104 }
105
106 /** Construct a Colour from an ARGB hex string; the alpha value is ignored.
107  *  @param argb_hex A string of the form AARRGGBB, where e.g. RR is a two-character
108  *  hex value.
109  */
110 Colour::Colour (string argb_hex)
111 {
112         int alpha;
113         if (sscanf (argb_hex.c_str(), "%2x%2x%2x%2x", &alpha, &r, &g, &b) != 4) {
114                 boost::throw_exception (XMLError ("could not parse colour string"));
115         }
116 }
117
118 /** @return An ARGB string of the form AARRGGBB, where e.g. RR is a two-character
119  *  hex value.  The alpha value will always be FF (ie 255; maximum alpha).
120  */
121 string
122 Colour::to_argb_string () const
123 {
124         locked_stringstream s;
125         s << "FF";
126         s << hex
127           << setw(2) << setfill('0') << r
128           << setw(2) << setfill('0') << g
129           << setw(2) << setfill('0') << b;
130
131         string t = s.str();
132         to_upper (t);
133         return t;
134 }
135
136 /** operator== for Colours.
137  *  @param a First colour to compare.
138  *  @param b Second colour to compare.
139  */
140 bool
141 dcp::operator== (Colour const & a, Colour const & b)
142 {
143         return (a.r == b.r && a.g == b.g && a.b == b.b);
144 }
145
146 /** operator!= for Colours.
147  *  @param a First colour to compare.
148  *  @param b Second colour to compare.
149  */
150 bool
151 dcp::operator!= (Colour const & a, Colour const & b)
152 {
153         return !(a == b);
154 }
155
156 ostream &
157 dcp::operator<< (ostream& s, Colour const & c)
158 {
159         s << "(" << c.r << ", " << c.g << ", " << c.b << ")";
160         return s;
161 }
162
163 string
164 dcp::effect_to_string (Effect e)
165 {
166         switch (e) {
167         case NONE:
168                 return "none";
169         case BORDER:
170                 return "border";
171         case SHADOW:
172                 return "shadow";
173         }
174
175         boost::throw_exception (MiscError ("unknown effect type"));
176 }
177
178 Effect
179 dcp::string_to_effect (string s)
180 {
181         if (s == "none") {
182                 return NONE;
183         } else if (s == "border") {
184                 return BORDER;
185         } else if (s == "shadow") {
186                 return SHADOW;
187         }
188
189         boost::throw_exception (DCPReadError ("unknown subtitle effect type"));
190 }
191
192 string
193 dcp::halign_to_string (HAlign h)
194 {
195         switch (h) {
196         case HALIGN_LEFT:
197                 return "left";
198         case HALIGN_CENTER:
199                 return "center";
200         case HALIGN_RIGHT:
201                 return "right";
202         }
203
204         boost::throw_exception (MiscError ("unknown subtitle halign type"));
205 }
206
207 HAlign
208 dcp::string_to_halign (string s)
209 {
210         if (s == "left") {
211                 return HALIGN_LEFT;
212         } else if (s == "center") {
213                 return HALIGN_CENTER;
214         } else if (s == "right") {
215                 return HALIGN_RIGHT;
216         }
217
218         boost::throw_exception (DCPReadError ("unknown subtitle halign type"));
219 }
220
221 string
222 dcp::valign_to_string (VAlign v)
223 {
224         switch (v) {
225         case VALIGN_TOP:
226                 return "top";
227         case VALIGN_CENTER:
228                 return "center";
229         case VALIGN_BOTTOM:
230                 return "bottom";
231         }
232
233         boost::throw_exception (MiscError ("unknown subtitle valign type"));
234 }
235
236 VAlign
237 dcp::string_to_valign (string s)
238 {
239         if (s == "top") {
240                 return VALIGN_TOP;
241         } else if (s == "center") {
242                 return VALIGN_CENTER;
243         } else if (s == "bottom") {
244                 return VALIGN_BOTTOM;
245         }
246
247         boost::throw_exception (DCPReadError ("unknown subtitle valign type"));
248 }
249
250 string
251 dcp::direction_to_string (Direction v)
252 {
253         switch (v) {
254         case DIRECTION_LTR:
255                 return "ltr";
256         case DIRECTION_RTL:
257                 return "rtl";
258         case DIRECTION_TTB:
259                 return "ttb";
260         case DIRECTION_BTT:
261                 return "btt";
262         }
263
264         boost::throw_exception (MiscError ("unknown subtitle direction type"));
265 }
266
267 Direction
268 dcp::string_to_direction (string s)
269 {
270         if (s == "ltr" || s == "horizontal") {
271                 return DIRECTION_LTR;
272         } else if (s == "rtl") {
273                 return DIRECTION_RTL;
274         } else if (s == "ttb" || s == "vertical") {
275                 return DIRECTION_TTB;
276         } else if (s == "btt") {
277                 return DIRECTION_BTT;
278         }
279
280         boost::throw_exception (DCPReadError ("unknown subtitle direction type"));
281 }