Fix missing version string when Popen communicate returns byte strings.
[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 bool dcp::operator== (dcp::Size const & a, dcp::Size const & b)
48 {
49         return (a.width == b.width && a.height == b.height);
50 }
51
52 bool dcp::operator!= (dcp::Size const & a, dcp::Size const & b)
53 {
54         return !(a == b);
55 }
56
57 ostream& dcp::operator<< (ostream& s, dcp::Size const & a)
58 {
59         s << a.width << "x" << a.height;
60         return s;
61 }
62
63 /** Construct a Fraction from a string of the form <numerator> <denominator>
64  *  e.g. "1 3".
65  */
66 Fraction::Fraction (string s)
67 {
68         vector<string> b;
69         split (b, s, is_any_of (" "));
70         if (b.size() != 2) {
71                 boost::throw_exception (XMLError ("malformed fraction " + s + " in XML node"));
72         }
73         numerator = raw_convert<int> (b[0]);
74         denominator = raw_convert<int> (b[1]);
75 }
76
77 string
78 Fraction::as_string () const
79 {
80         return String::compose ("%1 %2", numerator, denominator);
81 }
82
83 bool
84 dcp::operator== (Fraction const & a, Fraction const & b)
85 {
86         return (a.numerator == b.numerator && a.denominator == b.denominator);
87 }
88
89 bool
90 dcp::operator!= (Fraction const & a, Fraction const & b)
91 {
92         return (a.numerator != b.numerator || a.denominator != b.denominator);
93 }
94
95 ostream&
96 dcp::operator<< (ostream& s, Fraction const & f)
97 {
98         s << f.numerator << "/" << f.denominator;
99         return s;
100 }
101
102 /** Construct a Colour, initialising it to black. */
103 Colour::Colour ()
104         : r (0)
105         , g (0)
106         , b (0)
107 {
108
109 }
110
111 /** Construct a Colour from R, G and B.  The values run between
112  *  0 and 255.
113  */
114 Colour::Colour (int r_, int g_, int b_)
115         : r (r_)
116         , g (g_)
117         , b (b_)
118 {
119
120 }
121
122 /** Construct a Colour from an ARGB hex string; the alpha value is ignored.
123  *  @param argb_hex A string of the form AARRGGBB, where e.g. RR is a two-character
124  *  hex value.
125  */
126 Colour::Colour (string argb_hex)
127 {
128         int alpha;
129         if (sscanf (argb_hex.c_str(), "%2x%2x%2x%2x", &alpha, &r, &g, &b) != 4) {
130                 boost::throw_exception (XMLError ("could not parse colour string"));
131         }
132 }
133
134 /** @return An ARGB string of the form AARRGGBB, where e.g. RR is a two-character
135  *  hex value.  The alpha value will always be FF (ie 255; maximum alpha).
136  */
137 string
138 Colour::to_argb_string () const
139 {
140         char buffer[9];
141         snprintf (buffer, sizeof(buffer), "FF%02X%02X%02X", r, g, b);
142         return buffer;
143 }
144
145 /** @return An RGB string of the form RRGGBB, where e.g. RR is a two-character
146  *  hex value.
147  */
148 string
149 Colour::to_rgb_string () const
150 {
151         char buffer[7];
152         snprintf (buffer, sizeof(buffer), "%02X%02X%02X", r, g, b);
153         return buffer;
154 }
155
156 /** operator== for Colours.
157  *  @param a First colour to compare.
158  *  @param b Second colour to compare.
159  */
160 bool
161 dcp::operator== (Colour const & a, Colour const & b)
162 {
163         return (a.r == b.r && a.g == b.g && a.b == b.b);
164 }
165
166 /** operator!= for Colours.
167  *  @param a First colour to compare.
168  *  @param b Second colour to compare.
169  */
170 bool
171 dcp::operator!= (Colour const & a, Colour const & b)
172 {
173         return !(a == b);
174 }
175
176 ostream &
177 dcp::operator<< (ostream& s, Colour const & c)
178 {
179         s << "(" << c.r << ", " << c.g << ", " << c.b << ")";
180         return s;
181 }
182
183 string
184 dcp::effect_to_string (Effect e)
185 {
186         switch (e) {
187         case NONE:
188                 return "none";
189         case BORDER:
190                 return "border";
191         case SHADOW:
192                 return "shadow";
193         }
194
195         boost::throw_exception (MiscError ("unknown effect type"));
196 }
197
198 Effect
199 dcp::string_to_effect (string s)
200 {
201         if (s == "none") {
202                 return NONE;
203         } else if (s == "border") {
204                 return BORDER;
205         } else if (s == "shadow") {
206                 return SHADOW;
207         }
208
209         boost::throw_exception (DCPReadError ("unknown subtitle effect type"));
210 }
211
212 string
213 dcp::halign_to_string (HAlign h)
214 {
215         switch (h) {
216         case HALIGN_LEFT:
217                 return "left";
218         case HALIGN_CENTER:
219                 return "center";
220         case HALIGN_RIGHT:
221                 return "right";
222         }
223
224         boost::throw_exception (MiscError ("unknown subtitle halign type"));
225 }
226
227 HAlign
228 dcp::string_to_halign (string s)
229 {
230         if (s == "left") {
231                 return HALIGN_LEFT;
232         } else if (s == "center") {
233                 return HALIGN_CENTER;
234         } else if (s == "right") {
235                 return HALIGN_RIGHT;
236         }
237
238         boost::throw_exception (DCPReadError ("unknown subtitle halign type"));
239 }
240
241 string
242 dcp::valign_to_string (VAlign v)
243 {
244         switch (v) {
245         case VALIGN_TOP:
246                 return "top";
247         case VALIGN_CENTER:
248                 return "center";
249         case VALIGN_BOTTOM:
250                 return "bottom";
251         }
252
253         boost::throw_exception (MiscError ("unknown subtitle valign type"));
254 }
255
256 VAlign
257 dcp::string_to_valign (string s)
258 {
259         if (s == "top") {
260                 return VALIGN_TOP;
261         } else if (s == "center") {
262                 return VALIGN_CENTER;
263         } else if (s == "bottom") {
264                 return VALIGN_BOTTOM;
265         }
266
267         boost::throw_exception (DCPReadError ("unknown subtitle valign type"));
268 }
269
270 string
271 dcp::direction_to_string (Direction v)
272 {
273         switch (v) {
274         case DIRECTION_LTR:
275                 return "ltr";
276         case DIRECTION_RTL:
277                 return "rtl";
278         case DIRECTION_TTB:
279                 return "ttb";
280         case DIRECTION_BTT:
281                 return "btt";
282         }
283
284         boost::throw_exception (MiscError ("unknown subtitle direction type"));
285 }
286
287 Direction
288 dcp::string_to_direction (string s)
289 {
290         if (s == "ltr" || s == "horizontal") {
291                 return DIRECTION_LTR;
292         } else if (s == "rtl") {
293                 return DIRECTION_RTL;
294         } else if (s == "ttb" || s == "vertical") {
295                 return DIRECTION_TTB;
296         } else if (s == "btt") {
297                 return DIRECTION_BTT;
298         }
299
300         boost::throw_exception (DCPReadError ("unknown subtitle direction type"));
301 }