Use regex and check <IssueDate> in CPL.
authorCarl Hetherington <cth@carlh.net>
Fri, 6 Dec 2019 16:40:25 +0000 (17:40 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 22 Dec 2019 00:21:00 +0000 (01:21 +0100)
examples/wscript
src/verify.cc
src/verify.h
test/verify_test.cc
test/wscript
tools/wscript
wscript

index a71a215b660d6e5343f87c69e92c55259f69430c..46ee6c5ab981c90e54a0c02112c4116af9067ea5 100644 (file)
@@ -20,7 +20,7 @@ def build(bld):
     obj = bld(features='cxx cxxprogram')
     obj.name   = 'make_dcp'
     obj.use    = 'libdcp%s' % bld.env.API_VERSION
-    obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM'
+    obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM BOOST_REGEX'
     obj.source = 'make_dcp.cc'
     obj.target = 'make_dcp'
     obj.install_path = ''
@@ -28,7 +28,7 @@ def build(bld):
     obj = bld(features='cxx cxxprogram')
     obj.name   = 'read_dcp'
     obj.use    = 'libdcp%s' % bld.env.API_VERSION
-    obj.uselib = 'OPENJPEG CXML MAGICK OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM'
+    obj.uselib = 'OPENJPEG CXML MAGICK OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM BOOST_REGEX'
     obj.source = 'read_dcp.cc'
     obj.target = 'read_dcp'
     obj.install_path = ''
index f4b89afd45df30d670fc6111388600f9224e078a..032a3f3969c944de9e10d8996d3aec691d8e322a 100644 (file)
 #include "reel_sound_asset.h"
 #include "exceptions.h"
 #include "compose.hpp"
+#include "raw_convert.h"
 #include <boost/foreach.hpp>
 #include <boost/algorithm/string.hpp>
+#include <boost/regex.hpp>
 #include <list>
 #include <vector>
 #include <iostream>
@@ -96,37 +98,44 @@ verify_asset (shared_ptr<DCP> dcp, shared_ptr<ReelMXF> reel_mxf, function<void (
 
 static
 bool
-hex (string s)
+good_urn_uuid (string id)
 {
-       for (size_t i = 0; i < s.length(); ++i) {
-               if (string("0123456789abcdef").find(s[i]) == string::npos) {
-                       return false;
-               }
-       }
-
-       return true;
+       boost::regex ex("urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
+       return boost::regex_match (id, ex);
 }
 
 static
 bool
-good_urn_uuid (string id)
+good_date (string date)
 {
-       if (id.length() != 45) {
+       boost::regex ex("\\d{4}-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})[+-](\\d{2}):(\\d{2})");
+       boost::match_results<string::const_iterator> res;
+       if (!regex_match (date, res, ex, boost::match_default)) {
                return false;
        }
-
-       if (!boost::algorithm::starts_with(id, "urn:uuid:")) {
+       int const month = dcp::raw_convert<int>(res[1].str());
+       if (month < 1 || month > 12) {
                return false;
        }
-
-       if (id[17] != '-' || id[22] != '-' || id[27] != '-' || id[32] != '-') {
+       int const day = dcp::raw_convert<int>(res[2].str());
+       if (day < 1 || day > 31) {
                return false;
        }
-
-       if (!hex(id.substr(9, 8)) || !hex(id.substr(18, 4)) || !hex(id.substr(23, 4)) || !hex(id.substr(28, 4)) || !hex(id.substr(33, 8))) {
+       if (dcp::raw_convert<int>(res[3].str()) > 23) {
+               return false;
+       }
+       if (dcp::raw_convert<int>(res[4].str()) > 59) {
+               return false;
+       }
+       if (dcp::raw_convert<int>(res[5].str()) > 59) {
+               return false;
+       }
+       if (dcp::raw_convert<int>(res[6].str()) > 23) {
+               return false;
+       }
+       if (dcp::raw_convert<int>(res[7].str()) > 59) {
                return false;
        }
-
        return true;
 }
 
@@ -158,6 +167,9 @@ dcp::verify (vector<boost::filesystem::path> directories, function<void (string,
                        if (!good_urn_uuid(cpl_doc.string_child("Id"))) {
                                notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::Code::BAD_URN_UUID, string("CPL <Id> is malformed")));
                        }
+                       if (!good_date(cpl_doc.string_child("IssueDate"))) {
+                               notes.push_back (VerificationNote(VerificationNote::VERIFY_ERROR, VerificationNote::Code::BAD_DATE, string("CPL <IssueDate> is malformed")));
+                       }
 
                        /* Check that the CPL's hash corresponds to the PKL */
                        BOOST_FOREACH (shared_ptr<PKL> i, dcp->pkls()) {
@@ -252,7 +264,9 @@ dcp::note_to_string (dcp::VerificationNote note)
        case dcp::VerificationNote::MISMATCHED_STANDARD:
                return "The DCP contains both SMPTE and Interop parts.";
        case dcp::VerificationNote::BAD_URN_UUID:
-               return "There is a badly formed urn:uuid.";
+               return "There is a badly-formed urn:uuid.";
+       case dcp::VerificationNote::BAD_DATE:
+               return "There is a badly-formed date.";
        }
 
        return "";
index 1403797c709e09a2fa9500063876bd39ce671b35..4007f8fbbc1eb9ca975f792354e0f4bc3e0f0092 100644 (file)
@@ -77,6 +77,8 @@ public:
                MISMATCHED_STANDARD,
                /** A urn:uuid ID is badly formed */
                BAD_URN_UUID,
+               /** A date is badly formed */
+               BAD_DATE,
        };
 
        VerificationNote (Type type, Code code)
index 4a28a87706cff7937ae7df3516df62a84304627c..1e9f8aa41fd307a6f23abb3a334d7449f8249cd2 100644 (file)
@@ -307,3 +307,13 @@ BOOST_AUTO_TEST_CASE (verify_test9)
                        );
 }
 
+/* Badly formatted <IssueDate> in CPL */
+BOOST_AUTO_TEST_CASE (verify_test10)
+{
+       check_after_replace (
+                       10, &cpl,
+                       "<IssueDate>", "<IssueDate>x",
+                       dcp::VerificationNote::Code::BAD_DATE,
+                       dcp::VerificationNote::Code::CPL_HASH_INCORRECT
+                       );
+}
index 5bfe5bb860491ecc17975844defbacebba974866..ba2d3092ef6c4a07ccfc01b6eab6c7de6f2ba1e1 100644 (file)
@@ -39,7 +39,7 @@ def configure(conf):
 
     conf.check_cxx(fragment="""
                             #define BOOST_TEST_MODULE Config test\n
-                           #include <boost/test/unit_test.hpp>\n
+                            #include <boost/test/unit_test.hpp>\n
                             int main() {}
                             """,
                    msg='Checking for boost unit testing library',
@@ -51,7 +51,7 @@ def configure(conf):
 def build(bld):
     obj = bld(features='cxx cxxprogram')
     obj.name   = 'tests'
-    obj.uselib = 'BOOST_TEST BOOST_FILESYSTEM BOOST_DATETIME OPENJPEG CXML XMLSEC1 SNDFILE OPENMP ASDCPLIB_CTH LIBXML++ OPENSSL'
+    obj.uselib = 'BOOST_TEST BOOST_FILESYSTEM BOOST_DATETIME BOOST_REGEX OPENJPEG CXML XMLSEC1 SNDFILE OPENMP ASDCPLIB_CTH LIBXML++ OPENSSL'
     obj.cppflags = ['-fno-inline', '-fno-default-inline', '-fno-elide-constructors', '-g', '-O0']
     if bld.is_defined('HAVE_GCOV'):
         obj.use = 'libdcp%s_gcov' % bld.env.API_VERSION
@@ -106,7 +106,7 @@ def build(bld):
 
     obj = bld(features='cxx cxxprogram')
     obj.name   = 'subs_in_out'
-    obj.uselib = 'BOOST_TEST BOOST_FILESYSTEM OPENJPEG CXML OPENMP ASDCPLIB_CTH XMLSEC1 OPENSSL'
+    obj.uselib = 'BOOST_TEST BOOST_FILESYSTEM BOOST_REGEX OPENJPEG CXML OPENMP ASDCPLIB_CTH XMLSEC1 OPENSSL'
     obj.cppflags = ['-fno-inline', '-fno-default-inline', '-fno-elide-constructors', '-g', '-O0']
     if bld.is_defined('HAVE_GCOV'):
         obj.use = 'libdcp%s_gcov' % bld.env.API_VERSION
@@ -121,7 +121,7 @@ def build(bld):
 
     obj = bld(features='cxx cxxprogram')
     obj.name   = 'rewrite_subs'
-    obj.uselib = 'BOOST_TEST BOOST_FILESYSTEM OPENJPEG CXML OPENMP ASDCPLIB_CTH XMLSEC1 OPENSSL'
+    obj.uselib = 'BOOST_TEST BOOST_FILESYSTEM BOOST_REGEX OPENJPEG CXML OPENMP ASDCPLIB_CTH XMLSEC1 OPENSSL'
     obj.cppflags = ['-fno-inline', '-fno-default-inline', '-fno-elide-constructors', '-g', '-O0']
     if bld.is_defined('HAVE_GCOV'):
         obj.use = 'libdcp%s_gcov' % bld.env.API_VERSION
@@ -136,7 +136,7 @@ def build(bld):
 
     obj = bld(features='cxx cxxprogram')
     obj.name   = 'bench'
-    obj.uselib = 'BOOST_FILESYSTEM OPENJPEG CXML OPENMP ASDCPLIB_CTH XMLSEC1 OPENSSL LIBXML++'
+    obj.uselib = 'BOOST_FILESYSTEM BOOST_REGEX OPENJPEG CXML OPENMP ASDCPLIB_CTH XMLSEC1 OPENSSL LIBXML++'
     obj.use = 'libdcp%s' % bld.env.API_VERSION
     obj.source = 'bench.cc'
     obj.target = 'bench'
index 73c58f3020c458f2d1ab1178108f2cef8f98af6b..7d0f6630c299f660677c9774a96fb7c1521481cf 100644 (file)
 def build(bld):
     obj = bld(features='cxx cxxprogram')
     obj.use = ['libdcp%s' % bld.env.API_VERSION]
-    obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM LIBXML++ XMLSEC1 OPENSSL'
+    obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM BOOST_REGEX LIBXML++ XMLSEC1 OPENSSL'
     obj.source = 'dcpdiff.cc common.cc'
     obj.target = 'dcpdiff'
 
     obj = bld(features='cxx cxxprogram')
     obj.use = ['libdcp%s' % bld.env.API_VERSION]
-    obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM LIBXML++ XMLSEC1 OPENSSL'
+    obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM BOOST_REGEX LIBXML++ XMLSEC1 OPENSSL'
     obj.source = 'dcpinfo.cc common.cc'
     obj.target = 'dcpinfo'
 
     for f in ['dumpsub', 'decryptmxf', 'kdm', 'thumb', 'recover', 'verify']:
         obj = bld(features='cxx cxxprogram')
         obj.use = ['libdcp%s' % bld.env.API_VERSION]
-        obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM LIBXML++ XMLSEC1 OPENSSL'
+        obj.uselib = 'OPENJPEG CXML OPENMP ASDCPLIB_CTH BOOST_FILESYSTEM BOOST_REGEX LIBXML++ XMLSEC1 OPENSSL'
         obj.source = 'dcp%s.cc' % f
         obj.target = 'dcp%s' % f
diff --git a/wscript b/wscript
index e5e416edb1a2351d85cc0d8c4fec64105e161d78..111eb5f00c0d06e6a4122bf21cb15cae7c20f033 100644 (file)
--- a/wscript
+++ b/wscript
@@ -195,6 +195,15 @@ def configure(conf):
                    libpath='/usr/local/lib',
                    lib=['boost_date_time%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
                    uselib_store='BOOST_DATETIME')
+    
+    conf.check_cxx(fragment="""
+                           #include <boost/regex.hpp>\n
+                           int main() { boost::regex ex("a"); }\n
+                           """,
+                   msg='Checking for boost regex library',
+                   libpath='/usr/local/lib',
+                   lib=['boost_regex%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix],
+                   uselib_store='BOOST_REGEX')
 
     if not conf.env.DISABLE_TESTS:
         conf.recurse('test')