Bv2.1 8.7: CPLs with encrypted content must be signed.
[libdcp.git] / src / verify.h
index 63f47e289325c17e710f9f809388ace9852a3222..833efa72e88d96a6f3f0493d5b4277fededf9b10 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
@@ -35,8 +35,9 @@
 #define LIBDCP_VERIFY_H
 
 #include <boost/filesystem.hpp>
+#include <boost/function.hpp>
+#include <boost/optional.hpp>
 #include <string>
-#include <list>
 #include <vector>
 
 namespace dcp {
@@ -44,31 +45,209 @@ namespace dcp {
 class VerificationNote
 {
 public:
+       /* I've been unable to make mingw happy with ERROR as a symbol, so
+          I'm using a VERIFY_ prefix here.
+       */
        enum Type {
-               ERROR,
-               WARNING,
-               NOTE
+               VERIFY_ERROR,
+               VERIFY_BV21_ERROR, ///< may not always be considered an error, but violates a "shall" requirement of Bv2.1
+               VERIFY_WARNING
        };
 
-       VerificationNote (Type type, std::string note)
+       enum Code {
+               /** An error when reading the DCP.  note contains (probably technical) details. */
+               GENERAL_READ,
+               /** The hash of the CPL in the PKL does not agree with the CPL file */
+               CPL_HASH_INCORRECT,
+               /** Frame rate given in a reel for the main picture is not 24, 25, 30, 48, 50 or 60 */
+               INVALID_PICTURE_FRAME_RATE,
+               /** The hash of a main picture asset does not agree with the PKL file.  file contains the picture asset filename. */
+               PICTURE_HASH_INCORRECT,
+               /** The hash of a main picture is different in the CPL and PKL */
+               PKL_CPL_PICTURE_HASHES_DIFFER,
+               /** The hash of a main sound asset does not agree with the PKL file.  file contains the sound asset filename. */
+               SOUND_HASH_INCORRECT,
+               /** The hash of a main sound is different in the CPL and PKL */
+               PKL_CPL_SOUND_HASHES_DIFFER,
+               /** An assetmap's <Path> entry is empty */
+               EMPTY_ASSET_PATH,
+               /** A file mentioned in an asset map cannot be found */
+               MISSING_ASSET,
+               /** The DCP contains both SMPTE and Interop-standard components */
+               MISMATCHED_STANDARD,
+               /** Some XML fails to validate against the XSD/DTD */
+               XML_VALIDATION_ERROR,
+               /** No ASSETMAP{.xml} was found */
+               MISSING_ASSETMAP,
+               /** An asset's IntrinsicDuration is less than 1 second */
+               INTRINSIC_DURATION_TOO_SMALL,
+               /** An asset's Duration is less than 1 second */
+               DURATION_TOO_SMALL,
+               /** The JPEG2000 data in at least one picture frame is larger than the equivalent of 250Mbit/s */
+               PICTURE_FRAME_TOO_LARGE_IN_BYTES,
+               /** The JPEG2000 data in at least one picture frame is larger than the equivalent of 230Mbit/s */
+               PICTURE_FRAME_NEARLY_TOO_LARGE_IN_BYTES,
+               /** An asset that the CPL requires is not in this DCP; the DCP may be a VF */
+               EXTERNAL_ASSET,
+               /** DCP is Interop, not SMPTE [Bv2.1_6.1] */
+               NOT_SMPTE,
+               /** A language or territory does not conform to RFC 5646 [Bv2.1_6.2.1] */
+               BAD_LANGUAGE,
+               /** A picture asset does not have one of the required Bv2.1 sizes (in pixels) [Bv2.1_7.1] */
+               PICTURE_ASSET_INVALID_SIZE_IN_PIXELS,
+               /** A picture asset is 2K but is not at 24, 25 or 48 fps as required by Bv2.1 [Bv2.1_7.1] */
+               PICTURE_ASSET_INVALID_FRAME_RATE_FOR_2K,
+               /** A picture asset is 4K but is not at 24fps as required by Bv2.1 [Bv2.1_7.1] */
+               PICTURE_ASSET_INVALID_FRAME_RATE_FOR_4K,
+               /** A picture asset is 4K but is 3D which is not allowed by Bv2.1 [Bv2.1_7.1] */
+               PICTURE_ASSET_4K_3D,
+               /** A closed caption's XML file is larger than 256KB [Bv2.1_7.2.1] */
+               CLOSED_CAPTION_XML_TOO_LARGE_IN_BYTES,
+               /** Any timed text asset's total files is larger than 115MB [Bv2.1_7.2.1] */
+               TIMED_TEXT_ASSET_TOO_LARGE_IN_BYTES,
+               /** The total size of all a timed text asset's fonts is larger than 10MB [Bv2.1_7.2.1] */
+               TIMED_TEXT_FONTS_TOO_LARGE_IN_BYTES,
+               /** Some SMPTE subtitle XML has no <Language> tag [Bv2.1_7.2.2] */
+               MISSING_SUBTITLE_LANGUAGE,
+               /** Not all subtitle assets specify the same <Language> tag [Bv2.1_7.2.2] */
+               SUBTITLE_LANGUAGES_DIFFER,
+               /** Some SMPTE subtitle XML has no <StartTime> tag [Bv2.1_7.2.3] */
+               MISSING_SUBTITLE_START_TIME,
+               /** Some SMPTE subtitle XML has a non-zero <StartTime> tag [Bv2.1_7.2.3] */
+               SUBTITLE_START_TIME_NON_ZERO,
+               /** The first subtitle or closed caption happens before 4s into the first reel [Bv2.1_7.2.4] */
+               FIRST_TEXT_TOO_EARLY,
+               /** At least one subtitle is less than the minimum of 15 frames suggested by [Bv2.1_7.2.5] */
+               SUBTITLE_TOO_SHORT,
+               /** At least one pair of subtitles are separated by less than the the minimum of 2 frames suggested by [Bv2.1_7.2.5] */
+               SUBTITLE_TOO_CLOSE,
+               /** There are more than 3 subtitle lines in at least one place [Bv2.1_7.2.7] */
+               TOO_MANY_SUBTITLE_LINES,
+               /** There are more than 52 characters in at least one subtitle line [Bv2.1_7.2.7] */
+               SUBTITLE_LINE_LONGER_THAN_RECOMMENDED,
+               /** There are more than 79 characters in at least one subtitle line [Bv2.1_7.2.7] */
+               SUBTITLE_LINE_TOO_LONG,
+               /** There are more than 3 closed caption lines in at least one place [Bv2.1_7.2.6] */
+               TOO_MANY_CLOSED_CAPTION_LINES,
+               /** There are more than 32 characters in at least one closed caption line [Bv2.1_7.2.6] */
+               CLOSED_CAPTION_LINE_TOO_LONG,
+               /** The audio sampling rate must be 48kHz [Bv2.1_7.3] */
+               INVALID_SOUND_FRAME_RATE,
+               /** The CPL has no <AnnotationText> tag [Bv2.1_8.1] */
+               MISSING_ANNOTATION_TEXT_IN_CPL,
+               /** The <AnnotationText> is not the same as the <ContentTitleText> [Bv2.1_8.1] */
+               CPL_ANNOTATION_TEXT_DIFFERS_FROM_CONTENT_TITLE_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 */
+               MAIN_SUBTITLE_NOT_IN_ALL_REELS,
+               /** If one reel has at least one ClosedCaption, all reels must have the same number of ClosedCaptions */
+               CLOSED_CAPTION_ASSET_COUNTS_DIFFER,
+               /** MainSubtitle in reels must have <EntryPoint> Bv2.1_8.3.2 */
+               MISSING_SUBTITLE_ENTRY_POINT,
+               /** MainSubtitle <EntryPoint> must be zero Bv2.1_8.3.2 */
+               SUBTITLE_ENTRY_POINT_NON_ZERO,
+               /** Closed caption in reels must have <EntryPoint> Bv2.1_8.3.2 */
+               MISSING_CLOSED_CAPTION_ENTRY_POINT,
+               /** Closed caption MainSubtitle <EntryPoint> must be zero Bv2.1_8.3.2 */
+               CLOSED_CAPTION_ENTRY_POINT_NON_ZERO,
+               /** <Hash> must be present for assets in CPLs */
+               MISSING_HASH,
+               /** If ContentKind is Feature there must be a FFEC marker */
+               MISSING_FFEC_IN_FEATURE,
+               /** If ContentKind is Feature there must be a FFMC marker */
+               MISSING_FFMC_IN_FEATURE,
+               /** There should be a FFOC */
+               MISSING_FFOC,
+               /** There should be a LFOC */
+               MISSING_LFOC,
+               /** The FFOC should be 1 */
+               INCORRECT_FFOC,
+               /** The LFOC should be the last frame in the reel */
+               INCORRECT_LFOC,
+               /** There must be a <CompositionMetadataAsset> */
+               MISSING_CPL_METADATA,
+               /** CPL metadata should contain <VersionNumber> of 1, at least */
+               MISSING_CPL_METADATA_VERSION_NUMBER,
+               /** There must be an <ExtensionMetadata> in <CompositionMetadataAsset> Bv2.1_8.6.3 */
+               MISSING_EXTENSION_METADATA,
+               /** <ExtensionMetadata> must have a particular form Bv2.1_8.6.3 */
+               INVALID_EXTENSION_METADATA,
+               /** CPLs containing encrypted content must be signed Bv2.1_8.7 */
+               CPL_WITH_ENCRYPTED_CONTENT_NOT_SIGNED
+       };
+
+       VerificationNote (Type type, Code code)
+               : _type (type)
+               , _code (code)
+       {}
+
+       VerificationNote (Type type, Code code, std::string note)
+               : _type (type)
+               , _code (code)
+               , _note (note)
+       {}
+
+       VerificationNote (Type type, Code code, boost::filesystem::path file)
+               : _type (type)
+               , _code (code)
+               , _file (file)
+       {}
+
+       VerificationNote (Type type, Code code, std::string note, boost::filesystem::path file)
                : _type (type)
+               , _code (code)
                , _note (note)
+               , _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)
        {}
 
        Type type () const {
                return _type;
        }
 
-       std::string note () const {
+       Code code () const {
+               return _code;
+       }
+
+       boost::optional<std::string> note () const {
                return _note;
        }
 
+       boost::optional<boost::filesystem::path> file () const {
+               return _file;
+       }
+
+       boost::optional<uint64_t> line () const {
+               return _line;
+       }
+
 private:
        Type _type;
-       std::string _note;
+       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 */
+       uint64_t _line;
 };
 
-std::list<VerificationNote> verify (std::vector<boost::filesystem::path> directories);
+std::vector<VerificationNote> verify (
+       std::vector<boost::filesystem::path> directories,
+       boost::function<void (std::string, boost::optional<boost::filesystem::path>)> stage,
+       boost::function<void (float)> progress,
+       boost::filesystem::path xsd_dtd_directory
+       );
+
+std::string note_to_string (dcp::VerificationNote note);
 
 }