diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/asset.cc | 37 | ||||
| -rw-r--r-- | src/asset.h | 7 | ||||
| -rw-r--r-- | src/cpl.cc | 95 | ||||
| -rw-r--r-- | src/cpl.h | 12 | ||||
| -rw-r--r-- | src/cpl_file.cc | 148 | ||||
| -rw-r--r-- | src/dcp.cc | 109 | ||||
| -rw-r--r-- | src/dcp.h | 1 | ||||
| -rw-r--r-- | src/parse/asset_map.cc (renamed from src/asset_map.cc) | 40 | ||||
| -rw-r--r-- | src/parse/asset_map.h (renamed from src/asset_map.h) | 16 | ||||
| -rw-r--r-- | src/parse/cpl.cc | 147 | ||||
| -rw-r--r-- | src/parse/cpl.h (renamed from src/cpl_file.h) | 49 | ||||
| -rw-r--r-- | src/parse/pkl.cc (renamed from src/pkl_file.cc) | 36 | ||||
| -rw-r--r-- | src/parse/pkl.h (renamed from src/pkl_file.h) | 16 | ||||
| -rw-r--r-- | src/parse/subtitle.cc | 135 | ||||
| -rw-r--r-- | src/parse/subtitle.h | 93 | ||||
| -rw-r--r-- | src/picture_asset.cc | 21 | ||||
| -rw-r--r-- | src/picture_asset.h | 6 | ||||
| -rw-r--r-- | src/reel.cc | 17 | ||||
| -rw-r--r-- | src/reel.h | 3 | ||||
| -rw-r--r-- | src/sound_asset.cc | 17 | ||||
| -rw-r--r-- | src/sound_asset.h | 6 | ||||
| -rw-r--r-- | src/subtitle_asset.cc | 252 | ||||
| -rw-r--r-- | src/subtitle_asset.h | 83 | ||||
| -rw-r--r-- | src/types.h | 2 | ||||
| -rw-r--r-- | src/wscript | 16 | ||||
| -rw-r--r-- | src/xml.cc | 263 | ||||
| -rw-r--r-- | src/xml.h | 156 |
27 files changed, 783 insertions, 1000 deletions
diff --git a/src/asset.cc b/src/asset.cc index 58c821a7..84bdd2bd 100644 --- a/src/asset.cc +++ b/src/asset.cc @@ -25,6 +25,7 @@ #include <fstream> #include <boost/filesystem.hpp> #include <boost/function.hpp> +#include <boost/lexical_cast.hpp> #include "AS_DCP.h" #include "KM_util.h" #include "asset.h" @@ -50,31 +51,27 @@ Asset::Asset (string directory, string file_name, int edit_rate, int intrinsic_d } void -Asset::write_to_pkl (ostream& s) const +Asset::write_to_pkl (xmlpp::Node* node) const { - s << " <Asset>\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <AnnotationText>" << _file_name << "</AnnotationText>\n" - << " <Hash>" << digest() << "</Hash>\n" - << " <Size>" << filesystem::file_size(path()) << "</Size>\n" - << " <Type>application/mxf</Type>\n" - << " </Asset>\n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + asset->add_child("AnnotationText")->add_child_text (_file_name); + asset->add_child("Hash")->add_child_text (digest ()); + asset->add_child("Size")->add_child_text (lexical_cast<string> (filesystem::file_size(path()))); + asset->add_child("Type")->add_child_text ("application/mxf"); } void -Asset::write_to_assetmap (ostream& s) const +Asset::write_to_assetmap (xmlpp::Node* node) const { - s << " <Asset>\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <ChunkList>\n" - << " <Chunk>\n" - << " <Path>" << _file_name << "</Path>\n" - << " <VolumeIndex>1</VolumeIndex>\n" - << " <Offset>0</Offset>\n" - << " <Length>" << filesystem::file_size(path()) << "</Length>\n" - << " </Chunk>\n" - << " </ChunkList>\n" - << " </Asset>\n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + xmlpp::Node* chunk_list = asset->add_child ("ChunkList"); + xmlpp::Node* chunk = chunk_list->add_child ("Chunk"); + chunk->add_child("Path")->add_child_text (_file_name); + chunk->add_child("VolumeIndex")->add_child_text ("1"); + chunk->add_child("Offset")->add_child_text ("0"); + chunk->add_child("Length")->add_child_text (lexical_cast<string> (filesystem::file_size(path()))); } filesystem::path diff --git a/src/asset.h b/src/asset.h index 06c66356..3bc713a3 100644 --- a/src/asset.h +++ b/src/asset.h @@ -28,6 +28,7 @@ #include <list> #include <boost/filesystem.hpp> #include <boost/function.hpp> +#include <libxml++/libxml++.h> #include "types.h" namespace ASDCP { @@ -55,17 +56,17 @@ public: /** Write details of the asset to a CPL stream. * @param s Stream. */ - virtual void write_to_cpl (std::ostream& s) const = 0; + virtual void write_to_cpl (xmlpp::Node *) const = 0; /** Write details of the asset to a PKL stream. * @param s Stream. */ - void write_to_pkl (std::ostream& s) const; + void write_to_pkl (xmlpp::Node *) const; /** Write details of the asset to a ASSETMAP stream. * @param s Stream. */ - void write_to_assetmap (std::ostream& s) const; + void write_to_assetmap (xmlpp::Node *) const; std::string uuid () const { return _uuid; @@ -19,12 +19,12 @@ #include <fstream> #include "cpl.h" -#include "cpl_file.h" +#include "parse/cpl.h" #include "util.h" #include "picture_asset.h" #include "sound_asset.h" #include "subtitle_asset.h" -#include "asset_map.h" +#include "parse/asset_map.h" #include "reel.h" #include "metadata.h" @@ -34,6 +34,7 @@ using std::ofstream; using std::ostream; using std::list; using boost::shared_ptr; +using boost::lexical_cast; using namespace libdcp; CPL::CPL (string directory, string name, ContentKind content_kind, int length, int frames_per_second) @@ -52,16 +53,16 @@ CPL::CPL (string directory, string name, ContentKind content_kind, int length, i * @param asset_map The corresponding asset map. * @param require_mxfs true to throw an exception if a required MXF file does not exist. */ -CPL::CPL (string directory, string file, shared_ptr<const AssetMap> asset_map, bool require_mxfs) +CPL::CPL (string directory, string file, shared_ptr<const libdcp::parse::AssetMap> asset_map, bool require_mxfs) : _directory (directory) , _content_kind (FEATURE) , _length (0) , _fps (0) { /* Read the XML */ - shared_ptr<CPLFile> cpl; + shared_ptr<parse::CPL> cpl; try { - cpl.reset (new CPLFile (file)); + cpl.reset (new parse::CPL (file)); } catch (FileError& e) { boost::throw_exception (FileError ("could not load CPL file", file)); } @@ -71,9 +72,9 @@ CPL::CPL (string directory, string file, shared_ptr<const AssetMap> asset_map, b _name = cpl->annotation_text; _content_kind = cpl->content_kind; - for (list<shared_ptr<CPLReel> >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) { + for (list<shared_ptr<libdcp::parse::Reel> >::iterator i = cpl->reels.begin(); i != cpl->reels.end(); ++i) { - shared_ptr<Picture> p; + shared_ptr<parse::Picture> p; if ((*i)->asset_list->main_picture) { p = (*i)->asset_list->main_picture; @@ -180,45 +181,42 @@ CPL::write_xml (XMLMetadata const & metadata) const stringstream s; s << _uuid << "_cpl.xml"; p /= s.str(); - ofstream os (p.string().c_str()); - - os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - << "<CompositionPlaylist xmlns=\"http://www.smpte-ra.org/schemas/429-7/2006/CPL\">\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <AnnotationText>" << _name << "</AnnotationText>\n" - << " <IssueDate>" << metadata.issue_date << "</IssueDate>\n" - << " <Creator>" << metadata.creator << "</Creator>\n" - << " <ContentTitleText>" << _name << "</ContentTitleText>\n" - << " <ContentKind>" << content_kind_to_string (_content_kind) << "</ContentKind>\n" - << " <ContentVersion>\n" - << " <Id>urn:uri:" << _uuid << "_" << metadata.issue_date << "</Id>\n" - << " <LabelText>" << _uuid << "_" << metadata.issue_date << "</LabelText>\n" - << " </ContentVersion>\n" - << " <RatingList/>\n" - << " <ReelList>\n"; + + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("CompositionPlaylist", "http://www.smpte-ra.org/schemas/429-7/2006/CPL"); + root->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + root->add_child("AnnotationText")->add_child_text (_name); + root->add_child("IssueDate")->add_child_text (metadata.issue_date); + root->add_child("Creator")->add_child_text (metadata.creator); + root->add_child("ContentTitleText")->add_child_text (_name); + root->add_child("ContentKind")->add_child_text (content_kind_to_string (_content_kind)); + { + xmlpp::Node* cv = root->add_child ("ContentVersion"); + cv->add_child ("Id")->add_child_text ("urn:uri:" + _uuid + "_" + metadata.issue_date); + cv->add_child ("LabelText")->add_child_text (_uuid + "_" + metadata.issue_date); + } + root->add_child("RatingList"); + + xmlpp::Node* reel_list = root->add_child ("ReelList"); for (list<shared_ptr<const Reel> >::const_iterator i = _reels.begin(); i != _reels.end(); ++i) { - (*i)->write_to_cpl (os); + (*i)->write_to_cpl (reel_list); } - os << " </ReelList>\n" - << "</CompositionPlaylist>\n"; - - os.close (); + doc.write_to_file_formatted (p.string (), "UTF-8"); _digest = make_digest (p.string ()); _length = boost::filesystem::file_size (p.string ()); } void -CPL::write_to_pkl (ostream& s) const +CPL::write_to_pkl (xmlpp::Node* node) const { - s << " <Asset>\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <Hash>" << _digest << "</Hash>\n" - << " <Size>" << _length << "</Size>\n" - << " <Type>text/xml</Type>\n" - << " </Asset>\n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + asset->add_child("Hash")->add_child_text (_digest); + asset->add_child("Size")->add_child_text (lexical_cast<string> (_length)); + asset->add_child("Type")->add_child_text ("text/xml"); } list<shared_ptr<const Asset> > @@ -241,19 +239,16 @@ CPL::assets () const } void -CPL::write_to_assetmap (ostream& s) const +CPL::write_to_assetmap (xmlpp::Node* node) const { - s << " <Asset>\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <ChunkList>\n" - << " <Chunk>\n" - << " <Path>" << _uuid << "_cpl.xml</Path>\n" - << " <VolumeIndex>1</VolumeIndex>\n" - << " <Offset>0</Offset>\n" - << " <Length>" << _length << "</Length>\n" - << " </Chunk>\n" - << " </ChunkList>\n" - << " </Asset>\n"; + xmlpp::Node* asset = node->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + _uuid); + xmlpp::Node* chunk_list = asset->add_child ("ChunkList"); + xmlpp::Node* chunk = chunk_list->add_child ("Chunk"); + chunk->add_child("Path")->add_child_text (_uuid + "_cpl.xml"); + chunk->add_child("VolumeIndex")->add_child_text ("1"); + chunk->add_child("Offset")->add_child_text("0"); + chunk->add_child("Length")->add_child_text(lexical_cast<string> (_length)); } @@ -261,8 +256,10 @@ CPL::write_to_assetmap (ostream& s) const bool CPL::equals (CPL const & other, EqualityOptions opt, boost::function<void (NoteType, string)> note) const { - if (_name != other._name) { - note (ERROR, "names differ"); + if (_name != other._name && !opt.cpl_names_can_differ) { + stringstream s; + s << "names differ: " << _name << " vs " << other._name << "\n"; + note (ERROR, s.str ()); return false; } @@ -20,11 +20,15 @@ #include <list> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> +#include <libxml++/libxml++.h> #include "types.h" namespace libdcp { -class AssetMap; +namespace parse { + class AssetMap; +} + class Asset; class Reel; class XMLMetadata; @@ -34,7 +38,7 @@ class CPL { public: CPL (std::string directory, std::string name, ContentKind content_kind, int length, int frames_per_second); - CPL (std::string directory, std::string file, boost::shared_ptr<const AssetMap> asset_map, bool require_mxfs = true); + CPL (std::string directory, std::string file, boost::shared_ptr<const parse::AssetMap> asset_map, bool require_mxfs = true); void add_reel (boost::shared_ptr<const Reel> reel); @@ -71,8 +75,8 @@ public: bool equals (CPL const & other, EqualityOptions options, boost::function<void (NoteType, std::string)> note) const; void write_xml (XMLMetadata const &) const; - void write_to_assetmap (std::ostream& s) const; - void write_to_pkl (std::ostream& s) const; + void write_to_assetmap (xmlpp::Node *) const; + void write_to_pkl (xmlpp::Node *) const; private: std::string _directory; diff --git a/src/cpl_file.cc b/src/cpl_file.cc deleted file mode 100644 index 6a17d721..00000000 --- a/src/cpl_file.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington <cth@carlh.net> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/** @file src/cpl_file.cc - * @brief Classes used to parse a CPL. - */ - -#include <iostream> -#include "cpl_file.h" - -using namespace std; -using namespace libdcp; - -CPLFile::CPLFile (string file) - : XMLFile (file, "CompositionPlaylist") -{ - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - issue_date = string_child ("IssueDate"); - creator = optional_string_child ("Creator"); - content_title_text = string_child ("ContentTitleText"); - content_kind = kind_child ("ContentKind"); - content_version = optional_type_child<ContentVersion> ("ContentVersion"); - ignore_child ("RatingList"); - reels = type_grand_children<CPLReel> ("ReelList", "Reel"); - - ignore_child ("Issuer"); - ignore_child ("Signer"); - ignore_child ("Signature"); - - done (); -} - -ContentVersion::ContentVersion (xmlpp::Node const * node) - : XMLNode (node) -{ - id = optional_string_child ("Id"); - label_text = string_child ("LabelText"); - done (); -} - -CPLReel::CPLReel (xmlpp::Node const * node) - : XMLNode (node) -{ - id = string_child ("Id"); - asset_list = type_child<CPLAssetList> ("AssetList"); - - ignore_child ("AnnotationText"); - done (); -} - -CPLAssetList::CPLAssetList (xmlpp::Node const * node) - : XMLNode (node) -{ - main_picture = optional_type_child<MainPicture> ("MainPicture"); - main_stereoscopic_picture = optional_type_child<MainStereoscopicPicture> ("MainStereoscopicPicture"); - main_sound = optional_type_child<MainSound> ("MainSound"); - main_subtitle = optional_type_child<MainSubtitle> ("MainSubtitle"); - - done (); -} - -MainPicture::MainPicture (xmlpp::Node const * node) - : Picture (node) -{ - -} - -MainStereoscopicPicture::MainStereoscopicPicture (xmlpp::Node const * node) - : Picture (node) -{ - -} - -Picture::Picture (xmlpp::Node const * node) - : XMLNode (node) -{ - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - edit_rate = fraction_child ("EditRate"); - intrinsic_duration = int64_child ("IntrinsicDuration"); - entry_point = int64_child ("EntryPoint"); - duration = int64_child ("Duration"); - frame_rate = fraction_child ("FrameRate"); - try { - screen_aspect_ratio = fraction_child ("ScreenAspectRatio"); - } catch (XMLError& e) { - /* Maybe it's not a fraction */ - } - try { - float f = float_child ("ScreenAspectRatio"); - screen_aspect_ratio = Fraction (f * 1000, 1000); - } catch (bad_cast& e) { - - } - - ignore_child ("Hash"); - - done (); -} - -MainSound::MainSound (xmlpp::Node const * node) - : XMLNode (node) -{ - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - edit_rate = fraction_child ("EditRate"); - intrinsic_duration = int64_child ("IntrinsicDuration"); - entry_point = int64_child ("EntryPoint"); - duration = int64_child ("Duration"); - - ignore_child ("Hash"); - ignore_child ("Language"); - - done (); -} - -MainSubtitle::MainSubtitle (xmlpp::Node const * node) - : XMLNode (node) -{ - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - edit_rate = fraction_child ("EditRate"); - intrinsic_duration = int64_child ("IntrinsicDuration"); - entry_point = int64_child ("EntryPoint"); - duration = int64_child ("Duration"); - - ignore_child ("Hash"); - ignore_child ("Language"); - - done (); -} @@ -28,6 +28,7 @@ #include <iostream> #include <boost/filesystem.hpp> #include <boost/algorithm/string.hpp> +#include <boost/lexical_cast.hpp> #include <libxml++/libxml++.h> #include "dcp.h" #include "asset.h" @@ -37,9 +38,8 @@ #include "util.h" #include "metadata.h" #include "exceptions.h" -#include "cpl_file.h" -#include "pkl_file.h" -#include "asset_map.h" +#include "parse/pkl.h" +#include "parse/asset_map.h" #include "reel.h" #include "cpl.h" @@ -49,6 +49,7 @@ using std::stringstream; using std::ofstream; using std::ostream; using boost::shared_ptr; +using boost::lexical_cast; using namespace libdcp; DCP::DCP (string directory) @@ -81,30 +82,29 @@ DCP::write_pkl (string pkl_uuid, XMLMetadata const & metadata) const stringstream s; s << pkl_uuid << "_pkl.xml"; p /= s.str(); - ofstream pkl (p.string().c_str()); - - pkl << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - << "<PackingList xmlns=\"http://www.smpte-ra.org/schemas/429-8/2007/PKL\">\n" - << " <Id>urn:uuid:" << pkl_uuid << "</Id>\n" - /* XXX: this is a bit of a hack */ - << " <AnnotationText>" << _cpls.front()->name() << "</AnnotationText>\n" - << " <IssueDate>" << metadata.issue_date << "</IssueDate>\n" - << " <Issuer>" << metadata.issuer << "</Issuer>\n" - << " <Creator>" << metadata.creator << "</Creator>\n" - << " <AssetList>\n"; + + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("PackingList", "http://www.smpte-ra.org/schemas/429-8/2007/PKL"); + + root->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid); + /* XXX: this is a bit of a hack */ + root->add_child("AnnotationText")->add_child_text (_cpls.front()->name()); + root->add_child("IssueDate")->add_child_text (metadata.issue_date); + root->add_child("Issuer")->add_child_text (metadata.issuer); + root->add_child("Creator")->add_child_text (metadata.creator); + + xmlpp::Node* asset_list = root->add_child ("AssetList"); list<shared_ptr<const Asset> > a = assets (); for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) { - (*i)->write_to_pkl (pkl); + (*i)->write_to_pkl (asset_list); } for (list<shared_ptr<const CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) { - (*i)->write_to_pkl (pkl); + (*i)->write_to_pkl (asset_list); } - pkl << " </AssetList>\n" - << "</PackingList>\n"; - + doc.write_to_file_formatted (p.string (), "UTF-8"); return p.string (); } @@ -114,12 +114,11 @@ DCP::write_volindex () const boost::filesystem::path p; p /= _directory; p /= "VOLINDEX.xml"; - ofstream vi (p.string().c_str()); - vi << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - << "<VolumeIndex xmlns=\"http://www.smpte-ra.org/schemas/429-9/2007/AM\">\n" - << " <Index>1</Index>\n" - << "</VolumeIndex>\n"; + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("VolumeIndex", "http://www.smpte-ra.org/schemas/429-9/2007/AM"); + root->add_child("Index")->add_child_text ("1"); + doc.write_to_file_formatted (p.string (), "UTF-8"); } void @@ -128,41 +127,37 @@ DCP::write_assetmap (string pkl_uuid, int pkl_length, XMLMetadata const & metada boost::filesystem::path p; p /= _directory; p /= "ASSETMAP.xml"; - ofstream am (p.string().c_str()); - - am << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - << "<AssetMap xmlns=\"http://www.smpte-ra.org/schemas/429-9/2007/AM\">\n" - << " <Id>urn:uuid:" << make_uuid() << "</Id>\n" - << " <Creator>" << metadata.creator << "</Creator>\n" - << " <VolumeCount>1</VolumeCount>\n" - << " <IssueDate>" << metadata.issue_date << "</IssueDate>\n" - << " <Issuer>" << metadata.issuer << "</Issuer>\n" - << " <AssetList>\n"; - - am << " <Asset>\n" - << " <Id>urn:uuid:" << pkl_uuid << "</Id>\n" - << " <PackingList>true</PackingList>\n" - << " <ChunkList>\n" - << " <Chunk>\n" - << " <Path>" << pkl_uuid << "_pkl.xml</Path>\n" - << " <VolumeIndex>1</VolumeIndex>\n" - << " <Offset>0</Offset>\n" - << " <Length>" << pkl_length << "</Length>\n" - << " </Chunk>\n" - << " </ChunkList>\n" - << " </Asset>\n"; + + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("AssetMap", "http://www.smpte-ra.org/schemas/429-9/2007/AM"); + + root->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid()); + root->add_child("Creator")->add_child_text (metadata.creator); + root->add_child("VolumeCount")->add_child_text ("1"); + root->add_child("IssueDate")->add_child_text (metadata.issue_date); + root->add_child("Issuer")->add_child_text (metadata.issuer); + xmlpp::Node* asset_list = root->add_child ("AssetList"); + + xmlpp::Node* asset = asset_list->add_child ("Asset"); + asset->add_child("Id")->add_child_text ("urn:uuid:" + pkl_uuid); + asset->add_child("PackingList")->add_child_text ("true"); + xmlpp::Node* chunk_list = asset->add_child ("ChunkList"); + xmlpp::Node* chunk = chunk_list->add_child ("Chunk"); + chunk->add_child("Path")->add_child_text (pkl_uuid + "_pkl.xml"); + chunk->add_child("VolumeIndex")->add_child_text ("1"); + chunk->add_child("Offset")->add_child_text ("0"); + chunk->add_child("Length")->add_child_text (lexical_cast<string> (pkl_length)); for (list<shared_ptr<const CPL> >::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) { - (*i)->write_to_assetmap (am); + (*i)->write_to_assetmap (asset_list); } list<shared_ptr<const Asset> > a = assets (); for (list<shared_ptr<const Asset> >::const_iterator i = a.begin(); i != a.end(); ++i) { - (*i)->write_to_assetmap (am); + (*i)->write_to_assetmap (asset_list); } - am << " </AssetList>\n" - << "</AssetMap>\n"; + doc.write_to_file_formatted (p.string (), "UTF-8"); } @@ -171,17 +166,17 @@ DCP::read (bool require_mxfs) { Files files; - shared_ptr<AssetMap> asset_map; + shared_ptr<parse::AssetMap> asset_map; try { boost::filesystem::path p = _directory; p /= "ASSETMAP"; if (boost::filesystem::exists (p)) { - asset_map.reset (new AssetMap (p.string ())); + asset_map.reset (new libdcp::parse::AssetMap (p.string ())); } else { p = _directory; p /= "ASSETMAP.xml"; if (boost::filesystem::exists (p)) { - asset_map.reset (new AssetMap (p.string ())); + asset_map.reset (new libdcp::parse::AssetMap (p.string ())); } else { boost::throw_exception (DCPReadError ("could not find AssetMap file")); } @@ -191,7 +186,7 @@ DCP::read (bool require_mxfs) boost::throw_exception (FileError ("could not load AssetMap file", files.asset_map)); } - for (list<shared_ptr<AssetMapAsset> >::const_iterator i = asset_map->assets.begin(); i != asset_map->assets.end(); ++i) { + for (list<shared_ptr<libdcp::parse::AssetMapAsset> >::const_iterator i = asset_map->assets.begin(); i != asset_map->assets.end(); ++i) { if ((*i)->chunks.size() != 1) { boost::throw_exception (XMLError ("unsupported asset chunk count")); } @@ -233,9 +228,9 @@ DCP::read (bool require_mxfs) boost::throw_exception (FileError ("no PKL file found", "")); } - shared_ptr<PKLFile> pkl; + shared_ptr<parse::PKL> pkl; try { - pkl.reset (new PKLFile (files.pkl)); + pkl.reset (new parse::PKL (files.pkl)); } catch (FileError& e) { boost::throw_exception (FileError ("could not load PKL file", files.pkl)); } @@ -43,7 +43,6 @@ class PictureAsset; class SoundAsset; class SubtitleAsset; class Reel; -class AssetMap; class CPL; class XMLMetadata; diff --git a/src/asset_map.cc b/src/parse/asset_map.cc index 8fcc515f..aedc931e 100644 --- a/src/asset_map.cc +++ b/src/parse/asset_map.cc @@ -23,36 +23,36 @@ #include <boost/algorithm/string.hpp> #include "asset_map.h" -#include "util.h" +#include "../util.h" +#include "../xml.h" using std::string; using std::list; using boost::shared_ptr; -using namespace libdcp; +using namespace libdcp::parse; AssetMap::AssetMap (string file) - : XMLFile (file, "AssetMap") { - id = string_child ("Id"); - creator = string_child ("Creator"); - volume_count = int64_child ("VolumeCount"); - issue_date = string_child ("IssueDate"); - issuer = string_child ("Issuer"); - assets = type_grand_children<AssetMapAsset> ("AssetList", "Asset"); + cxml::File f (file, "AssetMap"); + + id = f.string_child ("Id"); + creator = f.string_child ("Creator"); + volume_count = f.number_child<int64_t> ("VolumeCount"); + issue_date = f.string_child ("IssueDate"); + issuer = f.string_child ("Issuer"); + assets = type_grand_children<AssetMapAsset> (f, "AssetList", "Asset"); } -AssetMapAsset::AssetMapAsset (xmlpp::Node const * node) - : XMLNode (node) +AssetMapAsset::AssetMapAsset (shared_ptr<const cxml::Node> node) { - id = string_child ("Id"); - packing_list = optional_string_child ("PackingList"); - chunks = type_grand_children<Chunk> ("ChunkList", "Chunk"); + id = node->string_child ("Id"); + packing_list = node->optional_string_child ("PackingList").get_value_or (""); + chunks = type_grand_children<Chunk> (node, "ChunkList", "Chunk"); } -Chunk::Chunk (xmlpp::Node const * node) - : XMLNode (node) +Chunk::Chunk (shared_ptr<const cxml::Node> node) { - path = string_child ("Path"); + path = node->string_child ("Path"); string const prefix = "file://"; @@ -60,9 +60,9 @@ Chunk::Chunk (xmlpp::Node const * node) path = path.substr (prefix.length()); } - volume_index = optional_int64_child ("VolumeIndex"); - offset = optional_int64_child ("Offset"); - length = optional_int64_child ("Length"); + volume_index = node->optional_number_child<int64_t> ("VolumeIndex").get_value_or (0); + offset = node->optional_number_child<int64_t> ("Offset").get_value_or (0); + length = node->optional_number_child<int64_t> ("Length").get_value_or (0); } shared_ptr<AssetMapAsset> diff --git a/src/asset_map.h b/src/parse/asset_map.h index 8cf89b4b..af3e8918 100644 --- a/src/asset_map.h +++ b/src/parse/asset_map.h @@ -23,18 +23,20 @@ #include <stdint.h> #include <boost/shared_ptr.hpp> -#include "xml.h" +#include <libcxml/cxml.h> namespace libdcp { +namespace parse { + /** @class Chunk * @brief A simple parser for and representation of a \<Chunk\> node within an asset map. */ -class Chunk : public XMLNode +class Chunk { public: Chunk (); - Chunk (xmlpp::Node const * node); + Chunk (boost::shared_ptr<const cxml::Node> node); std::string path; int64_t volume_index; @@ -45,11 +47,11 @@ public: /** @class AssetMapAsset * @brief A simple parser for and representation of an \<AssetMap\> node within an asset map. */ -class AssetMapAsset : public XMLNode +class AssetMapAsset { public: AssetMapAsset (); - AssetMapAsset (xmlpp::Node const * node); + AssetMapAsset (boost::shared_ptr<const cxml::Node> node); std::string id; std::string packing_list; @@ -59,7 +61,7 @@ public: /** @class AssetMap * @brief A simple parser for and representation of an asset map file. */ -class AssetMap : public XMLFile +class AssetMap { public: AssetMap (std::string file); @@ -75,3 +77,5 @@ public: }; } + +} diff --git a/src/parse/cpl.cc b/src/parse/cpl.cc new file mode 100644 index 00000000..c4cf4374 --- /dev/null +++ b/src/parse/cpl.cc @@ -0,0 +1,147 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/cpl_file.cc + * @brief Classes used to parse a CPL. + */ + +#include <iostream> +#include "cpl.h" +#include "../xml.h" +#include "../util.h" + +using std::string; +using std::bad_cast; +using boost::shared_ptr; +using namespace libdcp::parse; + +CPL::CPL (string file) +{ + cxml::File f (file, "CompositionPlaylist"); + + id = f.string_child ("Id"); + annotation_text = f.optional_string_child ("AnnotationText").get_value_or (""); + issue_date = f.string_child ("IssueDate"); + creator = f.optional_string_child ("Creator").get_value_or (""); + content_title_text = f.string_child ("ContentTitleText"); + content_kind = content_kind_from_string (f.string_child ("ContentKind")); + content_version = optional_type_child<ContentVersion> (f, "ContentVersion"); + f.ignore_child ("RatingList"); + reels = type_grand_children<Reel> (f, "ReelList", "Reel"); + + f.ignore_child ("Issuer"); + f.ignore_child ("Signer"); + f.ignore_child ("Signature"); + + f.done (); +} + +ContentVersion::ContentVersion (shared_ptr<const cxml::Node> node) +{ + id = node->optional_string_child ("Id").get_value_or (""); + label_text = node->string_child ("LabelText"); + node->done (); +} + +Reel::Reel (shared_ptr<const cxml::Node> node) +{ + id = node->string_child ("Id"); + asset_list = type_child<CPLAssetList> (node, "AssetList"); + + node->ignore_child ("AnnotationText"); + node->done (); +} + +CPLAssetList::CPLAssetList (shared_ptr<const cxml::Node> node) +{ + main_picture = optional_type_child<MainPicture> (node, "MainPicture"); + main_stereoscopic_picture = optional_type_child<MainStereoscopicPicture> (node, "MainStereoscopicPicture"); + main_sound = optional_type_child<MainSound> (node, "MainSound"); + main_subtitle = optional_type_child<MainSubtitle> (node, "MainSubtitle"); + + node->done (); +} + +MainPicture::MainPicture (shared_ptr<const cxml::Node> node) + : Picture (node) +{ + +} + +MainStereoscopicPicture::MainStereoscopicPicture (shared_ptr<const cxml::Node> node) + : Picture (node) +{ + +} + +Picture::Picture (shared_ptr<const cxml::Node> node) +{ + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child<int64_t> ("IntrinsicDuration"); + entry_point = node->number_child<int64_t> ("EntryPoint"); + duration = node->number_child<int64_t> ("Duration"); + frame_rate = Fraction (node->string_child ("FrameRate")); + try { + screen_aspect_ratio = Fraction (node->string_child ("ScreenAspectRatio")); + } catch (XMLError& e) { + /* Maybe it's not a fraction */ + } + try { + float f = node->number_child<float> ("ScreenAspectRatio"); + screen_aspect_ratio = Fraction (f * 1000, 1000); + } catch (bad_cast& e) { + + } + + node->ignore_child ("Hash"); + + node->done (); +} + +MainSound::MainSound (shared_ptr<const cxml::Node> node) +{ + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child<int64_t> ("IntrinsicDuration"); + entry_point = node->number_child<int64_t> ("EntryPoint"); + duration = node->number_child<int64_t> ("Duration"); + + node->ignore_child ("Hash"); + node->ignore_child ("Language"); + + node->done (); +} + +MainSubtitle::MainSubtitle (shared_ptr<const cxml::Node> node) +{ + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + edit_rate = Fraction (node->string_child ("EditRate")); + intrinsic_duration = node->number_child<int64_t> ("IntrinsicDuration"); + entry_point = node->number_child<int64_t> ("EntryPoint"); + duration = node->number_child<int64_t> ("Duration"); + + node->ignore_child ("Hash"); + node->ignore_child ("Language"); + + node->done (); +} diff --git a/src/cpl_file.h b/src/parse/cpl.h index 44115401..434a244b 100644 --- a/src/cpl_file.h +++ b/src/parse/cpl.h @@ -17,22 +17,25 @@ */ -/** @file src/cpl_file.h +/** @file src/parse/cpl.h * @brief Classes used to parse a CPL. */ #include <stdint.h> #include <boost/shared_ptr.hpp> -#include "xml.h" +#include <libcxml/cxml.h> +#include "../types.h" namespace libdcp { -/** @brief A simple parser for and representation of a CPL \<Picture\> node */ -class Picture : public XMLNode +namespace parse { + +/** @brief A simple representation of a CPL \<Picture\> node */ +class Picture { public: Picture () {} - Picture (xmlpp::Node const * node); + Picture (boost::shared_ptr<const cxml::Node> node); std::string id; std::string annotation_text; @@ -53,7 +56,7 @@ class MainPicture : public Picture { public: MainPicture () {} - MainPicture (xmlpp::Node const * node); + MainPicture (boost::shared_ptr<const cxml::Node> node); }; /** @brief A simple parser for and representation of a CPL \<MainStereoscopicPicture\> node */ @@ -61,15 +64,15 @@ class MainStereoscopicPicture : public Picture { public: MainStereoscopicPicture () {} - MainStereoscopicPicture (xmlpp::Node const * node); + MainStereoscopicPicture (boost::shared_ptr<const cxml::Node> node); }; /** @brief A simple parser for and representation of a CPL \<MainSound\> node */ -class MainSound : public XMLNode +class MainSound { public: MainSound () {} - MainSound (xmlpp::Node const * node); + MainSound (boost::shared_ptr<const cxml::Node> node); std::string id; std::string annotation_text; @@ -80,11 +83,11 @@ public: }; /** @brief A simple parser for and representation of a CPL \<MainSubtitle\> node */ -class MainSubtitle : public XMLNode +class MainSubtitle { public: MainSubtitle () {} - MainSubtitle (xmlpp::Node const * node); + MainSubtitle (boost::shared_ptr<const cxml::Node> node); std::string id; std::string annotation_text; @@ -95,11 +98,11 @@ public: }; /** @brief A simple parser for and representation of a CPL \<AssetList\> node */ -class CPLAssetList : public XMLNode +class CPLAssetList { public: CPLAssetList () {} - CPLAssetList (xmlpp::Node const * node); + CPLAssetList (boost::shared_ptr<const cxml::Node> node); boost::shared_ptr<MainPicture> main_picture; boost::shared_ptr<MainStereoscopicPicture> main_stereoscopic_picture; @@ -108,11 +111,11 @@ public: }; /** @brief A simple parser for and representation of a CPL \<Reel\> node */ -class CPLReel : public XMLNode +class Reel { public: - CPLReel () {} - CPLReel (xmlpp::Node const * node); + Reel () {} + Reel (boost::shared_ptr<const cxml::Node> node); std::string id; boost::shared_ptr<CPLAssetList> asset_list; @@ -120,27 +123,27 @@ public: /** @brief A simple parser for and representation of a CPL \<ContentVersion\> node */ -class ContentVersion : public XMLNode +class ContentVersion { public: ContentVersion () {} - ContentVersion (xmlpp::Node const * node); + ContentVersion (boost::shared_ptr<const cxml::Node> node); std::string id; std::string label_text; }; -/** @class CPLFile +/** @class CPL * @brief Class to parse a CPL * * This class is used to parse XML CPL files. It is rarely necessary * for the caller to use it outside libdcp. */ -class CPLFile : public XMLFile +class CPL { public: /** Parse a CPL XML file into our member variables */ - CPLFile (std::string file); + CPL (std::string file); std::string id; std::string annotation_text; @@ -149,8 +152,10 @@ public: std::string content_title_text; ContentKind content_kind; boost::shared_ptr<ContentVersion> content_version; - std::list<boost::shared_ptr<CPLReel> > reels; + std::list<boost::shared_ptr<Reel> > reels; }; } +} + diff --git a/src/pkl_file.cc b/src/parse/pkl.cc index 6dfb627c..d790cfe4 100644 --- a/src/pkl_file.cc +++ b/src/parse/pkl.cc @@ -22,30 +22,30 @@ */ #include <iostream> -#include "pkl_file.h" +#include "pkl.h" using namespace std; using namespace boost; -using namespace libdcp; +using namespace libdcp::parse; -PKLFile::PKLFile (string file) - : XMLFile (file, "PackingList") +PKL::PKL (string file) { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - issue_date = string_child ("IssueDate"); - issuer = string_child ("Issuer"); - creator = string_child ("Creator"); - assets = type_grand_children<PKLAsset> ("AssetList", "Asset"); + cxml::File f (file, "PackingList"); + + id = f.string_child ("Id"); + annotation_text = f.optional_string_child ("AnnotationText").get_value_or (""); + issue_date = f.string_child ("IssueDate"); + issuer = f.string_child ("Issuer"); + creator = f.string_child ("Creator"); + assets = type_grand_children<PKLAsset> (f, "AssetList", "Asset"); } -PKLAsset::PKLAsset (xmlpp::Node const * node) - : XMLNode (node) +PKLAsset::PKLAsset (boost::shared_ptr<const cxml::Node> node) { - id = string_child ("Id"); - annotation_text = optional_string_child ("AnnotationText"); - hash = string_child ("Hash"); - size = int64_child ("Size"); - type = string_child ("Type"); - original_file_name = optional_string_child ("OriginalFileName"); + id = node->string_child ("Id"); + annotation_text = node->optional_string_child ("AnnotationText").get_value_or (""); + hash = node->string_child ("Hash"); + size = node->number_child<int64_t> ("Size"); + type = node->string_child ("Type"); + original_file_name = node->optional_string_child ("OriginalFileName").get_value_or (""); } diff --git a/src/pkl_file.h b/src/parse/pkl.h index b64da5da..13d87fa1 100644 --- a/src/pkl_file.h +++ b/src/parse/pkl.h @@ -17,20 +17,22 @@ */ -/** @file src/pkl_file.h +/** @file src/parse/pkl.h * @brief Classes used to parse a PKL */ #include <boost/shared_ptr.hpp> -#include "xml.h" +#include "../xml.h" namespace libdcp { -class PKLAsset : public XMLNode +namespace parse { + +class PKLAsset { public: PKLAsset () {} - PKLAsset (xmlpp::Node const * node); + PKLAsset (boost::shared_ptr<const cxml::Node>); std::string id; std::string annotation_text; @@ -40,10 +42,10 @@ public: std::string original_file_name; }; -class PKLFile : public XMLFile +class PKL { public: - PKLFile (std::string file); + PKL (std::string file); std::string id; std::string annotation_text; @@ -54,3 +56,5 @@ public: }; } + +} diff --git a/src/parse/subtitle.cc b/src/parse/subtitle.cc new file mode 100644 index 00000000..612af716 --- /dev/null +++ b/src/parse/subtitle.cc @@ -0,0 +1,135 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> +#include "subtitle.h" +#include "../types.h" + +using std::string; +using std::list; +using boost::shared_ptr; +using boost::optional; +using boost::lexical_cast; +using namespace libdcp; +using namespace libdcp::parse; + +Font::Font (shared_ptr<const cxml::Node> node) +{ + text = node->content (); + + id = node->optional_string_attribute ("Id").get_value_or (""); + size = node->optional_number_attribute<int64_t> ("Size").get_value_or (0); + italic = node->optional_bool_attribute ("Italic"); + optional<string> c = node->optional_string_attribute ("Color"); + if (c) { + color = Color (c.get ()); + } + optional<string> const e = node->optional_string_attribute ("Effect"); + if (e) { + effect = string_to_effect (e.get ()); + } + c = node->optional_string_attribute ( "EffectColor"); + if (c) { + effect_color = Color (c.get ()); + } + subtitle_nodes = type_children<Subtitle> (node, "Subtitle"); + font_nodes = type_children<Font> (node, "Font"); + text_nodes = type_children<Text> (node, "Text"); +} + +Font::Font (list<shared_ptr<Font> > const & font_nodes) + : size (0) + , italic (false) + , color ("FFFFFFFF") + , effect_color ("FFFFFFFF") +{ + for (list<shared_ptr<Font> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { + if (!(*i)->id.empty ()) { + id = (*i)->id; + } + if ((*i)->size != 0) { + size = (*i)->size; + } + if ((*i)->italic) { + italic = (*i)->italic.get (); + } + if ((*i)->color) { + color = (*i)->color.get (); + } + if ((*i)->effect) { + effect = (*i)->effect.get (); + } + if ((*i)->effect_color) { + effect_color = (*i)->effect_color.get (); + } + } +} + +LoadFont::LoadFont (shared_ptr<const cxml::Node> node) +{ + id = node->string_attribute ("Id"); + uri = node->string_attribute ("URI"); +} + + +Subtitle::Subtitle (shared_ptr<const cxml::Node> node) +{ + in = Time (node->string_attribute ("TimeIn")); + out = Time (node->string_attribute ("TimeOut")); + font_nodes = type_children<Font> (node, "Font"); + text_nodes = type_children<Text> (node, "Text"); + fade_up_time = fade_time (node, "FadeUpTime"); + fade_down_time = fade_time (node, "FadeDownTime"); +} + +Time +Subtitle::fade_time (shared_ptr<const cxml::Node> node, string name) +{ + string const u = node->optional_string_attribute (name).get_value_or (""); + Time t; + + if (u.empty ()) { + t = Time (0, 0, 0, 20); + } else if (u.find (":") != string::npos) { + t = Time (u); + } else { + t = Time (0, 0, 0, lexical_cast<int> (u)); + } + + if (t > Time (0, 0, 8, 0)) { + t = Time (0, 0, 8, 0); + } + + return t; +} + +Text::Text (shared_ptr<const cxml::Node> node) + : v_align (CENTER) +{ + text = node->content (); + v_position = node->number_attribute<float> ("VPosition"); + optional<string> v = node->optional_string_attribute ("VAlign"); + if (v) { + v_align = string_to_valign (v.get ()); + } + + font_nodes = type_children<Font> (node, "Font"); +} + diff --git a/src/parse/subtitle.h b/src/parse/subtitle.h new file mode 100644 index 00000000..34321545 --- /dev/null +++ b/src/parse/subtitle.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "../xml.h" +#include "../dcp_time.h" +#include "../types.h" + +namespace libdcp +{ + +namespace parse +{ + +class Font; + +class Text +{ +public: + Text () {} + Text (boost::shared_ptr<const cxml::Node> node); + + float v_position; + VAlign v_align; + std::string text; + std::list<boost::shared_ptr<Font> > font_nodes; +}; + +class Subtitle +{ +public: + Subtitle () {} + Subtitle (boost::shared_ptr<const cxml::Node> node); + + Time in; + Time out; + Time fade_up_time; + Time fade_down_time; + std::list<boost::shared_ptr<Font> > font_nodes; + std::list<boost::shared_ptr<Text> > text_nodes; + +private: + Time fade_time (boost::shared_ptr<const cxml::Node>, std::string name); +}; + +class Font +{ +public: + Font () {} + Font (boost::shared_ptr<const cxml::Node> node); + Font (std::list<boost::shared_ptr<Font> > const & font_nodes); + + std::string text; + std::string id; + int size; + boost::optional<bool> italic; + boost::optional<Color> color; + boost::optional<Effect> effect; + boost::optional<Color> effect_color; + + std::list<boost::shared_ptr<Subtitle> > subtitle_nodes; + std::list<boost::shared_ptr<Font> > font_nodes; + std::list<boost::shared_ptr<Text> > text_nodes; +}; + +class LoadFont +{ +public: + LoadFont () {} + LoadFont (boost::shared_ptr<const cxml::Node> node); + + std::string id; + std::string uri; +}; + +} + +} diff --git a/src/picture_asset.cc b/src/picture_asset.cc index 0019d562..b5f59f3b 100644 --- a/src/picture_asset.cc +++ b/src/picture_asset.cc @@ -64,18 +64,17 @@ PictureAsset::PictureAsset (string directory, string mxf_name) } void -PictureAsset::write_to_cpl (ostream& s) const +PictureAsset::write_to_cpl (xmlpp::Node* node) const { - s << " <MainPicture>\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <AnnotationText>" << _file_name << "</AnnotationText>\n" - << " <EditRate>" << _edit_rate << " 1</EditRate>\n" - << " <IntrinsicDuration>" << _intrinsic_duration << "</IntrinsicDuration>\n" - << " <EntryPoint>" << _entry_point << "</EntryPoint>\n" - << " <Duration>" << _duration << "</Duration>\n" - << " <FrameRate>" << _edit_rate << " 1</FrameRate>\n" - << " <ScreenAspectRatio>" << _size.width << " " << _size.height << "</ScreenAspectRatio>\n" - << " </MainPicture>\n"; + xmlpp::Node* mp = node->add_child ("MainPicture"); + mp->add_child ("Id")->add_child_text ("urn:uuid:" + _uuid); + mp->add_child ("AnnotationText")->add_child_text (_file_name); + mp->add_child ("EditRate")->add_child_text (lexical_cast<string> (_edit_rate) + " 1"); + mp->add_child ("IntrinsicDuration")->add_child_text (lexical_cast<string> (_intrinsic_duration)); + mp->add_child ("EntryPoint")->add_child_text (lexical_cast<string> (_entry_point)); + mp->add_child ("Duration")->add_child_text (lexical_cast<string> (_duration)); + mp->add_child ("FrameRate")->add_child_text (lexical_cast<string> (_edit_rate) + " 1"); + mp->add_child ("ScreenAspectRatio")->add_child_text (lexical_cast<string> (_size.width) + " " + lexical_cast<string> (_size.height)); } bool diff --git a/src/picture_asset.h b/src/picture_asset.h index 2041abb3..8536bacc 100644 --- a/src/picture_asset.h +++ b/src/picture_asset.h @@ -59,10 +59,10 @@ public: */ PictureAsset (std::string directory, std::string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration, Size size); - /** Write details of this asset to a CPL stream. - * @param s Stream. + /** Write details of this asset to a CPL XML node. + * @param node Node. */ - void write_to_cpl (std::ostream& s) const; + void write_to_cpl (xmlpp::Node* node) const; bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const; diff --git a/src/reel.cc b/src/reel.cc index 86533ea2..481b153b 100644 --- a/src/reel.cc +++ b/src/reel.cc @@ -27,26 +27,23 @@ using namespace std; using namespace libdcp; void -Reel::write_to_cpl (ostream& s) const +Reel::write_to_cpl (xmlpp::Node* node) const { - s << " <Reel>\n" - << " <Id>urn:uuid:" << make_uuid() << "</Id>\n" - << " <AssetList>\n"; + xmlpp::Node* reel = node->add_child ("Reel"); + reel->add_child("Id")->add_child_text ("urn:uuid:" + make_uuid()); + xmlpp::Node* asset_list = reel->add_child ("AssetList"); if (_main_picture) { - _main_picture->write_to_cpl (s); + _main_picture->write_to_cpl (asset_list); } if (_main_sound) { - _main_sound->write_to_cpl (s); + _main_sound->write_to_cpl (asset_list); } if (_main_subtitle) { - _main_subtitle->write_to_cpl (s); + _main_subtitle->write_to_cpl (asset_list); } - - s << " </AssetList>\n" - << " </Reel>\n"; } bool @@ -20,6 +20,7 @@ #include <list> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> +#include <libxml++/libxml++.h> #include "types.h" namespace libdcp { @@ -54,7 +55,7 @@ public: return _main_subtitle; } - void write_to_cpl (std::ostream & s) const; + void write_to_cpl (xmlpp::Node *) const; bool equals (boost::shared_ptr<const Reel> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> notes) const; diff --git a/src/sound_asset.cc b/src/sound_asset.cc index efef3ba7..f59d82ad 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -211,16 +211,15 @@ SoundAsset::construct (boost::function<string (Channel)> get_path, MXFMetadata c } void -SoundAsset::write_to_cpl (ostream& s) const +SoundAsset::write_to_cpl (xmlpp::Node* node) const { - s << " <MainSound>\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <AnnotationText>" << _file_name << "</AnnotationText>\n" - << " <EditRate>" << _edit_rate << " 1</EditRate>\n" - << " <IntrinsicDuration>" << _intrinsic_duration << "</IntrinsicDuration>\n" - << " <EntryPoint>" << _entry_point << "</EntryPoint>\n" - << " <Duration>" << _duration << "</Duration>\n" - << " </MainSound>\n"; + xmlpp::Node* ms = node->add_child ("MainSound"); + ms->add_child ("Id")->add_child_text ("urn:uuid:" + _uuid); + ms->add_child ("AnnotationText")->add_child_text (_file_name); + ms->add_child ("EditRate")->add_child_text (lexical_cast<string> (_edit_rate) + " 1"); + ms->add_child ("IntrinsicDuration")->add_child_text (lexical_cast<string> (_intrinsic_duration)); + ms->add_child ("EntryPoint")->add_child_text (lexical_cast<string> (_entry_point)); + ms->add_child ("Duration")->add_child_text (lexical_cast<string> (_duration)); } bool diff --git a/src/sound_asset.h b/src/sound_asset.h index b95b34be..7b9c65a7 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -125,10 +125,10 @@ public: boost::shared_ptr<SoundAssetWriter> start_write (MXFMetadata const & metadata = MXFMetadata ()); - /** Write details of this asset to a CPL stream. - * @param s Stream. + /** Write details of this asset to a CPL XML node. + * @param node Node. */ - void write_to_cpl (std::ostream& s) const; + void write_to_cpl (xmlpp::Node* node) const; bool equals (boost::shared_ptr<const Asset> other, EqualityOptions opt, boost::function<void (NoteType, std::string)> note) const; diff --git a/src/subtitle_asset.cc b/src/subtitle_asset.cc index ba91cf90..ca91e2c7 100644 --- a/src/subtitle_asset.cc +++ b/src/subtitle_asset.cc @@ -22,6 +22,7 @@ #include <boost/algorithm/string.hpp> #include "subtitle_asset.h" #include "util.h" +#include "xml.h" using std::string; using std::list; @@ -30,6 +31,7 @@ using std::ofstream; using std::stringstream; using boost::shared_ptr; using boost::lexical_cast; +using boost::optional; using namespace libdcp; SubtitleAsset::SubtitleAsset (string directory, string xml_file) @@ -52,7 +54,7 @@ SubtitleAsset::SubtitleAsset (string directory, string movie_title, string langu void SubtitleAsset::read_xml (string xml_file) { - shared_ptr<XMLFile> xml (new XMLFile (xml_file, "DCSubtitle")); + shared_ptr<cxml::File> xml (new cxml::File (xml_file, "DCSubtitle")); _uuid = xml->string_child ("SubtitleID"); _movie_title = xml->string_child ("MovieTitle"); @@ -61,8 +63,8 @@ SubtitleAsset::read_xml (string xml_file) xml->ignore_child ("LoadFont"); - list<shared_ptr<FontNode> > font_nodes = xml->type_children<FontNode> ("Font"); - _load_font_nodes = xml->type_children<LoadFontNode> ("LoadFont"); + list<shared_ptr<libdcp::parse::Font> > font_nodes = type_children<libdcp::parse::Font> (xml, "Font"); + _load_font_nodes = type_children<libdcp::parse::LoadFont> (xml, "LoadFont"); /* Now make Subtitle objects to represent the raw XML nodes in a sane way. @@ -74,17 +76,17 @@ SubtitleAsset::read_xml (string xml_file) void SubtitleAsset::examine_font_nodes ( - shared_ptr<XMLFile> xml, - list<shared_ptr<FontNode> > const & font_nodes, + shared_ptr<const cxml::Node> xml, + list<shared_ptr<libdcp::parse::Font> > const & font_nodes, ParseState& parse_state ) { - for (list<shared_ptr<FontNode> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { + for (list<shared_ptr<libdcp::parse::Font> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { parse_state.font_nodes.push_back (*i); maybe_add_subtitle ((*i)->text, parse_state); - for (list<shared_ptr<SubtitleNode> >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) { + for (list<shared_ptr<libdcp::parse::Subtitle> >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) { parse_state.subtitle_nodes.push_back (*j); examine_text_nodes (xml, (*j)->text_nodes, parse_state); examine_font_nodes (xml, (*j)->font_nodes, parse_state); @@ -100,12 +102,12 @@ SubtitleAsset::examine_font_nodes ( void SubtitleAsset::examine_text_nodes ( - shared_ptr<XMLFile> xml, - list<shared_ptr<TextNode> > const & text_nodes, + shared_ptr<const cxml::Node> xml, + list<shared_ptr<libdcp::parse::Text> > const & text_nodes, ParseState& parse_state ) { - for (list<shared_ptr<TextNode> >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) { + for (list<shared_ptr<libdcp::parse::Text> >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) { parse_state.text_nodes.push_back (*i); maybe_add_subtitle ((*i)->text, parse_state); examine_font_nodes (xml, (*i)->font_nodes, parse_state); @@ -127,9 +129,9 @@ SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state) assert (!parse_state.text_nodes.empty ()); assert (!parse_state.subtitle_nodes.empty ()); - FontNode effective_font (parse_state.font_nodes); - TextNode effective_text (*parse_state.text_nodes.back ()); - SubtitleNode effective_subtitle (*parse_state.subtitle_nodes.back ()); + libdcp::parse::Font effective_font (parse_state.font_nodes); + libdcp::parse::Text effective_text (*parse_state.text_nodes.back ()); + libdcp::parse::Subtitle effective_subtitle (*parse_state.subtitle_nodes.back ()); _subtitles.push_back ( shared_ptr<Subtitle> ( @@ -152,107 +154,6 @@ SubtitleAsset::maybe_add_subtitle (string text, ParseState const & parse_state) ); } -FontNode::FontNode (xmlpp::Node const * node) - : XMLNode (node) -{ - text = content (); - - id = optional_string_attribute ("Id"); - size = optional_int64_attribute ("Size"); - italic = optional_bool_attribute ("Italic"); - color = optional_color_attribute ("Color"); - string const e = optional_string_attribute ("Effect"); - if (!e.empty ()) { - effect = string_to_effect (e); - } - effect_color = optional_color_attribute ("EffectColor"); - subtitle_nodes = type_children<SubtitleNode> ("Subtitle"); - font_nodes = type_children<FontNode> ("Font"); - text_nodes = type_children<TextNode> ("Text"); -} - -FontNode::FontNode (list<shared_ptr<FontNode> > const & font_nodes) - : size (0) - , italic (false) - , color ("FFFFFFFF") - , effect_color ("FFFFFFFF") -{ - for (list<shared_ptr<FontNode> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { - if (!(*i)->id.empty ()) { - id = (*i)->id; - } - if ((*i)->size != 0) { - size = (*i)->size; - } - if ((*i)->italic) { - italic = (*i)->italic.get (); - } - if ((*i)->color) { - color = (*i)->color.get (); - } - if ((*i)->effect) { - effect = (*i)->effect.get (); - } - if ((*i)->effect_color) { - effect_color = (*i)->effect_color.get (); - } - } -} - -LoadFontNode::LoadFontNode (xmlpp::Node const * node) - : XMLNode (node) -{ - id = string_attribute ("Id"); - uri = string_attribute ("URI"); -} - - -SubtitleNode::SubtitleNode (xmlpp::Node const * node) - : XMLNode (node) -{ - in = time_attribute ("TimeIn"); - out = time_attribute ("TimeOut"); - font_nodes = type_children<FontNode> ("Font"); - text_nodes = type_children<TextNode> ("Text"); - fade_up_time = fade_time ("FadeUpTime"); - fade_down_time = fade_time ("FadeDownTime"); -} - -Time -SubtitleNode::fade_time (string name) -{ - string const u = optional_string_attribute (name); - Time t; - - if (u.empty ()) { - t = Time (0, 0, 0, 20); - } else if (u.find (":") != string::npos) { - t = Time (u); - } else { - t = Time (0, 0, 0, lexical_cast<int> (u)); - } - - if (t > Time (0, 0, 8, 0)) { - t = Time (0, 0, 8, 0); - } - - return t; -} - -TextNode::TextNode (xmlpp::Node const * node) - : XMLNode (node) - , v_align (CENTER) -{ - text = content (); - v_position = float_attribute ("VPosition"); - string const v = optional_string_attribute ("VAlign"); - if (!v.empty ()) { - v_align = string_to_valign (v); - } - - font_nodes = type_children<FontNode> ("Font"); -} - list<shared_ptr<Subtitle> > SubtitleAsset::subtitles_at (Time t) const { @@ -269,7 +170,7 @@ SubtitleAsset::subtitles_at (Time t) const std::string SubtitleAsset::font_id_to_name (string id) const { - list<shared_ptr<LoadFontNode> >::const_iterator i = _load_font_nodes.begin(); + list<shared_ptr<libdcp::parse::LoadFont> >::const_iterator i = _load_font_nodes.begin(); while (i != _load_font_nodes.end() && (*i)->id != id) { ++i; } @@ -375,15 +276,15 @@ SubtitleAsset::add (shared_ptr<Subtitle> s) } void -SubtitleAsset::write_to_cpl (ostream& s) const +SubtitleAsset::write_to_cpl (xmlpp::Node* node) const { /* XXX: should EditRate, Duration and IntrinsicDuration be in here? */ - - s << " <MainSubtitle>\n" - << " <Id>urn:uuid:" << _uuid << "</Id>\n" - << " <AnnotationText>" << _file_name << "</AnnotationText>\n" - << " <EntryPoint>0</EntryPoint>\n" - << " </MainSubtitle>\n"; + + xmlpp::Node* ms = node->add_child ("MainSubtitle"); + ms->add_child("Id")->add_child_text("urn:uuid:" + _uuid); + ms->add_child("AnnotationText")->add_child_text (_file_name); + /* XXX */ + ms->add_child("EntryPoint")->add_child_text ("0"); } struct SubtitleSorter { @@ -398,26 +299,30 @@ struct SubtitleSorter { void SubtitleAsset::write_xml () const { - ofstream f (path().string().c_str()); - write_xml (f); + ofstream s (path().string().c_str()); + write_xml (s); } void SubtitleAsset::write_xml (ostream& s) const { - s << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" - << "<DCSubtitle Version=\"1.0\">\n" - << " <SubtitleID>" << _uuid << "</SubtitleID>\n" - << " <MovieTitle>" << _movie_title << "</MovieTitle>\n" - << " <ReelNumber>" << _reel_number << "</ReelNumber>\n" - << " <Language>" << _language << "</Language>\n"; + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("DCSubtitle"); + root->set_attribute ("Version", "1.0"); + + root->add_child("SubtitleID")->add_child_text (_uuid); + root->add_child("MovieTitle")->add_child_text (_movie_title); + root->add_child("ReelNumber")->add_child_text (lexical_cast<string> (_reel_number)); + root->add_child("Language")->add_child_text (_language); if (_load_font_nodes.size() > 1) { boost::throw_exception (MiscError ("multiple LoadFont nodes not supported")); } if (!_load_font_nodes.empty ()) { - s << " <LoadFont Id=\"" << _load_font_nodes.front()->id << "\" URI=\"" << _load_font_nodes.front()->uri << "\"/>\n"; + xmlpp::Element* load_font = root->add_child("LoadFont"); + load_font->set_attribute("Id", _load_font_nodes.front()->id); + load_font->set_attribute("URI", _load_font_nodes.front()->uri); } list<shared_ptr<Subtitle> > sorted = _subtitles; @@ -428,7 +333,6 @@ SubtitleAsset::write_xml (ostream& s) const /* XXX: multiple fonts not supported */ /* XXX: script, underlined, weight not supported */ - bool first = true; bool italic = false; Color color; int size = 0; @@ -440,66 +344,61 @@ SubtitleAsset::write_xml (ostream& s) const Time last_fade_up_time; Time last_fade_down_time; + xmlpp::Element* font = 0; + xmlpp::Element* subtitle = 0; + for (list<shared_ptr<Subtitle> >::iterator i = sorted.begin(); i != sorted.end(); ++i) { /* We will start a new <Font>...</Font> whenever some font property changes. - I suppose should really make an optimal hierarchy of <Font> tags, but + I suppose we should really make an optimal hierarchy of <Font> tags, but that seems hard. */ - bool const font_changed = first || + bool const font_changed = italic != (*i)->italic() || color != (*i)->color() || size != (*i)->size() || effect != (*i)->effect() || effect_color != (*i)->effect_color(); - stringstream a; if (font_changed) { italic = (*i)->italic (); - a << "Italic=\"" << (italic ? "yes" : "no") << "\" "; color = (*i)->color (); - a << "Color=\"" << color.to_argb_string() << "\" "; size = (*i)->size (); - a << "Size=\"" << size << "\" "; effect = (*i)->effect (); - a << "Effect=\"" << effect_to_string(effect) << "\" "; effect_color = (*i)->effect_color (); - a << "EffectColor=\"" << effect_color.to_argb_string() << "\" "; - a << "Script=\"normal\" Underlined=\"no\" Weight=\"normal\""; } - if (first || font_changed || + if (!font || font_changed) { + font = root->add_child ("Font"); + string id = "theFontId"; + if (!_load_font_nodes.empty()) { + id = _load_font_nodes.front()->id; + } + font->set_attribute ("Id", id); + font->set_attribute ("Italic", italic ? "yes" : "no"); + font->set_attribute ("Color", color.to_argb_string()); + font->set_attribute ("Size", lexical_cast<string> (size)); + font->set_attribute ("Effect", effect_to_string (effect)); + font->set_attribute ("EffectColor", effect_color.to_argb_string()); + font->set_attribute ("Script", "normal"); + font->set_attribute ("Underlined", "no"); + font->set_attribute ("Weight", "normal"); + } + + if (!subtitle || font_changed || (last_in != (*i)->in() || last_out != (*i)->out() || last_fade_up_time != (*i)->fade_up_time() || last_fade_down_time != (*i)->fade_down_time() )) { - if (!first) { - s << " </Subtitle>\n"; - } - - if (font_changed) { - if (!first) { - s << " </Font>\n"; - } - - string id = "theFontId"; - if (!_load_font_nodes.empty()) { - id = _load_font_nodes.front()->id; - } - - s << " <Font Id=\"" << id << "\" " << a.str() << ">\n"; - } - - s << " <Subtitle " - << "SpotNumber=\"" << spot_number++ << "\" " - << "TimeIn=\"" << (*i)->in().to_string() << "\" " - << "TimeOut=\"" << (*i)->out().to_string() << "\" " - << "FadeUpTime=\"" << (*i)->fade_up_time().to_ticks() << "\" " - << "FadeDownTime=\"" << (*i)->fade_down_time().to_ticks() << "\"" - << ">\n"; + subtitle = font->add_child ("Subtitle"); + subtitle->set_attribute ("SpotNumber", lexical_cast<string> (spot_number++)); + subtitle->set_attribute ("TimeIn", (*i)->in().to_string()); + subtitle->set_attribute ("TimeOut", (*i)->out().to_string()); + subtitle->set_attribute ("FadeUpTime", lexical_cast<string> ((*i)->fade_up_time().to_ticks())); + subtitle->set_attribute ("FadeDownTime", lexical_cast<string> ((*i)->fade_down_time().to_ticks())); last_in = (*i)->in (); last_out = (*i)->out (); @@ -507,23 +406,12 @@ SubtitleAsset::write_xml (ostream& s) const last_fade_down_time = (*i)->fade_down_time (); } - s << " <Text " - << "VAlign=\"" << valign_to_string ((*i)->v_align()) << "\" " - << "VPosition=\"" << (*i)->v_position() << "\"" - << ">" << escape ((*i)->text()) << "</Text>\n"; - - first = false; + xmlpp::Element* text = subtitle->add_child ("Text"); + text->set_attribute ("VAlign", valign_to_string ((*i)->v_align())); + text->set_attribute ("VPosition", lexical_cast<string> ((*i)->v_position())); + text->add_child_text ((*i)->text()); } - s << " </Subtitle>\n"; - s << " </Font>\n"; - s << "</DCSubtitle>\n"; + doc.write_to_stream_formatted (s, "UTF-8"); } -/** XXX: Another reason why we should be writing with libxml++ */ -string -SubtitleAsset::escape (string s) const -{ - boost::replace_all (s, "&", "&"); - return s; -} diff --git a/src/subtitle_asset.h b/src/subtitle_asset.h index 1e31df2b..2da1ce7b 100644 --- a/src/subtitle_asset.h +++ b/src/subtitle_asset.h @@ -20,71 +20,11 @@ #include "asset.h" #include "xml.h" #include "dcp_time.h" +#include "parse/subtitle.h" namespace libdcp { -class FontNode; - -class TextNode : public XMLNode -{ -public: - TextNode () {} - TextNode (xmlpp::Node const * node); - - float v_position; - VAlign v_align; - std::string text; - std::list<boost::shared_ptr<FontNode> > font_nodes; -}; - -class SubtitleNode : public XMLNode -{ -public: - SubtitleNode () {} - SubtitleNode (xmlpp::Node const * node); - - Time in; - Time out; - Time fade_up_time; - Time fade_down_time; - std::list<boost::shared_ptr<FontNode> > font_nodes; - std::list<boost::shared_ptr<TextNode> > text_nodes; - -private: - Time fade_time (std::string name); -}; - -class FontNode : public XMLNode -{ -public: - FontNode () {} - FontNode (xmlpp::Node const * node); - FontNode (std::list<boost::shared_ptr<FontNode> > const & font_nodes); - - std::string text; - std::string id; - int size; - boost::optional<bool> italic; - boost::optional<Color> color; - boost::optional<Effect> effect; - boost::optional<Color> effect_color; - - std::list<boost::shared_ptr<SubtitleNode> > subtitle_nodes; - std::list<boost::shared_ptr<FontNode> > font_nodes; - std::list<boost::shared_ptr<TextNode> > text_nodes; -}; - -class LoadFontNode : public XMLNode -{ -public: - LoadFontNode () {} - LoadFontNode (xmlpp::Node const * node); - - std::string id; - std::string uri; -}; - class Subtitle { public: @@ -183,7 +123,7 @@ public: SubtitleAsset (std::string directory, std::string xml_file); SubtitleAsset (std::string directory, std::string movie_title, std::string language); - void write_to_cpl (std::ostream&) const; + void write_to_cpl (xmlpp::Node *) const; virtual bool equals (boost::shared_ptr<const Asset>, EqualityOptions, boost::function<void (NoteType, std::string)> note) const { /* XXX */ note (ERROR, "subtitle assets not compared yet"); @@ -203,29 +143,28 @@ public: void read_xml (std::string); void write_xml () const; - void write_xml (std::ostream& s) const; + void write_xml (std::ostream &) const; private: std::string font_id_to_name (std::string id) const; - std::string escape (std::string) const; struct ParseState { - std::list<boost::shared_ptr<FontNode> > font_nodes; - std::list<boost::shared_ptr<TextNode> > text_nodes; - std::list<boost::shared_ptr<SubtitleNode> > subtitle_nodes; + std::list<boost::shared_ptr<parse::Font> > font_nodes; + std::list<boost::shared_ptr<parse::Text> > text_nodes; + std::list<boost::shared_ptr<parse::Subtitle> > subtitle_nodes; }; void maybe_add_subtitle (std::string text, ParseState const & parse_state); void examine_font_nodes ( - boost::shared_ptr<XMLFile> xml, - std::list<boost::shared_ptr<FontNode> > const & font_nodes, + boost::shared_ptr<const cxml::Node> xml, + std::list<boost::shared_ptr<parse::Font> > const & font_nodes, ParseState& parse_state ); void examine_text_nodes ( - boost::shared_ptr<XMLFile> xml, - std::list<boost::shared_ptr<TextNode> > const & text_nodes, + boost::shared_ptr<const cxml::Node> xml, + std::list<boost::shared_ptr<parse::Text> > const & text_nodes, ParseState& parse_state ); @@ -233,7 +172,7 @@ private: /* strangely, this is sometimes a string */ std::string _reel_number; std::string _language; - std::list<boost::shared_ptr<LoadFontNode> > _load_font_nodes; + std::list<boost::shared_ptr<parse::LoadFont> > _load_font_nodes; std::list<boost::shared_ptr<Subtitle> > _subtitles; bool _need_sort; diff --git a/src/types.h b/src/types.h index b1de4a0f..edabb9e2 100644 --- a/src/types.h +++ b/src/types.h @@ -100,12 +100,14 @@ struct EqualityOptions { : max_mean_pixel_error (0) , max_std_dev_pixel_error (0) , max_audio_sample_error (0) + , cpl_names_can_differ (false) , mxf_names_can_differ (false) {} double max_mean_pixel_error; double max_std_dev_pixel_error; int max_audio_sample_error; + bool cpl_names_can_differ; bool mxf_names_can_differ; }; diff --git a/src/wscript b/src/wscript index 81c39926..37151e51 100644 --- a/src/wscript +++ b/src/wscript @@ -1,5 +1,5 @@ def build(bld): - if bld.env.STATIC_LIBDCP: + if bld.env.STATIC: obj = bld(features = 'cxx cxxstlib') else: obj = bld(features = 'cxx cxxshlib') @@ -7,12 +7,10 @@ def build(bld): obj.name = 'libdcp' obj.target = 'dcp' obj.export_includes = ['.'] - obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 OPENSSL SIGC++ LIBXML++ OPENJPEG' + obj.uselib = 'BOOST_FILESYSTEM BOOST_SIGNALS2 OPENSSL SIGC++ LIBXML++ OPENJPEG CXML' obj.use = 'libkumu-libdcp libasdcp-libdcp' obj.source = """ asset.cc - asset_map.cc - cpl_file.cc dcp.cc cpl.cc dcp_time.cc @@ -21,7 +19,6 @@ def build(bld): mxf_asset.cc picture_asset.cc picture_frame.cc - pkl_file.cc reel.cc argb_frame.cc sound_asset.cc @@ -30,7 +27,10 @@ def build(bld): types.cc util.cc version.cc - xml.cc + parse/asset_map.cc + parse/cpl.cc + parse/pkl.cc + parse/subtitle.cc """ headers = """ @@ -51,9 +51,9 @@ def build(bld): types.h util.h version.h - xml.h """ bld.install_files('${PREFIX}/include/libdcp', headers) - if bld.env.STATIC_LIBDCP: + if bld.env.STATIC: bld.install_files('${PREFIX}/lib', 'libdcp.a') + diff --git a/src/xml.cc b/src/xml.cc deleted file mode 100644 index 508790ab..00000000 --- a/src/xml.cc +++ /dev/null @@ -1,263 +0,0 @@ -#include <sstream> -#include <iostream> -#include <boost/lexical_cast.hpp> -#include <boost/filesystem.hpp> -#include <boost/algorithm/string.hpp> -#include <libxml++/libxml++.h> -#include "xml.h" -#include "exceptions.h" -#include "util.h" - -using namespace std; -using namespace boost; -using namespace libdcp; - -XMLNode::XMLNode () - : _node (0) -{ - -} - -XMLNode::XMLNode (xmlpp::Node const * node) - : _node (node) -{ - -} - -xmlpp::Node * -XMLNode::node_child (string name) -{ - list<xmlpp::Node*> n = node_children (name); - if (n.size() > 1) { - boost::throw_exception (XMLError ("duplicate XML tag " + name)); - } else if (n.empty ()) { - boost::throw_exception (XMLError ("missing XML tag " + name + " in " + _node->get_name())); - } - - return n.front (); -} - -list<xmlpp::Node*> -XMLNode::node_children (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_child (string name) -{ - return XMLNode (node_child (name)).content (); -} - -string -XMLNode::optional_string_child (string name) -{ - list<xmlpp::Node*> nodes = node_children (name); - if (nodes.size() > 2) { - boost::throw_exception (XMLError ("duplicate XML tag " + name)); - } - - if (nodes.empty ()) { - return ""; - } - - return string_child (name); -} - -ContentKind -XMLNode::kind_child (string name) -{ - return content_kind_from_string (string_child (name)); -} - -Fraction -XMLNode::fraction_child (string name) -{ - return Fraction (string_child (name)); -} - -int64_t -XMLNode::int64_child (string name) -{ - string s = string_child (name); - erase_all (s, " "); - return lexical_cast<int64_t> (s); -} - -int64_t -XMLNode::optional_int64_child (string name) -{ - list<xmlpp::Node*> nodes = node_children (name); - if (nodes.size() > 2) { - boost::throw_exception (XMLError ("duplicate XML tag " + name)); - } - - if (nodes.empty ()) { - return 0; - } - - return int64_child (name); -} - -float -XMLNode::float_child (string name) -{ - return lexical_cast<float> (string_child (name)); -} - -void -XMLNode::ignore_child (string name) -{ - _taken.push_back (name); -} - -Time -XMLNode::time_attribute (string name) -{ - return Time (string_attribute (name)); -} - -string -XMLNode::string_attribute (string name) -{ - xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node); - if (!e) { - boost::throw_exception (XMLError ("missing attribute")); - } - - xmlpp::Attribute* a = e->get_attribute (name); - if (!a) { - boost::throw_exception (XMLError ("missing attribute")); - } - - return a->get_value (); -} - -string -XMLNode::optional_string_attribute (string name) -{ - xmlpp::Element const * e = dynamic_cast<const xmlpp::Element *> (_node); - if (!e) { - return ""; - } - - xmlpp::Attribute* a = e->get_attribute (name); - if (!a) { - return ""; - } - - return a->get_value (); -} - -float -XMLNode::float_attribute (string name) -{ - return lexical_cast<float> (string_attribute (name)); -} - -int64_t -XMLNode::int64_attribute (string name) -{ - return lexical_cast<int64_t> (string_attribute (name)); -} - -int64_t -XMLNode::optional_int64_attribute (string name) -{ - string const s = optional_string_attribute (name); - if (s.empty ()) { - return 0; - } - - return lexical_cast<int64_t> (s); -} - -optional<bool> -XMLNode::optional_bool_attribute (string name) -{ - string const s = optional_string_attribute (name); - if (s.empty ()) { - return optional<bool> (); - } - - if (s == "1" || s == "yes") { - return optional<bool> (true); - } - - return optional<bool> (false); -} - -optional<Color> -XMLNode::optional_color_attribute (string name) -{ - string const s = optional_string_attribute (name); - if (s.empty ()) { - return optional<Color> (); - } - - return optional<Color> (Color (s)); -} - -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 ()) { - boost::throw_exception (XMLError ("unexpected XML node " + (*i)->get_name())); - } - } -} - -string -XMLNode::content () -{ - string content; - - xmlpp::Node::NodeList c = _node->get_children (); - for (xmlpp::Node::NodeList::const_iterator i = c.begin(); i != c.end(); ++i) { - xmlpp::ContentNode const * v = dynamic_cast<xmlpp::ContentNode const *> (*i); - if (v) { - content += v->get_content (); - } - } - - return content; -} - -XMLFile::XMLFile (string file, string root_name) -{ - if (!filesystem::exists (file)) { - boost::throw_exception (FileError ("XML file does not exist", file)); - } - - _parser = new xmlpp::DomParser; - _parser->parse_file (file); - if (!_parser) { - boost::throw_exception (XMLError ("could not parse XML")); - } - - _node = _parser->get_document()->get_root_node (); - if (_node->get_name() != root_name) { - boost::throw_exception (XMLError ("unrecognised root node")); - } -} - -XMLFile::~XMLFile () -{ - delete _parser; -} @@ -1,103 +1,91 @@ -#ifndef LIBDCP_XML_H -#define LIBDCP_XML_H +/* + Copyright (C) 2013 Carl Hetherington <cth@carlh.net> -#include <string> -#include <list> -#include <stdint.h> -#include <glibmm.h> -#include <boost/shared_ptr.hpp> -#include <boost/optional.hpp> -#include "types.h" -#include "exceptions.h" -#include "dcp_time.h" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -namespace xmlpp { - class Node; - class DomParser; -} + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -namespace libdcp { + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -/** @brief A helper class for XML nodes */ -class XMLNode -{ -public: - XMLNode (); - XMLNode (xmlpp::Node const * node); +*/ - std::string string_child (std::string); - std::string optional_string_child (std::string); - ContentKind kind_child (std::string); - Fraction fraction_child (std::string); - int64_t int64_child (std::string); - int64_t optional_int64_child (std::string); - float float_child (std::string); - void ignore_child (std::string); - void done (); +#ifndef LIBDCP_XML_H +#define LIBDCP_XML_H - Time time_attribute (std::string); - float float_attribute (std::string); - std::string string_attribute (std::string); - std::string optional_string_attribute (std::string); - int64_t int64_attribute (std::string); - int64_t optional_int64_attribute (std::string); - boost::optional<bool> optional_bool_attribute (std::string); - boost::optional<Color> optional_color_attribute (std::string); +#include <libcxml/cxml.h> +#include "exceptions.h" - std::string content (); +namespace libdcp +{ - template <class T> - boost::shared_ptr<T> type_child (std::string name) { - return boost::shared_ptr<T> (new T (node_child (name))); +template <class T> +boost::shared_ptr<T> +optional_type_child (cxml::Node const & node, std::string name) +{ + std::list<boost::shared_ptr<cxml::Node> > n = node.node_children (name); + if (n.size() > 1) { + throw XMLError ("duplicate XML tag"); + } else if (n.empty ()) { + return boost::shared_ptr<T> (); } - template <class T> - boost::shared_ptr<T> optional_type_child (std::string name) { - std::list<xmlpp::Node*> n = node_children (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 ())); - } + return boost::shared_ptr<T> (new T (n.front ())); +} + +template <class T> +boost::shared_ptr<T> type_child (boost::shared_ptr<const cxml::Node> node, std::string name) { + return boost::shared_ptr<T> (new T (node->node_child (name))); +} - template <class T> - std::list<boost::shared_ptr<T> > type_children (std::string name) { - std::list<xmlpp::Node*> n = node_children (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; - } +template <class T> +boost::shared_ptr<T> +optional_type_child (boost::shared_ptr<const cxml::Node> node, std::string name) +{ + return optional_type_child<T> (*node.get(), name); +} - template <class T> - std::list<boost::shared_ptr<T> > type_grand_children (std::string name, std::string sub) { - XMLNode p (node_child (name)); - return p.type_children<T> (sub); +template <class T> +std::list<boost::shared_ptr<T> > +type_children (cxml::Node const & node, std::string name) +{ + std::list<boost::shared_ptr<cxml::Node> > n = node.node_children (name); + std::list<boost::shared_ptr<T> > r; + for (typename std::list<boost::shared_ptr<cxml::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* node_child (std::string); - std::list<xmlpp::Node*> node_children (std::string); - std::list<Glib::ustring> _taken; -}; - -/** @brief A helper class for XML files */ -class XMLFile : public XMLNode +template <class T> +std::list<boost::shared_ptr<T> > +type_children (boost::shared_ptr<const cxml::Node> node, std::string name) { -public: - XMLFile (std::string file, std::string root_name); - virtual ~XMLFile (); - -private: - xmlpp::DomParser* _parser; -}; + return type_children<T> (*node.get(), name); +} + +template <class T> +std::list<boost::shared_ptr<T> > +type_grand_children (cxml::Node const & node, std::string name, std::string sub) +{ + boost::shared_ptr<const cxml::Node> p = node.node_child (name); + return type_children<T> (p, sub); +} +template <class T> +std::list<boost::shared_ptr<T> > +type_grand_children (boost::shared_ptr<const cxml::Node> node, std::string name, std::string sub) +{ + return type_grand_children<T> (*node.get(), name, sub); +} + } #endif |
