Various.
authorCarl Hetherington <cth@carlh.net>
Mon, 30 Jul 2012 22:47:57 +0000 (23:47 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 30 Jul 2012 22:47:57 +0000 (23:47 +0100)
21 files changed:
run/dcpdiff [new file with mode: 0755]
src/asset_map.cc [new file with mode: 0644]
src/asset_map.h [new file with mode: 0644]
src/cpl.cc
src/cpl.h
src/dcp.cc
src/dcp.h
src/exceptions.h
src/pkl.cc [new file with mode: 0644]
src/pkl.h [new file with mode: 0644]
src/types.cc [new file with mode: 0644]
src/types.h
src/util.cc
src/util.h
src/wscript
src/xml.cc
src/xml.h
test/tests.cc
tools/dcpdiff.cc [new file with mode: 0644]
tools/wscript [new file with mode: 0644]
wscript

diff --git a/run/dcpdiff b/run/dcpdiff
new file mode 100755 (executable)
index 0000000..1799938
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+export LD_LIBRARY_PATH=build/src
+if [ "$1" == "--debug" ]; then
+    gdb --args build/tools/dcpdiff "$@"
+elif [ "$1" == "--valgrind" ]; then
+    valgrind --tool="memcheck" --leak-check=full --show-reachable=yes build/tools/dcpdiff "$@"
+else
+    build/tools/dcpdiff "$@"
+fi
diff --git a/src/asset_map.cc b/src/asset_map.cc
new file mode 100644 (file)
index 0000000..b5e621d
--- /dev/null
@@ -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 (file)
index 0000000..56370ab
--- /dev/null
@@ -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;
+};
index 1eba666c4f92669e981ba305fc554c154c978516..99d5b411d901fb3477e093af22db2e3c98f75a46 100644 (file)
@@ -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 ();
 }
index 6ec55e619a4ad46b15aef1e693246e53087c6d56..643a243beec84f9250471da025b963d2539b8271 100644 (file)
--- a/src/cpl.h
+++ b/src/cpl.h
@@ -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;
 };
+
+}
+
index 8c74ea8e593e3ba2f4e1597249622a6e6e65f249..27f3243eccb0c09022507f0990a65ace49e455f3 100644 (file)
 #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");
-               
-       }
-}
index 9407c9c79320bee3c42c8210de0bec83d27b0928..8c13c50502cde71d4fbc4e80f4095add858a3cce 100644 (file)
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -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 */
index 7443db151184a2564a51be25858d88f3f4d4c96d..cd3c5cdb9b79a92e9fa8f13e7849e238ffeb74fe 100644 (file)
@@ -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 (file)
index 0000000..b41fc18
--- /dev/null
@@ -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 (file)
index 0000000..ab6c7a6
--- /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 (file)
index 0000000..85c5fd6
--- /dev/null
@@ -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]);
+}
index 63f52f3e7e8e127f14dbd77f3bdd1ef9fd362859..b8f7805a4111b97223bedd8ddc1bfac3d5958ad7 100644 (file)
@@ -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
index 9b650fa459fcb3f3c704e815867afb9a5968656d..7138a075db5e29ab401a16fba7e631cc2ce0821f 100644 (file)
@@ -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)
index f4c7d2866845bc54af31549d18ce5c2f54af3377..ac13e9f6120e88b69019428666e88816bb9f54e0 100644 (file)
@@ -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);
        
 }
