0347d02f15cc7f68df9f67f4cf282682f1f3cebf
[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         char buffer[9];
125         snprintf (buffer, sizeof(buffer), "FF%02X%02X%02X", r, g, b);
126         return buffer;
127 }
128
129 /** @return An RGB string of the form RRGGBB, where e.g. RR is a two-character
130  *  hex value.
131  */
132 string
133 Colour::to_rgb_string () const
134 {
135         char buffer[7];
136         snprintf (buffer, sizeof(buffer), "%02X%02X%02X", r, g, b);
137         return buffer;
138 }
139
140 /** operator== for Colours.
141  *  @param a First colour to compare.
142  *  @param b Second colour to compare.
143  */
144 bool
145 dcp::operator== (Colour const & a, Colour const & b)
146 {
147         return (a.r == b.r && a.g == b.g && a.b == b.b);
148 }
149
150 /** operator!= for Colours.
151  *  @param a First colour to compare.
152  *  @param b Second colour to compare.
153  */
154 bool
155 dcp::operator!= (Colour const & a, Colour const & b)
156 {
157         return !(a == b);
158 }
159
160 ostream &
161 dcp::operator<< (ostream& s, Colour const & c)
162 {
163         s << "(" << c.r << ", " << c.g << ", " << c.b << ")";
164         return s;
165 }
166
167 string
168 dcp::effect_to_string (Effect e)
169 {
170         switch (e) {
171         case NONE:
172                 return "none";
173         case BORDER:
174                 return "border";
175         case SHADOW:
176                 return "shadow";
177         }
178
179         boost::throw_exception (MiscError ("unknown effect type"));
180 }
181
182 Effect
183 dcp::string_to_effect (string s)
184 {
185         if (s == "none") {
186                 return NONE;
187         } else if (s == "border") {
188                 return BORDER;
189         } else if (s == "shadow") {
190                 return SHADOW;
191         }
192
193         boost::throw_exception (DCPReadError ("unknown subtitle effect type"));
194 }
195
196 string
197 dcp::halign_to_string (HAlign h)
198 {
199         switch (h) {
200         case HALIGN_LEFT:
201                 return "left";
202         case HALIGN_CENTER:
203                 return "center";
204         case HALIGN_RIGHT:
205                 return "right";
206         }
207
208         boost::throw_exception (MiscError ("unknown subtitle halign type"));
209 }
210
211 HAlign
212 dcp::string_to_halign (string s)
213 {
214         if (s == "left") {
215                 return HALIGN_LEFT;
216         } else if (s == "center") {
217                 return HALIGN_CENTER;
218         } else if (s == "right") {
219                 return HALIGN_RIGHT;
220         }
221
222         boost::throw_exception (DCPReadError ("unknown subtitle halign type"));
223 }
224
225 string
226 dcp::valign_to_string (VAlign v)
227 {
228         switch (v) {
229         case VALIGN_TOP:
230                 return "top";
231         case VALIGN_CENTER:
232                 return "center";
233         case VALIGN_BOTTOM:
234                 return "bottom";
235         }
236
237         boost::throw_exception (MiscError ("unknown subtitle valign type"));
238 }
239
240 VAlign
241 dcp::string_to_valign (string s)
242 {
243         if (s == "top") {
244                 return VALIGN_TOP;
245         } else if (s == "center") {
246                 return VALIGN_CENTER;
247         } else if (s == "bottom") {
248                 return VALIGN_BOTTOM;
249         }
250
251         boost::throw_exception (DCPReadError ("unknown subtitle valign type"));
252 }
253
254 string
255 dcp::direction_to_string (Direction v)
256 {
257         switch (v) {
258         case DIRECTION_LTR:
259                 return "ltr";
260         case DIRECTION_RTL:
261                 return "rtl";
262         case DIRECTION_TTB:
263                 return "ttb";
264         case DIRECTION_BTT:
265                 return "btt";
266         }
267
268         boost::throw_exception (MiscError ("unknown subtitle direction type"));
269 }
270
271 Direction
272 dcp::string_to_direction (string s)
273 {
274         if (s == "ltr" || s == "horizontal") {
275                 return DIRECTION_LTR;
276         } else if (s == "rtl") {
277                 return DIRECTION_RTL;
278         } else if (s == "ttb" || s == "vertical") {
279                 return DIRECTION_TTB;
280         } else if (s == "btt") {
281                 return DIRECTION_BTT;
282         }
283
284         boost::throw_exception (DCPReadError ("unknown subtitle direction type"));
285 }