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