Use libxml++ for writing XML.
authorCarl Hetherington <cth@carlh.net>
Mon, 13 May 2013 14:57:00 +0000 (15:57 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 13 May 2013 14:57:00 +0000 (15:57 +0100)
13 files changed:
src/asset.cc
src/asset.h
src/cpl.cc
src/cpl.h
src/dcp.cc
src/picture_asset.cc
src/picture_asset.h
src/reel.cc
src/reel.h
src/sound_asset.cc
src/sound_asset.h
src/subtitle_asset.cc
src/subtitle_asset.h

index 58c821a7c9f370d056283e4039be2f74abb29e27..84bdd2bd4bbe68dfeffcb2892e559e06ab77723f 100644 (file)
@@ -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
index 06c6635636141882b35dc11fab5895ce1e16e2c5..3bc713a38b4b29450bfae79e3111151b890cca0f 100644 (file)
@@ -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;
index 3a2ad0b34014683b8ab916237ec51b3bebf2276a..e7eb1ced914355f79964e16feaf884158893a308 100644 (file)
@@ -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)
@@ -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));
 }
        
        
index c04fd6addd5390c7c6f48828fff563e1d7554dd4..0c86b91e0547a941ea3a80fe7e3152f103a6f5d3 100644 (file)
--- a/src/cpl.h
+++ b/src/cpl.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 {
@@ -74,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;
index 7a43e9b23e38219483577d8bdf7956f315444b48..c7634b5d3385d1a9cafd5b847dffd41dd4540d66 100644 (file)
@@ -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"
@@ -48,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)
@@ -80,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 ();
 }
 
@@ -113,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
@@ -127,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");
 }
 
 
index 788e3dc4fa383119a1b315dad0c9d6a3eec10cd0..72a6317368aa2d82a839a662d9fdc5e6a0049bd1 100644 (file)
@@ -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
index 59c4dc001820468963e16d86794ac82c65fdbb09..3edf3a1ce8c5fc4f7686468e4c8e88e8d2c2b66b 100644 (file)
@@ -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;
 
index 86533ea2e8e26a204b45bd42bfd9d1dacf943515..481b153b93176b6ace07f099d7b203dc367d5ad6 100644 (file)
@@ -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
index 93dc09206ffc998b2af2aeb44edceaa3a8432d24..49a756adc1206bccb63e57a51d11c424b48dc4a8 100644 (file)
@@ -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;
 
index 9b6b48aa06bb2fa698de854127dc701f7d371b4f..4a7abd4dd4de7a81ba4a343d8d71e750c4154f5a 100644 (file)
@@ -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
index 5c230e06848805ab114bc032a734a32983d78d54..1e3553a0f48338af33fcf1fd08bbdf0a79c63f91 100644 (file)
@@ -127,10 +127,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;
 
index d89d52de978b7814e780a7d8ae3fc8d05c25c596..5decc1e37a7ae485657543a1968be8ae54c42c1e 100644 (file)
@@ -276,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 {
@@ -299,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;
@@ -329,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;
@@ -341,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 ||
                    (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 ();
@@ -408,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);
 }
 
-/** XXX: Another reason why we should be writing with libxml++ */
-string
-SubtitleAsset::escape (string s) const
-{
-       boost::replace_all (s, "&", "&amp;");
-       return s;
-}
index 0d662d6c3fa0ef3644d2dacd8d29614bf8066916..2da1ce7b8f9b7ae6f0c3090428a4b6351bdd027d 100644 (file)
@@ -123,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");
@@ -143,11 +143,10 @@ 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<parse::Font> > font_nodes;