diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-07-30 23:47:57 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-07-30 23:47:57 +0100 |
| commit | 9a9d4e014c16be88d72914a9480343445bc785a5 (patch) | |
| tree | 1857fcdd8963d51ac50f1467d9ae81d4d9be5f8e /src | |
| parent | 34a25d89b16a33b5f619ae0eaaa03c17f93980af (diff) | |
Various.
Diffstat (limited to 'src')
| -rw-r--r-- | src/asset_map.cc | 45 | ||||
| -rw-r--r-- | src/asset_map.h | 37 | ||||
| -rw-r--r-- | src/cpl.cc | 87 | ||||
| -rw-r--r-- | src/cpl.h | 85 | ||||
| -rw-r--r-- | src/dcp.cc | 147 | ||||
| -rw-r--r-- | src/dcp.h | 8 | ||||
| -rw-r--r-- | src/exceptions.h | 39 | ||||
| -rw-r--r-- | src/pkl.cc | 32 | ||||
| -rw-r--r-- | src/pkl.h | 41 | ||||
| -rw-r--r-- | src/types.cc | 20 | ||||
| -rw-r--r-- | src/types.h | 13 | ||||
| -rw-r--r-- | src/util.cc | 33 | ||||
| -rw-r--r-- | src/util.h | 4 | ||||
| -rw-r--r-- | src/wscript | 8 | ||||
| -rw-r--r-- | src/xml.cc | 151 | ||||
| -rw-r--r-- | src/xml.h | 78 |
16 files changed, 655 insertions, 173 deletions
diff --git a/src/asset_map.cc b/src/asset_map.cc new file mode 100644 index 00000000..b5e621d4 --- /dev/null +++ b/src/asset_map.cc @@ -0,0 +1,45 @@ +#include "asset_map.h" + +using namespace std; +using namespace libdcp; + +AssetMap::AssetMap (string file) + : XMLFile (file) +{ + id = string_node ("Id"); + creator = string_node ("Creator"); + volume_count = int_node ("VolumeCount"); + issue_date = string_node ("IssueDate"); + issuer = string_node ("Issuer"); + asset_list = sub_node<AssetList> ("AssetMapAssetList"); +} + +AssetMapAssetList::AssetMapAssetList (xmlpp::Node const * node) + : XMLNode (node) +{ + assets = sub_nodes<AssetMapAsset> ("Asset"); +} + +AssetMapAsset::AssetMapAsset (xmlpp::Node const * node) + : XMLNode (node) +{ + id = string_node ("Id"); + packing_list = optional_string_node ("PackingList"); + chunk_list = sub_node<ChunkList> ("ChunkList"); +} + +ChunkList::ChunkList (xmlpp::Node const * node) + : XMLNode (node) +{ + chunks = sub_nodes<Chunk> ("Chunk"); +} + +Chunk::Chunk (xmlpp::Node const * node) + : XMLNode (node) +{ + path = string_node ("Path"); + volume_index = int_node ("VolumeIndex"); + offset = int_node ("Offset"); + length = int_node ("Length"); +} + diff --git a/src/asset_map.h b/src/asset_map.h new file mode 100644 index 00000000..56370ab9 --- /dev/null +++ b/src/asset_map.h @@ -0,0 +1,37 @@ +#include <boost/shared_ptr.hpp> +#include "xml.h" + +namespace libdcp { + +class AssetMapAsset : public XMLNode +{ +public: + AssetMapAsset (); + AssetMapAsset (xmlpp::Node const * node); + + std::string id; + std::string packing_list; + boost::shared_ptr<ChunkList> +}; + +class AssetMapAssetList : public XMLNode +{ +public: + AssetMapAssetList (); + AssetMapAssetList (xmlpp::Node const * node); + + std::list<boost::shared_ptr<AssetMapAsset> > assets; +}; + +class AssetMap : public XMLFile +{ +public: + AssetMap (std::string file); + + std::string id; + std::string creator; + int volume_count; + std::string issue_date; + std::string issuer; + boost::shared_ptr<AssetMapAssetList> asset_list; +}; @@ -1,16 +1,81 @@ #include "cpl.h" +using namespace std; +using namespace libdcp; + CPL::CPL (string file) + : XMLFile (file, "CompositionPlaylist") +{ + id = string_node ("Id"); + annotation_text = string_node ("AnnotationText"); + issue_date = string_node ("IssueDate"); + creator = string_node ("Creator"); + content_title_text = string_node ("ContentTitleText"); + content_kind = kind_node ("ContentKind"); + content_version = sub_node<ContentVersion> ("ContentVersion"); + ignore_node ("RatingList"); + reel_list = sub_node<ReelList> ("ReelList"); + + done (); +} + +ContentVersion::ContentVersion (xmlpp::Node const * node) + : XMLNode (node) +{ + id = string_node ("Id"); + label_text = string_node ("LabelText"); + done (); +} + +ReelList::ReelList (xmlpp::Node const * node) + : XMLNode (node) +{ + reels = sub_nodes<Reel> ("Reel"); + done (); +} + +Reel::Reel (xmlpp::Node const * node) + : XMLNode (node) +{ + id = string_node ("Id"); + asset_list = sub_node<CPLAssetList> ("AssetList"); + + done (); +} + +CPLAssetList::CPLAssetList (xmlpp::Node const * node) + : XMLNode (node) +{ + main_picture = sub_node<MainPicture> ("MainPicture"); + main_sound = optional_sub_node<MainSound> ("MainSound"); + + done (); +} + +MainPicture::MainPicture (xmlpp::Node const * node) + : XMLNode (node) +{ + id = string_node ("Id"); + annotation_text = string_node ("AnnotationText"); + edit_rate = fraction_node ("EditRate"); + intrinsic_duration = int_node ("IntrinsicDuration"); + entry_point = int_node ("EntryPoint"); + duration = int_node ("Duration"); + frame_rate = fraction_node ("FrameRate"); + screen_aspect_ratio = fraction_node ("ScreenAspectRatio"); + + done (); +} + +MainSound::MainSound (xmlpp::Node const * node) + : XMLNode (node) { - file_is (file); - - _id = string_tag ("Id"); - _annotation_text = string_tag ("AnnotationText"); - _issue_date = string_tag ("IssueDate"); - _creator = string_tag ("Creator"); - _content_title_text = string_tag ("ContentTitleText"); - _content_kind = kind_tag ("ContentKind"); - _content_version = sub (new ContentVersion, "ContentVersion"); - ignore ("RatingList"); - _reel_list = sub (new ReelList, "ReelList"); + id = string_node ("Id"); + annotation_text = string_node ("AnnotationText"); + edit_rate = fraction_node ("EditRate"); + intrinsic_duration = int_node ("IntrinsicDuration"); + entry_point = int_node ("EntryPoint"); + duration = int_node ("Duration"); + + done (); } @@ -1,8 +1,91 @@ +#include <boost/shared_ptr.hpp> #include "xml.h" -class CPL : public XML +namespace libdcp { + +class MainPicture : public XMLNode +{ +public: + MainPicture () {} + MainPicture (xmlpp::Node const * node); + + std::string id; + std::string annotation_text; + Fraction edit_rate; + int intrinsic_duration; + int entry_point; + int duration; + Fraction frame_rate; + Fraction screen_aspect_ratio; +}; + +class MainSound : public XMLNode +{ +public: + MainSound () {} + MainSound (xmlpp::Node const * node); + + std::string id; + std::string annotation_text; + Fraction edit_rate; + int intrinsic_duration; + int entry_point; + int duration; +}; + +class CPLAssetList : public XMLNode +{ +public: + CPLAssetList () {} + CPLAssetList (xmlpp::Node const * node); + + boost::shared_ptr<MainPicture> main_picture; + boost::shared_ptr<MainSound> main_sound; +}; + +class Reel : public XMLNode +{ +public: + Reel () {} + Reel (xmlpp::Node const * node); + + std::string id; + boost::shared_ptr<CPLAssetList> asset_list; +}; + +class ReelList : public XMLNode +{ +public: + ReelList () {} + ReelList (xmlpp::Node const * node); + + std::list<boost::shared_ptr<Reel> > reels; +}; + +class ContentVersion : public XMLNode +{ +public: + ContentVersion () {} + ContentVersion (xmlpp::Node const * node); + + std::string id; + std::string label_text; +}; + +class CPL : public XMLFile { public: CPL (std::string file); + std::string id; + std::string annotation_text; + std::string issue_date; + std::string creator; + std::string content_title_text; + std::string content_kind; + boost::shared_ptr<ContentVersion> content_version; + boost::shared_ptr<ReelList> reel_list; }; + +} + @@ -32,15 +32,18 @@ #include "picture_asset.h" #include "util.h" #include "metadata.h" +#include "exceptions.h" +#include "cpl.h" +#include "pkl.h" using namespace std; using namespace boost; using namespace libdcp; -DCP::DCP (string directory, string name, ContentType content_type, int fps, int length) +DCP::DCP (string directory, string name, ContentKind content_kind, int fps, int length) : _directory (directory) , _name (name) - , _content_type (content_type) + , _content_kind (content_kind) , _fps (fps) , _length (length) { @@ -115,7 +118,7 @@ DCP::write_cpl (string cpl_uuid) const << " <IssueDate>" << Metadata::instance()->issue_date << "</IssueDate>\n" << " <Creator>" << Metadata::instance()->creator << "</Creator>\n" << " <ContentTitleText>" << _name << "</ContentTitleText>\n" - << " <ContentKind>" << content_type_string (_content_type) << "</ContentKind>\n" + << " <ContentKind>" << content_kind_to_string (_content_kind) << "</ContentKind>\n" << " <ContentVersion>\n" << " <Id>urn:uri:" << cpl_uuid << "_" << Metadata::instance()->issue_date << "</Id>\n" << " <LabelText>" << cpl_uuid << "_" << Metadata::instance()->issue_date << "</LabelText>\n" @@ -243,148 +246,34 @@ DCP::write_assetmap (string cpl_uuid, int cpl_length, string pkl_uuid, int pkl_l DCP::DCP (string directory) : _directory (directory) { - string cpl; - string pkl; - string asset_map; + string cpl_file; + string pkl_file; + string asset_map_file; for (filesystem::directory_iterator i = filesystem::directory_iterator(directory); i != filesystem::directory_iterator(); ++i) { - string const t = i->path()->string (); + string const t = i->path().string (); if (ends_with (t, "_cpl.xml")) { - if (cpl.empty ()) { - cpl = t; + if (cpl_file.empty ()) { + cpl_file = t; } else { throw DCPReadError ("duplicate CPLs found"); } } else if (ends_with (t, "_pkl.xml")) { - if (pkl.empty ()) { - pkl = t; + if (pkl_file.empty ()) { + pkl_file = t; } else { throw DCPReadError ("duplicate PKLs found"); } } else if (ends_with (t, "ASSETMAP.xml")) { - if (asset_map.empty ()) { - asset_map = t; + if (asset_map_file.empty ()) { + asset_map_file = t; } else { throw DCPReadError ("duplicate AssetMaps found"); } } } - load_cpl (cpl); - load_pkl (pkl); - load_asset_map (asset_map); + CPL cpl (cpl_file); + PKL pkl (pkl_file); } -void -DCP::load_cpl (string file) -{ - xmlpp::DOMParser parser; - parser.parser_file (file); - if (!parser) { - throw DCPReadError ("could not create parser for CPL"); - } - - xmlpp::Element* root = parser.get_document()->get_root_node (); - dcp_read_assert (root->get_name() == "CompositionPlaylist", "unrecognised CPL format"); - - xmlpp::Node::NodeList children = root->get_children (); - for (xmlpp::Node::NodeList::iterator i = children.begin(); i != children.end(); ++i) { - bool taken = false; - xml_maybe (*i, taken, _cpl_id, "Id"); - xml_maybe (*i, taken, _annotation_text, "AnnotationText"); - xml_maybe (*i, taken, _issue_date, "IssueDate"); - xml_maybe (*i, taken, _creator, "Creator"); - xml_maybe (*i, taken, _content_title_text, "ContentTitleText"); - xml_maybe (*i, taken, _content_kind, "ContentKind"); - - if ((*i)->get_name() == "ContentVersion") { - taken = true; - load_cpl_content_version (*i); - } - - if ((*i)->get_name() == "RatingList") { - taken = true; - } - - if ((*i)->get_name() == "ReelList") { - taken = true; - load_cpl_reel_list (*i); - } - - xml_assert_taken (*i, taken); - } -} - -void -DCP::load_cpl_content_version (xmlpp::Node const * node) -{ - xmlpp::Node::NodeList children = node->get_children (); - for (xmlpp::Node::NodeList::iterator i = children.begin(); i != children.end(); ++i) { - bool taken = false; - xml_maybe (*i, taken, _content_version_id, "Id"); - xml_maybe (*i, taken, _content_version_label_text, "LabelText"); - xml_assert_taken (*i, taken); - } -} - -void -DCP::load_cpl_reel_list (xmlpp::Node const * node) -{ - xmlpp::Node::NodeList children = node->get_children (); - bool had_reel = false; - for (xmlpp::Node::NodeList::iterator i = children.begin(); i != children.end(); ++i) { - bool taken = false; - if ((*i)->get_name() == "Reel") { - if (!had_reel) { - load_cpl_reel (*i); - had_reel = true; - } else { - throw DCPReadError ("multiple reels not supported"); - } - } - xml_assert_taken (*i, taken); - } -} - -void -DCP::load_cpl_reel (xmlpp::Node const * node) -{ - xmlpp::Node::NodeList children = node->get_children (); - for (xmlpp::Node::NodeList::iterator i = children.begin(); i != children.end(); ++i) { - bool taken = false; - xml_taken (*i, taken, _reel_id, "Id"); - if ((*i)->name() == "AssetList") { - taken = true; - load_cpl_asset_list (*i); - } - xml_assert_taken (*i, taken); - } -} - -void -DCP::load_cpl_asset_list (xmlpp::Node const * node) -{ - xmlpp::Node::NodeList children = node->get_children (); - for (xmlpp::Node::NodeList::iterator i = children.begin(); i != children.end(); ++i) { - bool taken = false; - if ((*i)->name() == "MainPicture") { - taken = true; - load_cpl_main_picture (*i); - } else if ((*i)->name() == "MainSound") { - taken = true; - load_cpl_main_sound (*i); - } - xml_assert_taken (*i, taken); - } -} - -void -DCP::load_cpl_main_picture (xmlpp::Node const * node) -{ - xmlpp::Node::NodeList children = node->get_children (); - for (xmlpp::Node::NodeList::iterator i = children.begin(); i != children.end(); ++i) { - bool taken = false; - xml_maybe (*i, taken, _video_id, "Id"); - - } -} @@ -50,11 +50,11 @@ public: /** Construct a DCP. * @param directory Directory to write files to. * @param name Name. - * @param content_type Content type. + * @param content_kind Content kind. * @param fps Frames per second. * @param length Length in frames. */ - DCP (std::string directory, std::string name, ContentType content_type, int fps, int length); + DCP (std::string directory, std::string name, ContentKind content_kind, int fps, int length); DCP (std::string directory); @@ -126,8 +126,8 @@ private: std::string _directory; /** the name of the DCP */ std::string _name; - /** the content type of the DCP */ - ContentType _content_type; + /** the content kind of the DCP */ + ContentKind _content_kind; /** frames per second */ int _fps; /** length in frames */ diff --git a/src/exceptions.h b/src/exceptions.h index 7443db15..cd3c5cdb 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -17,6 +17,9 @@ */ +#ifndef LIBDCP_EXCEPTIONS_H +#define LIBDCP_EXCEPTIONS_H + /** @file src/exceptions.h * @brief Exceptions thrown by libdcp. */ @@ -70,4 +73,40 @@ private: std::string _message; }; +/** @brief A DCP read exception */ +class DCPReadError : public std::exception +{ +public: + DCPReadError (std::string const & message) : _message (message) {} + ~DCPReadError () throw () {} + + /** @return error message */ + char const * what () const throw () { + return _message.c_str (); + } + +private: + /** error message */ + std::string _message; +}; + +/** @brief An XML error */ +class XMLError : public std::exception +{ +public: + XMLError (std::string const & message) : _message (message) {} + ~XMLError () throw () {} + + /** @return error message */ + char const * what () const throw () { + return _message.c_str (); + } + +private: + /** error message */ + std::string _message; +}; + } + +#endif diff --git a/src/pkl.cc b/src/pkl.cc new file mode 100644 index 00000000..b41fc185 --- /dev/null +++ b/src/pkl.cc @@ -0,0 +1,32 @@ +#include "pkl.h" + +using namespace std; +using namespace libdcp; + +PKL::PKL (string file) + : XMLFile (file, "PackingList") +{ + id = string_node ("Id"); + annotation_text = string_node ("AnnotationText"); + issue_date = string_node ("IssueDate"); + issuer = string_node ("Issuer"); + creator = string_node ("Creator"); + asset_list = sub_node<PKLAssetList> ("AssetList"); +} + +PKLAssetList::PKLAssetList (xmlpp::Node const * node) + : XMLNode (node) +{ + assets = sub_nodes<PKLAsset> ("Asset"); +} + +PKLAsset::PKLAsset (xmlpp::Node const * node) + : XMLNode (node) +{ + id = string_node ("Id"); + annotation_text = optional_string_node ("AnnotationText"); + hash = string_node ("Hash"); + size = int_node ("Size"); + type = string_node ("Type"); +} + diff --git a/src/pkl.h b/src/pkl.h new file mode 100644 index 00000000..ab6c7a60 --- /dev/null +++ b/src/pkl.h @@ -0,0 +1,41 @@ +#include <boost/shared_ptr.hpp> +#include "xml.h" + +namespace libdcp { + +class PKLAsset : public XMLNode +{ +public: + PKLAsset () {} + PKLAsset (xmlpp::Node const * node); + + std::string id; + std::string annotation_text; + std::string hash; + int size; + std::string type; +}; + +class PKLAssetList : public XMLNode +{ +public: + PKLAssetList (); + PKLAssetList (xmlpp::Node const * node); + + std::list<boost::shared_ptr<PKLAsset> > assets; +}; + +class PKL : public XMLFile +{ +public: + PKL (std::string file); + + std::string id; + std::string annotation_text; + std::string issue_date; + std::string issuer; + std::string creator; + boost::shared_ptr<PKLAssetList> asset_list; +}; + +} diff --git a/src/types.cc b/src/types.cc new file mode 100644 index 00000000..85c5fd6e --- /dev/null +++ b/src/types.cc @@ -0,0 +1,20 @@ +#include <vector> +#include <boost/lexical_cast.hpp> +#include <boost/algorithm/string.hpp> +#include "types.h" +#include "exceptions.h" + +using namespace std; +using namespace libdcp; +using namespace boost; + +Fraction::Fraction (string s) +{ + vector<string> b; + split (b, s, is_any_of (" ")); + if (b.size() != 2) { + throw XMLError ("malformed fraction " + s + " in XML node"); + } + numerator = lexical_cast<int> (b[0]); + denominator = lexical_cast<int> (b[1]); +} diff --git a/src/types.h b/src/types.h index 63f52f3e..b8f7805a 100644 --- a/src/types.h +++ b/src/types.h @@ -37,7 +37,7 @@ enum Channel { RS = 5 ///< right surround }; -enum ContentType +enum ContentKind { FEATURE, SHORT, @@ -51,6 +51,17 @@ enum ContentType ADVERTISEMENT }; +class Fraction +{ +public: + Fraction () : numerator (0), denominator (0) {} + Fraction (std::string s); + Fraction (int n, int d) : numerator (n), denominator (d) {} + + int numerator; + int denominator; +}; + } #endif diff --git a/src/util.cc b/src/util.cc index 9b650fa4..7138a075 100644 --- a/src/util.cc +++ b/src/util.cc @@ -32,6 +32,7 @@ #include "AS_DCP.h" #include "util.h" #include "exceptions.h" +#include "types.h" using namespace std; using namespace boost; @@ -88,9 +89,9 @@ libdcp::make_digest (string filename, sigc::signal1<void, float>* progress) } string -libdcp::content_type_to_string (ContentType type) +libdcp::content_kind_to_string (ContentKind kind) { - switch (type) { + switch (kind) { case FEATURE: return "feature"; case SHORT: @@ -115,6 +116,34 @@ libdcp::content_type_to_string (ContentType type) assert (false); } + +libdcp::ContentKind +libdcp::content_kind_from_string (string type) +{ + if (type == "feature") { + return FEATURE; + } else if (type == "short") { + return SHORT; + } else if (type == "trailer") { + return TRAILER; + } else if (type == "test") { + return TEST; + } else if (type == "transitional") { + return TRANSITIONAL; + } else if (type == "rating") { + return RATING; + } else if (type == "teaser") { + return TEASER; + } else if (type == "policy") { + return POLICY; + } else if (type == "psa") { + return PUBLIC_SERVICE_ANNOUNCEMENT; + } else if (type == "advertisement") { + return ADVERTISEMENT; + } + + assert (false); +} bool libdcp::ends_with (string big, string little) @@ -23,6 +23,7 @@ #include <string> #include <sigc++/sigc++.h> +#include "types.h" namespace libdcp { @@ -39,7 +40,8 @@ extern std::string make_uuid (); */ extern std::string make_digest (std::string filename, sigc::signal1<void, float>* progress); -extern std::string content_type_to_string (ContentType type); +extern std::string content_kind_to_string (ContentKind kind); +extern ContentKind content_kind_from_string (std::string kind); extern bool ends_with (std::string big, std::string little); } diff --git a/src/wscript b/src/wscript index 58390837..1505edcc 100644 --- a/src/wscript +++ b/src/wscript @@ -3,17 +3,21 @@ def build(bld): obj.name = 'libdcp' obj.target = 'dcp' obj.export_includes = ['.'] - obj.uselib = 'BOOST_FILESYSTEM OPENSSL SIGC++' + obj.uselib = 'BOOST_FILESYSTEM OPENSSL SIGC++ LIBXML++' obj.use = 'libkumu-libdcp libasdcp-libdcp' obj.source = """ - dcp.cc + cpl.cc + dcp.cc asset.cc sound_asset.cc picture_asset.cc + pkl.cc util.cc metadata.cc version.cc test_mode.cc + types.cc + xml.cc """ headers = """ @@ -1,34 +1,145 @@ +#include <sstream> +#include <iostream> +#include <boost/lexical_cast.hpp> +#include <libxml++/libxml++.h> #include "xml.h" +#include "exceptions.h" +#include "util.h" -XMLFile::XMLFile (string file, string root_id) +using namespace std; +using namespace boost; +using namespace libdcp; + +XMLNode::XMLNode () + : _node (0) { - xmlpp::DomParser parser; - parser.parse_file (file); - if (!parser) { - throw XMLError ("could not parse XML"); + +} + +XMLNode::XMLNode (xmlpp::Node const * node) + : _node (node) +{ + +} + +xmlpp::Node * +XMLNode::xml_node (string name) +{ + list<xmlpp::Node*> n = xml_nodes (name); + if (n.size() > 1) { + throw XMLError ("duplicate XML tag " + name); + } else if (n.empty ()) { + throw XMLError ("missing XML tag " + name); } + + return n.front (); +} - _root = parser.get_document()->get_root_node (); - if (_root->get_name() != root_id) { - throw XMLError ("unrecognised root node"); +list<xmlpp::Node*> +XMLNode::xml_nodes (string name) +{ + /* XXX: using find / get_path should work here, but I can't follow + how get_path works. + */ + + xmlpp::Node::NodeList c = _node->get_children (); + + list<xmlpp::Node*> n; + for (xmlpp::Node::NodeList::iterator i = c.begin (); i != c.end(); ++i) { + if ((*i)->get_name() == name) { + n.push_back (*i); + } + } + + _taken.push_back (name); + return n; +} + +string +XMLNode::string_node (string name) +{ + xmlpp::Node* node = xml_node (name); + + xmlpp::Node::NodeList c = node->get_children (); + if (c.size() != 1) { + throw XMLError ("unexpected content in XML node"); } + + xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (c.front()); + if (!v) { + throw XMLError ("missing content in XML node"); + } + + return v->get_content (); } string -XMLFile::string_tag (string id) +XMLNode::optional_string_node (string name) +{ + list<xmlpp::Node*> nodes = xml_nodes (name); + if (nodes.size() > 2) { + throw XMLError ("duplicate XML tag " + name); + } + + if (nodes.empty ()) { + return ""; + } + + return string_node (name); +} + +ContentKind +XMLNode::kind_node (string name) +{ + return content_kind_from_string (string_node (name)); +} + +Fraction +XMLNode::fraction_node (string name) +{ + return Fraction (string_node (name)); +} + +int +XMLNode::int_node (string name) +{ + return lexical_cast<int> (string_node (name)); +} + +void +XMLNode::ignore_node (string name) +{ + _taken.push_back (name); +} + +void +XMLNode::done () +{ + xmlpp::Node::NodeList c = _node->get_children (); + for (xmlpp::Node::NodeList::iterator i = c.begin(); i != c.end(); ++i) { + if (dynamic_cast<xmlpp::Element *> (*i) && find (_taken.begin(), _taken.end(), (*i)->get_name()) == _taken.end ()) { + throw XMLError ("unexpected XML node " + (*i)->get_name()); + } + } +} + +XMLFile::XMLFile (string file, string root_name) { - stringstream x; - x << _root->get_name() << "/" << id; - xmlpp::NodeSet n = _root->find (x.str ()); - if (n.empty ()) { - throw XMLError ("missing XML tag"); - } else if (n.size() > 1) { - throw XMLError ("duplicate XML tag"); + _parser = new xmlpp::DomParser; + _parser->parse_file (file); + if (!_parser) { + throw XMLError ("could not parse XML"); + } + + _node = _parser->get_document()->get_root_node (); + if (_node->get_name() != root_name) { + throw XMLError ("unrecognised root node"); } - xml::Node::NodeList c = n.front()->get_children (); - if (c.empty() - + cout << this << " root node is " << _node->get_name() << "\n"; +} - return n.front()->get_name (); +XMLFile::~XMLFile () +{ + delete _parser; } @@ -1,6 +1,80 @@ +#ifndef LIBDCP_XML_H +#define LIBDCP_XML_H -class XMLFile +#include <string> +#include <list> +#include <glibmm.h> +#include <boost/shared_ptr.hpp> +#include "types.h" +#include "exceptions.h" + +namespace xmlpp { + class Node; + class DomParser; +} + +namespace libdcp { + +class XMLNode { public: - XMLFile (std::string file); + XMLNode (); + XMLNode (xmlpp::Node const * node); + +protected: + std::string string_node (std::string); + std::string optional_string_node (std::string); + ContentKind kind_node (std::string); + Fraction fraction_node (std::string); + int int_node (std::string); + void ignore_node (std::string); + void done (); + + template <class T> + boost::shared_ptr<T> sub_node (std::string name) { + return boost::shared_ptr<T> (new T (xml_node (name))); + } + + template <class T> + boost::shared_ptr<T> optional_sub_node (std::string name) { + std::list<xmlpp::Node*> n = xml_nodes (name); + if (n.size() > 1) { + throw XMLError ("duplicate XML tag"); + } else if (n.empty ()) { + return boost::shared_ptr<T> (); + } + + return boost::shared_ptr<T> (new T (n.front ())); + } + + template <class T> + std::list<boost::shared_ptr<T> > sub_nodes (std::string name) { + std::list<xmlpp::Node*> n = xml_nodes (name); + std::list<boost::shared_ptr<T> > r; + for (typename std::list<xmlpp::Node*>::iterator i = n.begin(); i != n.end(); ++i) { + r.push_back (boost::shared_ptr<T> (new T (*i))); + } + return r; + } + + xmlpp::Node const * _node; + +private: + xmlpp::Node* xml_node (std::string); + std::list<xmlpp::Node*> xml_nodes (std::string); + std::list<Glib::ustring> _taken; }; + +class XMLFile : public XMLNode +{ +public: + XMLFile (std::string file, std::string root_name); + virtual ~XMLFile (); + +private: + xmlpp::DomParser* _parser; +}; + +} + +#endif |