index 58390837e7b370415eefbd31ecdd0308095f9194..1505edcc80b52e15662f2e635f3e3f82e76a0a16 100644 (file)
@@ -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 = """
index 3863bdff335e3e42947a5705a0ddf9b688fdd923..9386906bd45fe662755cef6cc3f230779b5a9a48 100644 (file)
+#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;
 }
index 5cfa49477c1ab6c78b3f9cd1690b5b0a884819ab..ff4b1e67cf8c3bab4b35e29021fa9a596122cd81 100644 (file)
--- a/src/xml.h
+++ b/src/xml.h
@@ -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
index bbd877bad78561ca4827cebe352edeaf26d22a95..7e470f3e3c5b3d40a955e1828de5cf5dcc03581a 100644 (file)
@@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE (dcp_test)
        t->issue_date = "2012-07-17T04:45:18+00:00";
        filesystem::remove_all ("build/test/foo");
        filesystem::create_directories ("build/test/foo");
-       libdcp::DCP d ("build/test/foo", "A Test DCP", libdcp::DCP::FEATURE, 24, 24);
+       libdcp::DCP d ("build/test/foo", "A Test DCP", libdcp::FEATURE, 24, 24);
 
        d.add_picture_asset (sigc::ptr_fun (&j2c), 32, 32);
        d.add_sound_asset (sigc::ptr_fun (&wav), 2);
@@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE (dcp_test)
 
 BOOST_AUTO_TEST_CASE (error_test)
 {
-       libdcp::DCP d ("build/test/bar", "A Test DCP", libdcp::DCP::TEST, 24, 24);
+       libdcp::DCP d ("build/test/bar", "A Test DCP", libdcp::TEST, 24, 24);
        vector<string> p;
        p.push_back ("frobozz");
        BOOST_CHECK_THROW (d.add_picture_asset (p, 32, 32), libdcp::FileError);
diff --git a/tools/dcpdiff.cc b/tools/dcpdiff.cc
new file mode 100644 (file)
index 0000000..b503ee1
--- /dev/null
@@ -0,0 +1,10 @@
+#include "dcp.h"
+
+using namespace libdcp;
+
+int
+main (int argc, char* argv[])
+{
+       DCP dcp ("/home/carl/src/dvdomatic-test/reference/dolby_aurora.vob/dolby_aurora.vob");
+       return 0;
+}
diff --git a/tools/wscript b/tools/wscript
new file mode 100644 (file)
index 0000000..665d44b
--- /dev/null
@@ -0,0 +1,5 @@
+def build(bld):
+    obj = bld(features = 'cxx cxxprogram')
+    obj.use = ['libdcp']
+    obj.source = 'dcpdiff.cc'
+    obj.target = 'dcpdiff'
diff --git a/wscript b/wscript
index f4e2c3ebe6257dc6c32be8c7335028910b338eac..83ba8218f7d202128c0b45a00d78f5996ef90eac 100644 (file)
--- a/wscript
+++ b/wscript
@@ -7,6 +7,7 @@ VERSION = '0.05'
 def options(opt):
     opt.load('compiler_cxx')
     opt.add_option('--target-windows', action='store_true', default = False, help = 'set up to do a cross-compile to Windows')
+    opt.add_option('--enable-debug', action='store_true', default = False, help = 'build with debugging information and without optimisation')
 
 def configure(conf):
     conf.load('compiler_cxx')
@@ -20,12 +21,18 @@ def configure(conf):
 
     conf.check_cfg(package = 'openssl', args = '--cflags --libs', uselib_store = 'OPENSSL', mandatory = True)
     conf.check_cfg(package = 'sigc++-2.0', args = '--cflags --libs', uselib_store = 'SIGC++', mandatory = True)
+    conf.check_cfg(package = 'libxml++-2.6', args = '--cflags --libs', uselib_store = 'LIBXML++', mandatory = True)
 
     if conf.options.target_windows:
         boost_lib_suffix = '-mt'
     else:
         boost_lib_suffix = ''
-    
+
+    if conf.options.enable_debug:
+        conf.env.append_value('CXXFLAGS', '-g')
+    else:
+        conf.env.append_value('CXXFLAGS', '-O3')
+
     conf.check_cxx(fragment = """
                              #include <boost/filesystem.hpp>\n
                              int main() { boost::filesystem::copy_file ("a", "b"); }\n
@@ -48,6 +55,7 @@ def build(bld):
         install_path = '${LIBDIR}/pkgconfig')
 
     bld.recurse('src')
+    bld.recurse('tools')
     bld.recurse('test')
     bld.recurse('asdcplib')