]> git.sesse.net Git - casparcg/blob - modules/psd/util/pdf_reader.cpp
[psd] Fixed bug where keyframes where one frame off sometimes in the temporal space.
[casparcg] / modules / psd / util / pdf_reader.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG 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 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG 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 CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Niklas P Andersson, niklas.p.andersson@svt.se
20 */
21
22 #include "pdf_reader.h"
23
24 #include <common/log.h>
25
26 #pragma warning(push)
27 #pragma warning(disable: 4459)
28 #pragma warning(disable: 4244)
29 #include <boost/spirit/home/qi.hpp>
30 #pragma warning(pop)
31
32 #include <boost/lexical_cast.hpp>
33
34 #include <cstdint>
35
36 namespace qi = boost::spirit::qi;
37
38 namespace caspar { namespace psd { 
39
40 struct pdf_context
41 {
42         typedef boost::property_tree::wptree Ptree;
43         typedef std::vector<char>::iterator It;
44
45         std::wstring value;
46         bool char_flag;
47         Ptree root;
48         std::wstring name;
49         std::vector<Ptree*> stack;
50
51         void clear_state()
52         {
53                 name.clear();
54                 value.clear();
55                 char_flag = false;
56         }
57
58         void start_object()
59         {
60                 if(stack.empty())
61                         stack.push_back(&root);
62                 else
63                 {
64                         Ptree* parent = stack.back();
65                         Ptree* child = &parent->push_back(std::make_pair(name, Ptree()))->second;
66                         stack.push_back(child);
67
68                         clear_state();
69                 }
70         }
71
72         void end_object()
73         {
74                 BOOST_ASSERT(stack.size() >= 1);
75                 stack.pop_back();
76         }
77
78         std::string get_indent() const
79         {
80                 return std::string(stack.size() * 4, ' ');
81         }
82
83         void set_name(const std::string& str)
84         {
85                 name.assign(str.begin(), str.end());
86                 CASPAR_LOG(debug) << get_indent() << name;
87         }
88
89         void add_char(std::uint8_t c)
90         {
91                 char_flag = !char_flag;
92
93                 if(char_flag)
94                         value.push_back(c << 8);
95                 else
96                         value[value.size()-1] = value[value.size()-1] + c;
97         }
98
99         void set_value(bool val)
100         {
101                 value = val ? L"true" : L"false";
102                 set_value();
103         }
104         void set_value(double val)
105         {
106                 value = boost::lexical_cast<std::wstring>(val);
107                 set_value();
108         }
109
110         void set_value()
111         {
112                 CASPAR_LOG(debug) << get_indent() << value;
113
114                 stack.back()->push_back(std::make_pair(name, Ptree(value)));
115                 clear_state();
116         }
117 };
118
119 template<typename Iterator>
120 struct pdf_grammar : qi::grammar<Iterator, qi::space_type>
121 {
122         qi::rule<Iterator, qi::space_type> root, object, member, value, list;
123         qi::rule<Iterator, qi::space_type> string;
124         qi::rule<Iterator, std::string()> name_str;
125         qi::rule<Iterator> escape;
126         qi::rule<Iterator> name;
127
128         mutable pdf_context context;
129
130         pdf_grammar() : pdf_grammar::base_type(root, "pdf-grammar")
131         {
132                 root 
133                         =       object >> qi::eoi;
134                         
135                 object 
136                         =       qi::lit("<<")[a_object_start(context)] >> *member >> qi::lit(">>")[a_object_end(context)];
137
138                 member 
139                         =       qi::char_('/') >> name >> value;
140
141                 name 
142                         =       name_str[a_name(context)];
143
144                 name_str 
145                         =       (qi::alpha >> *qi::alnum);
146
147                 list 
148                         =       qi::char_('[')[a_list_start(context)] >> *value >> qi::char_(']')[a_list_end(context)];
149
150                 string
151                         =       qi::lexeme[qi::lit("(\xfe\xff") >> 
152                                         *(
153                                                 (qi::char_('\0')[a_char(context)] >> escape)
154                                         |       (qi::char_ - ')')[a_char(context)]
155                                          )
156                                         >> 
157                                         ')'];
158
159                 escape
160                         =       ('\x5c' > qi::char_("nrtbf()\\")[a_char(context)]) | qi::char_[a_char(context)];
161
162                 value 
163                         =       qi::double_[a_numeral(context)] | list | object | string[a_string(context)] | qi::lit("true")[a_bool(true, context)] | qi::lit("false")[a_bool(false, context)];
164         }
165
166         struct a_object_start
167         {
168                 pdf_context &c;
169                 explicit a_object_start(pdf_context& c) : c(c) {}
170
171                 void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const
172                 {
173                         c.start_object();
174                 }
175         };
176
177         struct a_object_end
178         {
179                 pdf_context &c;
180                 explicit a_object_end(pdf_context& c) : c(c) {}
181
182                 void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const
183                 {
184                         c.end_object();
185                 }
186         };
187         struct a_list_start
188         {
189                 pdf_context &c;
190                 explicit a_list_start(pdf_context& c) : c(c) {}
191
192                 void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const
193                 {
194                         c.start_object();
195                 }
196         };
197
198         struct a_list_end
199         {
200                 pdf_context &c;
201                 explicit a_list_end(pdf_context& c) : c(c) {}
202
203                 void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const
204                 {
205                         c.end_object();
206                 }
207         };
208
209         struct a_name
210         {
211                 pdf_context &c;
212                 explicit a_name(pdf_context& c) : c(c) {}
213
214                 void operator()(std::string const& n, qi::unused_type, qi::unused_type) const
215                 {
216                         c.set_name(n);
217                 }
218         };
219
220         struct a_numeral
221         {
222                 pdf_context &c;
223                 explicit a_numeral(pdf_context& c) : c(c) {}
224
225                 void operator()(double const& n, qi::unused_type, qi::unused_type) const
226                 {
227                         c.set_value(n);
228                 }
229         };
230
231         struct a_string
232         {
233                 pdf_context &c;
234                 explicit a_string(pdf_context& c) : c(c) {}
235
236                 void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const
237                 {
238                         c.set_value();
239                 }
240         };
241
242         struct a_bool
243         {
244                 pdf_context &c;
245                 bool val;
246                 a_bool(bool val, pdf_context& c) : val(val), c(c) {}
247
248                 void operator()(qi::unused_type, qi::unused_type, qi::unused_type) const
249                 {
250                         c.set_value(val);
251                 }
252         };
253
254         struct a_char
255         {
256                 pdf_context &c;
257                 explicit a_char(pdf_context& c) : c(c) {}
258
259                 void operator()(std::uint8_t n, qi::unused_type, qi::unused_type) const
260                 {
261                         c.add_char(n);
262                 }
263         };
264 };
265
266 bool read_pdf(boost::property_tree::wptree& tree, const std::string& s)
267 {
268         typedef std::string::const_iterator iterator_type;
269
270         pdf_grammar<iterator_type> g;
271         bool result = false;
272         
273         try
274         {
275                 auto it = s.begin();
276                 result = qi::phrase_parse(it, s.end(), g, qi::space);
277                 if(result)
278                         tree.swap(g.context.root);
279         }
280         catch(std::exception&)
281         {
282                 CASPAR_LOG_CURRENT_EXCEPTION();
283         }
284
285         return result;
286 }
287
288 }       //namespace psd
289 }       //namespace caspar