summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asset.cc37
-rw-r--r--src/asset.h7
-rw-r--r--src/cpl.cc95
-rw-r--r--src/cpl.h12
-rw-r--r--src/cpl_file.cc148
-rw-r--r--src/dcp.cc109
-rw-r--r--src/dcp.h1
-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.cc147
-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.cc135
-rw-r--r--src/parse/subtitle.h93
-rw-r--r--src/picture_asset.cc21
-rw-r--r--src/picture_asset.h6
-rw-r--r--src/reel.cc17
-rw-r--r--src/reel.h3
-rw-r--r--src/sound_asset.cc17
-rw-r--r--src/sound_asset.h6
-rw-r--r--src/subtitle_asset.cc252
-rw-r--r--src/subtitle_asset.h83
-rw-r--r--src/types.h2
-rw-r--r--src/wscript16
-rw-r--r--src/xml.cc263
-rw-r--r--src/xml.h156
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;
diff --git a/src/cpl.cc b/src/cpl.cc
index 10a83078..fd705680 100644
--- a/src/cpl.cc
+++ b/src/cpl.cc
@@ -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;
}
diff --git a/src/cpl.h b/src/cpl.h
index 0abff749..0c86b91e 100644
--- a/src/cpl.h
+++ b/src/cpl.h
@@ -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 ();
-}
diff --git a/src/dcp.cc b/src/dcp.cc
index 7af3f353..c7634b5d 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -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));
}
diff --git a/src/dcp.h b/src/dcp.h
index 42c0c6d9..eea043dd 100644
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -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
diff --git a/src/reel.h b/src/reel.h
index 93dc0920..49a756ad 100644
--- a/src/reel.h
+++ b/src/reel.h
@@ -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, "&", "&amp;");
- 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;
-}
diff --git a/src/xml.h b/src/xml.h
index 6fc0d0fa..5978ff7e 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -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