{
/* Read the ASSETMAP and PKL */
- boost::filesystem::path asset_map_file;
if (boost::filesystem::exists (_directory / "ASSETMAP")) {
- asset_map_file = _directory / "ASSETMAP";
+ _asset_map = _directory / "ASSETMAP";
} else if (boost::filesystem::exists (_directory / "ASSETMAP.xml")) {
- asset_map_file = _directory / "ASSETMAP.xml";
+ _asset_map = _directory / "ASSETMAP.xml";
} else {
boost::throw_exception (DCPReadError (String::compose ("could not find ASSETMAP nor ASSETMAP.xml in `%1'", _directory.string())));
}
cxml::Document asset_map ("AssetMap");
- asset_map.read_file (asset_map_file);
+ asset_map.read_file (_asset_map.get());
if (asset_map.namespace_uri() == assetmap_interop_ns) {
_standard = INTEROP;
} else if (asset_map.namespace_uri() == assetmap_smpte_ns) {
}
doc.write_to_file_formatted (p.string (), "UTF-8");
+ _asset_map = p;
}
/** Write all the XML files for this DCP.
return _pkls;
}
+ boost::optional<boost::filesystem::path> asset_map_path () {
+ return _asset_map;
+ }
+
static std::vector<boost::filesystem::path> directories_from_files (std::vector<boost::filesystem::path> files);
private:
*/
void write_assetmap (Standard standard, std::string pkl_uuid, boost::filesystem::path pkl_path, XMLMetadata metadata) const;
- /** the directory that we are writing to */
+ /** The directory that we are writing to */
boost::filesystem::path _directory;
- /** the CPLs that make up this DCP */
+ /** The CPLs that make up this DCP */
std::list<boost::shared_ptr<CPL> > _cpls;
+ /** The PKLs that make up this DCP */
std::list<boost::shared_ptr<PKL> > _pkls;
+ /** File that the ASSETMAP was read from or last written to */
+ mutable boost::optional<boost::filesystem::path> _asset_map;
/** Standard of DCP that was read in */
boost::optional<Standard> _standard;
};
static
-list<XMLValidationError>
-validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_directory)
+void
+validate_xml (boost::filesystem::path xml_file, boost::filesystem::path xsd_dtd_directory, list<VerificationNote>& notes)
{
try {
XMLPlatformUtils::Initialize ();
schema["http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"] = "xmldsig-core-schema.xsd";
schema["http://www.smpte-ra.org/schemas/429-7/2006/CPL"] = "SMPTE-429-7-2006-CPL.xsd";
schema["http://www.smpte-ra.org/schemas/429-8/2006/PKL"] = "SMPTE-429-8-2006-PKL.xsd";
+ schema["http://www.smpte-ra.org/schemas/429-9/2007/AM"] = "SMPTE-429-9-2007-AM.xsd";
schema["http://www.w3.org/2001/03/xml.xsd"] = "xml.xsd";
string locations;
XMLPlatformUtils::Terminate ();
- return error_handler.errors ();
+ BOOST_FOREACH (XMLValidationError i, error_handler.errors()) {
+ notes.push_back (
+ VerificationNote(
+ VerificationNote::VERIFY_ERROR,
+ VerificationNote::Code::XML_VALIDATION_ERROR,
+ i.message(),
+ xml_file,
+ i.line()
+ )
+ );
+ }
}
static Result
BOOST_FOREACH (shared_ptr<CPL> cpl, dcp->cpls()) {
stage ("Checking CPL", cpl->file());
-
- list<XMLValidationError> errors = validate_xml (cpl->file().get(), xsd_dtd_directory);
- BOOST_FOREACH (XMLValidationError i, errors) {
- notes.push_back (
- VerificationNote(
- VerificationNote::VERIFY_ERROR,
- VerificationNote::Code::XML_VALIDATION_ERROR,
- i.message(),
- cpl->file().get(),
- i.line()
- )
- );
- }
+ validate_xml (cpl->file().get(), xsd_dtd_directory, notes);
/* Check that the CPL's hash corresponds to the PKL */
BOOST_FOREACH (shared_ptr<PKL> i, dcp->pkls()) {
BOOST_FOREACH (shared_ptr<PKL> pkl, dcp->pkls()) {
stage ("Checking PKL", pkl->file());
-
- list<XMLValidationError> errors = validate_xml (pkl->file().get(), xsd_dtd_directory);
- BOOST_FOREACH (XMLValidationError i, errors) {
- notes.push_back (
- VerificationNote(
- VerificationNote::VERIFY_ERROR,
- VerificationNote::Code::XML_VALIDATION_ERROR,
- i.message(),
- pkl->file().get(),
- i.line()
- )
- );
- }
+ validate_xml (pkl->file().get(), xsd_dtd_directory, notes);
}
+
+ stage ("Checking ASSETMAP", dcp->asset_map_path().get());
+ validate_xml (dcp->asset_map_path().get(), xsd_dtd_directory, notes);
+
}
return notes;
boost::filesystem::path const cpl_file = "build/test/verify_test1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml";
boost::filesystem::path const pkl_file = "build/test/verify_test1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml";
+ boost::filesystem::path const assetmap_file = "build/test/verify_test1/ASSETMAP.xml";
list<pair<string, optional<boost::filesystem::path> > >::const_iterator st = stages.begin();
BOOST_CHECK_EQUAL (st->first, "Checking DCP");
BOOST_REQUIRE (st->second);
BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(pkl_file));
++st;
+ BOOST_CHECK_EQUAL (st->first, "Checking ASSETMAP");
+ BOOST_REQUIRE (st->second);
+ BOOST_CHECK_EQUAL (st->second.get(), boost::filesystem::canonical(assetmap_file));
+ ++st;
BOOST_REQUIRE (st == stages.end());
dump_notes (notes);
return dcp::String::compose("build/test/verify_test%1/cpl_81fb54df-e1bf-4647-8788-ea7ba154375b.xml", n);
}
+static
+boost::filesystem::path
+pkl (int n)
+{
+ return dcp::String::compose("build/test/verify_test%1/pkl_ae8a9818-872a-4f86-8493-11dfdea03e09.xml", n);
+}
+
+static
+boost::filesystem::path
+asset_map (int n)
+{
+ return dcp::String::compose("build/test/verify_test%1/ASSETMAP.xml", n);
+}
+
static
void check_after_replace (int n, boost::function<boost::filesystem::path (int)> file, string from, string to, dcp::VerificationNote::Code code1)
{
dcp::VerificationNote::Code::CPL_HASH_INCORRECT
);
}
+
+/* Badly-formatted <Id> in PKL */
+BOOST_AUTO_TEST_CASE (verify_test11)
+{
+ check_after_replace (
+ 11, &pkl,
+ "<Id>urn:uuid:ae8", "<Id>urn:uuid:xe8",
+ dcp::VerificationNote::Code::XML_VALIDATION_ERROR
+ );
+}
+
+/* Badly-formatted <Id> in ASSETMAP */
+BOOST_AUTO_TEST_CASE (verify_test12)
+{
+ check_after_replace (
+ 12, &asset_map,
+ "<Id>urn:uuid:74e", "<Id>urn:uuid:x4e",
+ dcp::VerificationNote::Code::XML_VALIDATION_ERROR
+ );
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema targetNamespace="http://www.smpte-ra.org/schemas/429-9/2007/AM" xmlns:am="http://www.smpte-ra.org/schemas/429-9/2007/AM" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
+
+ <xs:simpleType name="UUID">
+ <xs:restriction base="xs:anyURI">
+ <xs:pattern value="urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="UserText">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="language" type="xs:language" use="optional" default="en"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:complexType name="ChunkType">
+ <xs:sequence>
+ <xs:element name="Path" type="xs:anyURI"/>
+ <xs:element name="VolumeIndex" type="xs:positiveInteger" minOccurs="0"/>
+ <xs:element name="Offset" type="xs:nonNegativeInteger" minOccurs="0"/>
+ <xs:element name="Length" type="xs:positiveInteger" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="AssetType">
+ <xs:sequence>
+ <xs:element name="Id" type="am:UUID"/>
+ <xs:element name="AnnotationText" type="am:UserText" minOccurs="0"/>
+ <xs:element name="PackingList" type="xs:boolean" minOccurs="0"/>
+ <xs:element name="ChunkList">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Chunk" type="am:ChunkType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="AssetMapType">
+ <xs:sequence>
+ <xs:element name="Id" type="am:UUID"/>
+ <xs:element name="AnnotationText" type="am:UserText" minOccurs="0"/>
+ <xs:element name="Creator" type="am:UserText"/>
+ <xs:element name="VolumeCount" type="xs:positiveInteger"/>
+ <xs:element name="IssueDate" type="xs:dateTime"/>
+ <xs:element name="Issuer" type="am:UserText"/>
+ <xs:element name="AssetList">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="Asset" type="am:AssetType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:element name="AssetMap" type="am:AssetMapType"/>
+
+ <xs:complexType name="VolumeIndexType">
+ <xs:sequence>
+ <xs:element name="Index" type="xs:positiveInteger"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:element name="VolumeIndex" type="am:VolumeIndexType"/>
+
+</xs:schema>
+