Use int64 in a few places.
[libdcp.git] / src / xml.cc
1 #include <sstream>
2 #include <iostream>
3 #include <boost/lexical_cast.hpp>
4 #include <libxml++/libxml++.h>
5 #include "xml.h"
6 #include "exceptions.h"
7 #include "util.h"
8
9 using namespace std;
10 using namespace boost;
11 using namespace libdcp;
12
13 XMLNode::XMLNode ()
14         : _node (0)
15 {
16
17 }
18
19 XMLNode::XMLNode (xmlpp::Node const * node)
20         : _node (node)
21 {
22         
23 }
24
25 xmlpp::Node *
26 XMLNode::xml_node (string name)
27 {
28         list<xmlpp::Node*> n = xml_nodes (name);
29         if (n.size() > 1) {
30                 throw XMLError ("duplicate XML tag " + name);
31         } else if (n.empty ()) {
32                 throw XMLError ("missing XML tag " + name);
33         }
34         
35         return n.front ();
36 }
37
38 list<xmlpp::Node*>
39 XMLNode::xml_nodes (string name)
40 {
41         /* XXX: using find / get_path should work here, but I can't follow
42            how get_path works.
43         */
44
45         xmlpp::Node::NodeList c = _node->get_children ();
46         
47         list<xmlpp::Node*> n;
48         for (xmlpp::Node::NodeList::iterator i = c.begin (); i != c.end(); ++i) {
49                 if ((*i)->get_name() == name) {
50                         n.push_back (*i);
51                 }
52         }
53         
54         _taken.push_back (name);
55         return n;
56 }
57
58 string
59 XMLNode::string_node (string name)
60 {
61         xmlpp::Node* node = xml_node (name);
62         
63         xmlpp::Node::NodeList c = node->get_children ();
64         if (c.size() != 1) {
65                 throw XMLError ("unexpected content in XML node");
66         }
67         
68         xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (c.front());
69         if (!v) {
70                 throw XMLError ("missing content in XML node");
71         }
72         
73         return v->get_content ();
74 }
75
76 string
77 XMLNode::optional_string_node (string name)
78 {
79         list<xmlpp::Node*> nodes = xml_nodes (name);
80         if (nodes.size() > 2) {
81                 throw XMLError ("duplicate XML tag " + name);
82         }
83
84         if (nodes.empty ()) {
85                 return "";
86         }
87
88         return string_node (name);
89 }
90
91 ContentKind
92 XMLNode::kind_node (string name)
93 {
94         return content_kind_from_string (string_node (name));
95 }
96
97 Fraction
98 XMLNode::fraction_node (string name)
99 {
100         return Fraction (string_node (name));
101 }
102
103 int64_t
104 XMLNode::int64_node (string name)
105 {
106         return lexical_cast<int64_t> (string_node (name));
107 }
108
109 void
110 XMLNode::ignore_node (string name)
111 {
112         _taken.push_back (name);
113 }
114
115 void
116 XMLNode::done ()
117 {
118         xmlpp::Node::NodeList c = _node->get_children ();
119         for (xmlpp::Node::NodeList::iterator i = c.begin(); i != c.end(); ++i) {
120                 if (dynamic_cast<xmlpp::Element *> (*i) && find (_taken.begin(), _taken.end(), (*i)->get_name()) == _taken.end ()) {
121                         throw XMLError ("unexpected XML node " + (*i)->get_name());
122                 }
123         }
124 }
125
126 XMLFile::XMLFile (string file, string root_name)
127 {
128         _parser = new xmlpp::DomParser;
129         _parser->parse_file (file);
130         if (!_parser) {
131                 throw XMLError ("could not parse XML");
132         }
133
134         _node = _parser->get_document()->get_root_node ();
135         if (_node->get_name() != root_name) {
136                 throw XMLError ("unrecognised root node");
137         }
138 }
139
140 XMLFile::~XMLFile ()
141 {
142         delete _parser;
143 }