Add OK note when content version label text is valid.
[libdcp.git] / src / verify.h
index d565abfa6f3b7230cbf11b66eefeb8c347374728..081007c98525df1f5b66f3e0f973cd57885da8e6 100644 (file)
 #define LIBDCP_VERIFY_H
 
 
+#include "decrypted_kdm.h"
+#include <boost/any.hpp>
 #include <boost/filesystem.hpp>
 #include <boost/function.hpp>
 #include <boost/optional.hpp>
+#include <map>
 #include <string>
 #include <vector>
 
 
-/* Something in windows.h defines this */
+/* windows.h defines this but we want to use it */
 #undef ERROR
 
 
 namespace dcp {
 
 
+class DCP;
+
+
 class VerificationNote
 {
 public:
        enum class Type {
+               OK,
                ERROR,
                BV21_ERROR, ///< may not always be considered an error, but violates a "shall" requirement of Bv2.1
                WARNING
        };
 
-       /** Codes for errors or warnings from verifying DCPs.
+       /** Codes for successful checks, errors or warnings from verifying DCPs.
         *
         *  The names should (in general) answer the question "what is wrong?" with an answer that begins "There is a ..."
         *  e.g. "There is a INCORRECT_CPL_HASH"
@@ -95,17 +102,23 @@ public:
                 *  note contains (probably technical) details
                 */
                FAILED_READ,
+               MATCHING_CPL_HASHES,
                /** The hash of the CPL in the PKL does not agree with the CPL file
                 *  note contains CPL ID
                 *  file contains CPL filename
+                *  calculated_hash contains current hash of the CPL
+                *  reference_hash contains the hash written in the PKL
                 */
                MISMATCHED_CPL_HASHES,
                /** The frame rate given in a reel for the main picture is not 24, 25, 30, 48, 50 or 60
                 *  note contains the invalid frame rate as "<numerator>/<denominator>"
                 */
                INVALID_PICTURE_FRAME_RATE,
+               CORRECT_PICTURE_HASH,
                /** The hash of a main picture asset does not agree with the PKL file
                 *  file contains the picture asset filename
+                *  calculated_hash contains the current hash of the picture MXF
+                *  reference_hash contains the hash from the PKL
                 */
                INCORRECT_PICTURE_HASH,
                /** The hash of a main picture is different in the CPL and PKL
@@ -114,6 +127,8 @@ public:
                MISMATCHED_PICTURE_HASHES,
                /** The hash of a main sound asset does not agree with the PKL file
                 *  file contains the sound asset filename
+                *  calculated_hash contains the current hash of the picture MXF
+                *  reference_hash contains the hash from the PKL
                 */
                INCORRECT_SOUND_HASH,
                /** The hash of a main sound is different in the CPL and PKL
@@ -144,6 +159,7 @@ public:
                 *  note contains asset ID
                 */
                INVALID_DURATION,
+               VALID_PICTURE_FRAME_SIZES_IN_BYTES,
                /** The JPEG2000 data in at least one picture frame is larger than the equivalent of 250Mbit/s
                 *  file contains the picture asset filename
                 */
@@ -166,6 +182,7 @@ public:
                 *  note contains the invalid language
                 */
                INVALID_LANGUAGE,
+               VALID_RELEASE_TERRITORY,
                /** A picture asset does not have one of the required Bv2.1 sizes (in pixels) [Bv2.1_7.1]
                 *  note contains the incorrect size as "<width>x<height>"
                 *  file contains the asset filename
@@ -248,6 +265,7 @@ public:
                 *  file contains the CPL filename
                 */
                MISMATCHED_CPL_ANNOTATION_TEXT,
+               VALID_CPL_ANNOTATION_TEXT,
                /** At least one asset in a reel does not have the same duration as the others */
                MISMATCHED_ASSET_DURATION,
                /** If one reel has a _MainSubtitle_, all must have them */
@@ -325,9 +343,15 @@ public:
                 *  file contains the PKL filename
                 */
                MISMATCHED_PKL_ANNOTATION_TEXT_WITH_CPL,
+               MATCHING_PKL_ANNOTATION_TEXT_WITH_CPL,
+               /** All content is encrypted */
+               ALL_ENCRYPTED,
+               /** No content is encrypted */
+               NONE_ENCRYPTED,
                /** Some, but not all content, is encrypted */
                PARTIALLY_ENCRYPTED,
                /** General error during JPEG2000 codestream verification
+                *  frame contains the frame index (counted from 0)
                 *  note contains details
                 */
                INVALID_JPEG2000_CODESTREAM,
@@ -396,16 +420,78 @@ public:
                UNEXPECTED_DURATION,
                /** A <ContentKind> has been specified with either no scope or the SMPTE 429-7 scope, but which is not one of those allowed */
                INVALID_CONTENT_KIND,
+               VALID_CONTENT_KIND,
                /** Either the width or height of a <MainPictureActiveArea> in a CPL is either not an even number, or bigger than the corresponding asset dimension.
                 *  note contains details of what is wrong
                 *  file contains the CPL filename
                 */
                INVALID_MAIN_PICTURE_ACTIVE_AREA,
+               VALID_MAIN_PICTURE_ACTIVE_AREA,
                /** A PKL has more than one asset with the same ID
                 *  note contains the PKL ID
                 *  file contains the PKL filename
                 */
-               DUPLICATE_ASSET_ID_IN_PKL
+               DUPLICATE_ASSET_ID_IN_PKL,
+               /** An ASSETMAP has more than one asset with the same ID
+                *  note contains the ASSETMAP ID
+                *  file contains the ASSETMAP filename
+                */
+               DUPLICATE_ASSET_ID_IN_ASSETMAP,
+               /** An Interop subtitle asset has no subtitles
+                *  note contains the asset ID
+                *  file contains the asset filename
+                */
+               MISSING_SUBTITLE,
+               /** A SMPTE subtitle asset as an <IssueDate> which is not of the form yyyy-mm-ddThh:mm:ss
+                *  I can find no reference in a standard to this being required, but the Deluxe delivery
+                *  specifications require it and their QC will fail DCPs that don't have it.
+                *  note contains the incorrect <IssueDate>
+                */
+               INVALID_SUBTITLE_ISSUE_DATE,
+               /** The sound assets in the CPL do not have the same audio channel count.
+                *  file contains the filename of the first asset to differ
+                */
+               MISMATCHED_SOUND_CHANNEL_COUNTS,
+               /** The CPL contains a MainSoundConfiguration tag which does not describe the number of
+                *  channels in the audio assets.
+                *  note contains details of what is wrong
+                *  file contains the CPL filename
+                */
+               INVALID_MAIN_SOUND_CONFIGURATION,
+               /** An interop subtitle file has a <LoadFont> node which refers to a font file that is not found.
+                *  note contains the <LoadFont> ID
+                */
+               MISSING_FONT,
+               /** A tile part in a JPEG2000 frame is too big.
+                *  frame contains the frame index (counted from 0)
+                *  component contains the component index (0, 1 or 2)
+                *  size contains the invalid size in bytes.
+                */
+               INVALID_JPEG2000_TILE_PART_SIZE,
+               /** A subtitle XML root node has more than one namespace (xmlns) declaration.
+                *  note contains the asset ID
+                */
+               INCORRECT_SUBTITLE_NAMESPACE_COUNT,
+               /** A subtitle or closed caption file has a <Font> tag which refers to a font that is not
+                *  first introduced with a <LoadFont>.
+                *  id contains the ID of the <Font> tag.
+                */
+               MISSING_LOAD_FONT_FOR_FONT,
+               /** A SMPTE subtitle asset has at least one <Text> element but no <LoadFont>
+                *  id contains the ID of the subtitle asset.
+                */
+               MISSING_LOAD_FONT,
+               /** An ID in an asset map does not match the ID obtained from reading the actual file.
+                *  id contains the ID from the asset map.
+                *  other_id contains the ID from the file.
+                */
+               MISMATCHED_ASSET_MAP_ID,
+               /** The <LabelText> inside a <ContentVersion> is empty
+                *  note contains the CPL ID
+                *  file contains the CPL filename
+                */
+               EMPTY_CONTENT_VERSION_LABEL_TEXT,
+               VALID_CONTENT_VERSION_LABEL_TEXT,
        };
 
        VerificationNote (Type type, Code code)
@@ -416,29 +502,33 @@ public:
        VerificationNote (Type type, Code code, std::string note)
                : _type (type)
                , _code (code)
-               , _note (note)
-       {}
+       {
+               _data[Data::NOTE] = note;
+       }
 
        VerificationNote (Type type, Code code, boost::filesystem::path file)
                : _type (type)
                , _code (code)
-               , _file (file)
-       {}
+       {
+               _data[Data::FILE] = file;
+       }
 
        VerificationNote (Type type, Code code, std::string note, boost::filesystem::path file)
                : _type (type)
                , _code (code)
-               , _note (note)
-               , _file (file)
-       {}
+       {
+               _data[Data::NOTE] = note;
+               _data[Data::FILE] = file;
+       }
 
        VerificationNote (Type type, Code code, std::string note, boost::filesystem::path file, uint64_t line)
                : _type (type)
                , _code (code)
-               , _note (note)
-               , _file (file)
-               , _line (line)
-       {}
+       {
+               _data[Data::NOTE] = note;
+               _data[Data::FILE] = file;
+               _data[Data::LINE] = line;
+       }
 
        Type type () const {
                return _type;
@@ -448,40 +538,163 @@ public:
                return _code;
        }
 
+private:
+       enum class Data {
+               NOTE,  ///< further information about the error
+               FILE,  ///< path of file containing the error
+               LINE,  ///< error line number within the FILE
+               FRAME,
+               COMPONENT,
+               SIZE,
+               ID,
+               OTHER_ID,
+               FRAME_RATE,
+               CPL_ID,
+               CALCULATED_HASH,
+               REFERENCE_HASH
+       };
+
+       template <class T>
+       boost::optional<T> data(Data key) const
+       {
+               auto iter = _data.find(key);
+               if (iter == _data.end()) {
+                       return {};
+               }
+               return boost::any_cast<T>(iter->second);
+       }
+
+public:
        boost::optional<std::string> note () const {
-               return _note;
+               return data<std::string>(Data::NOTE);
        }
 
        boost::optional<boost::filesystem::path> file () const {
-               return _file;
+               return data<boost::filesystem::path>(Data::FILE);
        }
 
        boost::optional<uint64_t> line () const {
-               return _line;
+               return data<uint64_t>(Data::LINE);
+       }
+
+       VerificationNote& set_frame(int frame) {
+               _data[Data::FRAME] = frame;
+               return *this;
+       }
+
+       boost::optional<int> frame() const {
+               return data<int>(Data::FRAME);
+       }
+
+       VerificationNote& set_component(int component) {
+               _data[Data::COMPONENT] = component;
+               return *this;
+       }
+
+       boost::optional<int> component() const {
+               return data<int>(Data::COMPONENT);
+       }
+
+       VerificationNote& set_size(int size) {
+               _data[Data::SIZE] = size;
+               return *this;
+       }
+
+       boost::optional<int> size() const {
+               return data<int>(Data::SIZE);
+       }
+
+       VerificationNote& set_id(std::string id) {
+               _data[Data::ID] = id;
+               return *this;
+       }
+
+       boost::optional<std::string> id() const {
+               return data<std::string>(Data::ID);
+       }
+
+       VerificationNote& set_other_id(std::string other_id) {
+               _data[Data::OTHER_ID] = other_id;
+               return *this;
+       }
+
+       boost::optional<std::string> other_id() const {
+               return data<std::string>(Data::OTHER_ID);
+       }
+
+       VerificationNote& set_frame_rate(int frame_rate) {
+               _data[Data::FRAME_RATE] = frame_rate;
+               return *this;
+       }
+
+       boost::optional<int> frame_rate() const {
+               return data<int>(Data::FRAME_RATE);
+       }
+
+       VerificationNote& set_calculated_hash(std::string hash) {
+               _data[Data::CALCULATED_HASH] = hash;
+               return *this;
+       }
+
+       boost::optional<std::string> calculated_hash() const {
+               return data<std::string>(Data::CALCULATED_HASH);
+       }
+
+       VerificationNote& set_reference_hash(std::string hash) {
+               _data[Data::REFERENCE_HASH] = hash;
+               return *this;
+       }
+
+       boost::optional<std::string> reference_hash() const {
+               return data<std::string>(Data::REFERENCE_HASH);
+       }
+
+       VerificationNote& set_cpl_id(std::string id) {
+               _data[Data::CPL_ID] = id;
+               return *this;
+       }
+
+       boost::optional<std::string> cpl_id() const {
+               return data<std::string>(Data::CPL_ID);
        }
 
 private:
        Type _type;
        Code _code;
-       /** Further information about the error, if applicable */
-       boost::optional<std::string> _note;
-       /** Path of file containing the error, if applicable */
-       boost::optional<boost::filesystem::path> _file;
-       /** Error line number within _file, if applicable */
-       boost::optional<uint64_t> _line;
+       std::map<Data, boost::any> _data;
+};
+
+
+struct VerificationOptions
+{
+       ///< If set, any assets larger than this number of bytes will not have their hashes checked
+       boost::optional<boost::uintmax_t> maximum_asset_size_for_hash_check;
+       ///< true to check asset hashes (except those which match maximum_asset_size_for_hash_check)
+       ///< false to check no asset hashes.
+       bool check_asset_hashes = true;
+};
+
+
+struct VerifyResult
+{
+       std::vector<VerificationNote> notes;
+       std::vector<std::shared_ptr<dcp::DCP>> dcps;
 };
 
 
-std::vector<VerificationNote> verify (
+VerifyResult verify(
        std::vector<boost::filesystem::path> directories,
-       boost::function<void (std::string, boost::optional<boost::filesystem::path>)> stage,
-       boost::function<void (float)> progress,
+       std::vector<dcp::DecryptedKDM> kdms,
+       std::function<void (std::string, boost::optional<boost::filesystem::path>)> stage,
+       std::function<void (float)> progress,
+       VerificationOptions options = {},
        boost::optional<boost::filesystem::path> xsd_dtd_directory = boost::optional<boost::filesystem::path>()
        );
 
 std::string note_to_string (dcp::VerificationNote note);
 
 bool operator== (dcp::VerificationNote const& a, dcp::VerificationNote const& b);
+bool operator!=(dcp::VerificationNote const& a, dcp::VerificationNote const& b);
 bool operator< (dcp::VerificationNote const& a, dcp::VerificationNote const& b);
 
 std::ostream& operator<<(std::ostream& s, dcp::VerificationNote const& note);