From c3c127e0bdb988696d16f47ea8080df3eff38420 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 16 Dec 2025 17:45:46 +0100 Subject: Add can_be_read() to ReelFileAsset and subclasses. --- src/atmos_asset.cc | 22 +++++ src/atmos_asset.h | 2 + src/mono_j2k_picture_asset.cc | 22 +++++ src/mono_j2k_picture_asset.h | 2 + src/mono_mpeg2_picture_asset.cc | 24 +++++ src/mono_mpeg2_picture_asset.h | 2 + src/mxf.cc | 7 ++ src/mxf.h | 2 + src/reel_atmos_asset.cc | 12 +++ src/reel_atmos_asset.h | 2 + src/reel_file_asset.cc | 7 ++ src/reel_file_asset.h | 1 + src/reel_mono_picture_asset.cc | 14 ++- src/reel_mono_picture_asset.h | 2 + src/reel_smpte_text_asset.cc | 11 +++ src/reel_smpte_text_asset.h | 2 + src/reel_sound_asset.cc | 12 +++ src/reel_sound_asset.h | 2 + src/reel_stereo_picture_asset.cc | 17 +++- src/reel_stereo_picture_asset.h | 2 + src/smpte_text_asset.cc | 21 +++++ src/smpte_text_asset.h | 2 + src/sound_asset.cc | 21 +++++ src/sound_asset.h | 2 + src/stereo_j2k_picture_asset.cc | 22 +++++ src/stereo_j2k_picture_asset.h | 2 + test/can_be_read_test.cc | 152 +++++++++++++++++++++++++++++++ test/data/other_kdm.xml | 190 +++++++++++++++++++++++++++++++++++++++ test/wscript | 1 + 29 files changed, 577 insertions(+), 3 deletions(-) create mode 100644 test/can_be_read_test.cc create mode 100644 test/data/other_kdm.xml diff --git a/src/atmos_asset.cc b/src/atmos_asset.cc index 09a22c1e..9c4b1c80 100644 --- a/src/atmos_asset.cc +++ b/src/atmos_asset.cc @@ -122,3 +122,25 @@ AtmosAsset::start_write (boost::filesystem::path file) /* Can't use make_shared here since the constructor is protected */ return shared_ptr(new AtmosAssetWriter(this, file)); } + + +bool +AtmosAsset::can_be_read() const +{ + if (!MXF::can_be_read()) { + return false; + } + + try { + auto reader = start_read(); + reader->set_check_hmac(false); + reader->get_frame(0); + } catch (dcp::ReadError&) { + return false; + } catch (dcp::MiscError&) { + return false; + } + + return true; +} + diff --git a/src/atmos_asset.h b/src/atmos_asset.h index a682ae60..9fcd359f 100644 --- a/src/atmos_asset.h +++ b/src/atmos_asset.h @@ -61,6 +61,8 @@ public: AtmosAsset (Fraction edit_rate, int first_frame, int max_channel_count, int max_object_count, int atmos_version); explicit AtmosAsset (boost::filesystem::path file); + bool can_be_read() const override; + std::shared_ptr start_write (boost::filesystem::path file); std::shared_ptr start_read () const; diff --git a/src/mono_j2k_picture_asset.cc b/src/mono_j2k_picture_asset.cc index b1f311d6..4a8a3219 100644 --- a/src/mono_j2k_picture_asset.cc +++ b/src/mono_j2k_picture_asset.cc @@ -207,3 +207,25 @@ MonoJ2KPictureAsset::cpl_node_name () const { return "MainPicture"; } + + +bool +MonoJ2KPictureAsset::can_be_read() const +{ + if (!MXF::can_be_read()) { + return false; + } + + try { + auto reader = start_read(); + reader->set_check_hmac(false); + reader->get_frame(0)->xyz_image(); + } catch (dcp::ReadError&) { + return false; + } catch (dcp::MiscError&) { + return false; + } + + return true; +} + diff --git a/src/mono_j2k_picture_asset.h b/src/mono_j2k_picture_asset.h index d716b8ff..f790e543 100644 --- a/src/mono_j2k_picture_asset.h +++ b/src/mono_j2k_picture_asset.h @@ -68,6 +68,8 @@ public: */ MonoJ2KPictureAsset(Fraction edit_rate, Standard standard); + bool can_be_read() const override; + /** Start a progressive write to a MonoJ2KPictureAsset. * @path file File to write to. * @path behaviour OVERWRITE_EXISTING to overwrite and potentially add to an existing file diff --git a/src/mono_mpeg2_picture_asset.cc b/src/mono_mpeg2_picture_asset.cc index 380da0fe..9a879f0b 100644 --- a/src/mono_mpeg2_picture_asset.cc +++ b/src/mono_mpeg2_picture_asset.cc @@ -36,6 +36,7 @@ #include "mono_mpeg2_picture_asset.h" #include "mono_mpeg2_picture_asset_reader.h" #include "mono_mpeg2_picture_asset_writer.h" +#include "mpeg2_transcode.h" #include @@ -84,3 +85,26 @@ MonoMPEG2PictureAsset::start_write(boost::filesystem::path file, Behaviour behav /* Can't use make_shared here as the MonoJ2KPictureAssetWriter constructor is private */ return shared_ptr(new MonoMPEG2PictureAssetWriter(this, file, behaviour == Behaviour::OVERWRITE_EXISTING)); } + + +bool +MonoMPEG2PictureAsset::can_be_read() const +{ + if (!MXF::can_be_read()) { + return false; + } + + try { + auto reader = start_read(); + reader->set_check_hmac(false); + dcp::MPEG2Decompressor decompressor; + decompressor.decompress_frame(reader->get_frame(0)); + } catch (dcp::ReadError&) { + return false; + } catch (dcp::MiscError&) { + return false; + } + + return true; +} + diff --git a/src/mono_mpeg2_picture_asset.h b/src/mono_mpeg2_picture_asset.h index 8ef3653e..dc2637e7 100644 --- a/src/mono_mpeg2_picture_asset.h +++ b/src/mono_mpeg2_picture_asset.h @@ -61,6 +61,8 @@ public: explicit MonoMPEG2PictureAsset(boost::filesystem::path file); + bool can_be_read() const override; + std::shared_ptr start_write(boost::filesystem::path file, Behaviour behaviour) override; std::shared_ptr start_read() const; }; diff --git a/src/mxf.cc b/src/mxf.cc index 1154b80d..60ef5552 100644 --- a/src/mxf.cc +++ b/src/mxf.cc @@ -146,3 +146,10 @@ MXF::read_writer_info (ASDCP::WriterInfo const & info) Kumu::bin2UUIDhex (info.AssetUUID, ASDCP::UUIDlen, buffer, sizeof (buffer)); return buffer; } + + +bool +MXF::can_be_read() const +{ + return !encrypted() || key(); +} diff --git a/src/mxf.h b/src/mxf.h index ad9e39ed..933e7afb 100644 --- a/src/mxf.h +++ b/src/mxf.h @@ -76,6 +76,8 @@ public: MXF (Standard standard); virtual ~MXF () {} + virtual bool can_be_read() const; + /** @return true if the data is encrypted */ bool encrypted () const { return static_cast(_key_id); diff --git a/src/reel_atmos_asset.cc b/src/reel_atmos_asset.cc index fcecb548..ae7be33a 100644 --- a/src/reel_atmos_asset.cc +++ b/src/reel_atmos_asset.cc @@ -104,3 +104,15 @@ ReelAtmosAsset::equals(shared_ptr other, EqualityOptions c return true; } + + +bool +ReelAtmosAsset::can_be_read() const +{ + if (!ReelFileAsset::can_be_read()) { + return false; + } + + return asset()->can_be_read(); +} + diff --git a/src/reel_atmos_asset.h b/src/reel_atmos_asset.h index ab18d1ab..ed525bae 100644 --- a/src/reel_atmos_asset.h +++ b/src/reel_atmos_asset.h @@ -60,6 +60,8 @@ public: ReelAtmosAsset (std::shared_ptr asset, int64_t entry_point); explicit ReelAtmosAsset (std::shared_ptr); + bool can_be_read() const override; + std::shared_ptr asset () const { return asset_of_type(); } diff --git a/src/reel_file_asset.cc b/src/reel_file_asset.cc index 8fed8012..ad534ebd 100644 --- a/src/reel_file_asset.cc +++ b/src/reel_file_asset.cc @@ -107,3 +107,10 @@ ReelFileAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const return asset; } + +bool +ReelFileAsset::can_be_read() const +{ + return asset_ref().resolved(); +} + diff --git a/src/reel_file_asset.h b/src/reel_file_asset.h index 48fdf215..2412ac2b 100644 --- a/src/reel_file_asset.h +++ b/src/reel_file_asset.h @@ -57,6 +57,7 @@ public: explicit ReelFileAsset (std::shared_ptr node); virtual xmlpp::Element* write_to_cpl(xmlpp::Element* node, Standard standard) const override; + virtual bool can_be_read() const; /** @return a Ref to our actual asset */ Ref const & asset_ref () const { diff --git a/src/reel_mono_picture_asset.cc b/src/reel_mono_picture_asset.cc index 5dbf85d2..9cbeb7e1 100644 --- a/src/reel_mono_picture_asset.cc +++ b/src/reel_mono_picture_asset.cc @@ -42,8 +42,9 @@ #include -using std::string; +using std::dynamic_pointer_cast; using std::shared_ptr; +using std::string; using namespace dcp; @@ -66,3 +67,14 @@ ReelMonoPictureAsset::cpl_node_name() const { return "MainPicture"; } + + +bool +ReelMonoPictureAsset::can_be_read() const +{ + if (!ReelFileAsset::can_be_read()) { + return false; + } + + return asset()->can_be_read(); +} diff --git a/src/reel_mono_picture_asset.h b/src/reel_mono_picture_asset.h index 0c468e0e..29df2d14 100644 --- a/src/reel_mono_picture_asset.h +++ b/src/reel_mono_picture_asset.h @@ -61,6 +61,8 @@ public: ReelMonoPictureAsset(std::shared_ptr asset, int64_t entry_point); explicit ReelMonoPictureAsset (std::shared_ptr); + bool can_be_read() const override; + /** @return the MonoJ2KPictureAsset that this object refers to, if applicable */ std::shared_ptr mono_j2k_asset() const { return asset_of_type(); diff --git a/src/reel_smpte_text_asset.cc b/src/reel_smpte_text_asset.cc index b1ce34cb..30a4d443 100644 --- a/src/reel_smpte_text_asset.cc +++ b/src/reel_smpte_text_asset.cc @@ -116,3 +116,14 @@ ReelSMPTETextAsset::write_to_cpl(xmlpp::Element* node, Standard standard) const } + +bool +ReelSMPTETextAsset::can_be_read() const +{ + if (!ReelFileAsset::can_be_read()) { + return false; + } + + return smpte_asset()->can_be_read(); +} + diff --git a/src/reel_smpte_text_asset.h b/src/reel_smpte_text_asset.h index b3c2f655..68459c30 100644 --- a/src/reel_smpte_text_asset.h +++ b/src/reel_smpte_text_asset.h @@ -56,6 +56,8 @@ public: ReelSMPTETextAsset(TextType type, std::shared_ptr asset, Fraction edit_rate, int64_t intrinsic_duration, int64_t entry_point); explicit ReelSMPTETextAsset(std::shared_ptr); + bool can_be_read() const override; + std::shared_ptr smpte_asset() const { return asset_of_type(); } diff --git a/src/reel_sound_asset.cc b/src/reel_sound_asset.cc index dbac6cb3..3c11f666 100644 --- a/src/reel_sound_asset.cc +++ b/src/reel_sound_asset.cc @@ -93,3 +93,15 @@ ReelSoundAsset::equals(shared_ptr other, EqualityOptions c return true; } + + +bool +ReelSoundAsset::can_be_read() const +{ + if (!ReelFileAsset::can_be_read()) { + return false; + } + + return asset()->can_be_read(); +} + diff --git a/src/reel_sound_asset.h b/src/reel_sound_asset.h index 6537ab5c..ac157bdb 100644 --- a/src/reel_sound_asset.h +++ b/src/reel_sound_asset.h @@ -55,6 +55,8 @@ public: ReelSoundAsset (std::shared_ptr content, int64_t entry_point); explicit ReelSoundAsset (std::shared_ptr); + bool can_be_read() const override; + /** @return the SoundAsset that this object refers to */ std::shared_ptr asset () const { return asset_of_type(); diff --git a/src/reel_stereo_picture_asset.cc b/src/reel_stereo_picture_asset.cc index 2ee452d9..53abb8d6 100644 --- a/src/reel_stereo_picture_asset.cc +++ b/src/reel_stereo_picture_asset.cc @@ -42,10 +42,11 @@ #include -using std::string; -using std::pair; +using std::dynamic_pointer_cast; using std::make_pair; +using std::pair; using std::shared_ptr; +using std::string; using namespace dcp; @@ -82,3 +83,15 @@ ReelStereoPictureAsset::cpl_node_attribute (Standard standard) const DCP_ASSERT (false); } + + +bool +ReelStereoPictureAsset::can_be_read() const +{ + if (!ReelFileAsset::can_be_read()) { + return false; + } + + return asset()->can_be_read(); +} + diff --git a/src/reel_stereo_picture_asset.h b/src/reel_stereo_picture_asset.h index 0dd726a4..9e5b30cf 100644 --- a/src/reel_stereo_picture_asset.h +++ b/src/reel_stereo_picture_asset.h @@ -60,6 +60,8 @@ public: ReelStereoPictureAsset (std::shared_ptr content, int64_t entry_point); explicit ReelStereoPictureAsset (std::shared_ptr); + bool can_be_read() const override; + /** @return the StereoJ2KPictureAsset that this object refers to */ std::shared_ptr stereo_asset () const { return asset_of_type(); diff --git a/src/smpte_text_asset.cc b/src/smpte_text_asset.cc index 63e8c8ab..84624171 100644 --- a/src/smpte_text_asset.cc +++ b/src/smpte_text_asset.cc @@ -615,3 +615,24 @@ SMPTETextAsset::schema_namespace() const DCP_ASSERT(false); } + + + +bool +SMPTETextAsset::can_be_read() const +{ + if (!MXF::can_be_read()) { + return false; + } + + try { + texts(); + } catch (dcp::ReadError&) { + return false; + } catch (dcp::MiscError&) { + return false; + } + + return true; +} + diff --git a/src/smpte_text_asset.h b/src/smpte_text_asset.h index 6a08ffe4..9b7f09a6 100644 --- a/src/smpte_text_asset.h +++ b/src/smpte_text_asset.h @@ -82,6 +82,8 @@ public: */ explicit SMPTETextAsset(boost::filesystem::path file); + bool can_be_read() const override; + bool equals ( std::shared_ptr, EqualityOptions const&, diff --git a/src/sound_asset.cc b/src/sound_asset.cc index f671a58a..614f6165 100644 --- a/src/sound_asset.cc +++ b/src/sound_asset.cc @@ -294,3 +294,24 @@ SoundAsset::active_channels() const return _active_channels.get_value_or(_channels); } + +bool +SoundAsset::can_be_read() const +{ + if (!MXF::can_be_read()) { + return false; + } + + try { + auto reader = start_read(); + reader->set_check_hmac(false); + reader->get_frame(0); + } catch (dcp::ReadError&) { + return false; + } catch (dcp::MiscError&) { + return false; + } + + return true; +} + diff --git a/src/sound_asset.h b/src/sound_asset.h index e5acb119..64bc0a03 100644 --- a/src/sound_asset.h +++ b/src/sound_asset.h @@ -84,6 +84,8 @@ public: DISABLED }; + bool can_be_read() const override; + /** @param extra_active_channels list of channels that are active in the asset, other than the basic 5.1 * which are assumed always to be active. */ diff --git a/src/stereo_j2k_picture_asset.cc b/src/stereo_j2k_picture_asset.cc index 6a5e7d79..d403ed41 100644 --- a/src/stereo_j2k_picture_asset.cc +++ b/src/stereo_j2k_picture_asset.cc @@ -181,3 +181,25 @@ StereoJ2KPictureAsset::equals(shared_ptr other, EqualityOptions con return result; } + + +bool +StereoJ2KPictureAsset::can_be_read() const +{ + if (!MXF::can_be_read()) { + return false; + } + + try { + auto reader = start_read(); + reader->set_check_hmac(false); + reader->get_frame(0)->xyz_image(Eye::LEFT); + } catch (dcp::ReadError&) { + return false; + } catch (dcp::MiscError&) { + return false; + } + + return true; +} + diff --git a/src/stereo_j2k_picture_asset.h b/src/stereo_j2k_picture_asset.h index 7ef86ec5..6c870d59 100644 --- a/src/stereo_j2k_picture_asset.h +++ b/src/stereo_j2k_picture_asset.h @@ -57,6 +57,8 @@ public: explicit StereoJ2KPictureAsset (boost::filesystem::path file); explicit StereoJ2KPictureAsset (Fraction edit_rate, Standard standard); + bool can_be_read() const override; + /** Start a progressive write to a StereoJ2KPictureAsset */ std::shared_ptr start_write(boost::filesystem::path file, Behaviour behaviour) override; std::shared_ptr start_read () const; diff --git a/test/can_be_read_test.cc b/test/can_be_read_test.cc new file mode 100644 index 00000000..76615b24 --- /dev/null +++ b/test/can_be_read_test.cc @@ -0,0 +1,152 @@ +/* + Copyright (C) 2025 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +#include "encrypted_kdm.h" +#include "mono_j2k_picture_asset.h" +#include "reel_atmos_asset.h" +#include "reel_mono_picture_asset.h" +#include "reel_sound_asset.h" +#include "reel_text_asset.h" +#include +#include +#include "test.h" + + +using std::function; +using std::shared_ptr; + + +BOOST_AUTO_TEST_CASE(can_be_read_in_reel_mono_picture_asset_unencrypted) +{ + cxml::Document doc("Dummy"); + doc.read_string( + "" + "" + "urn:uuid:5407b210-4441-4e97-8b16-8bdc7c12da54" + "25 1" + "2508" + "225" + "2283" + "hcE3Lb8IEDIre9qXNEt64Z5RcNw=" + "25 1" + "1998 1080" + "" + "" + ); + + dcp::ReelMonoPictureAsset reel_asset(doc.node_child("MainPicture")); + + /* Unresolved */ + BOOST_CHECK(!reel_asset.can_be_read()); + + auto asset = std::make_shared("test/data/DCP/video.mxf"); + reel_asset.asset_ref().resolve({asset}); + + /* Resolved */ + BOOST_CHECK(reel_asset.can_be_read()); +} + + +BOOST_AUTO_TEST_CASE(can_be_read_in_reel_sound_asset_unencrypted) +{ + cxml::Document doc("Dummy"); + doc.read_string( + "" + "" + "urn:uuid:97f0f352-5b77-48ee-a558-9df37717f4fa" + "25 1" + "2508" + "225" + "2283" + "hcE3Lb8IEDIre9qXNEt64Z5RcNw=" + "" + "" + ); + + dcp::ReelSoundAsset reel_asset(doc.node_child("MainSound")); + + /* Unresolved */ + BOOST_CHECK(!reel_asset.can_be_read()); + + auto asset = std::make_shared("test/data/DCP/audio.mxf"); + reel_asset.asset_ref().resolve({asset}); + + /* Resolved */ + BOOST_CHECK(reel_asset.can_be_read()); +} + + +static void +can_be_read_in_reel_encrypted_one(function (shared_ptr)> get_asset) +{ + auto dcp = dcp::DCP(private_test / "data" / "encrypted_dcp_with_subs_and_atmos"); + dcp.read(); + + BOOST_REQUIRE_EQUAL(dcp.cpls().size(), 1U); + BOOST_REQUIRE_EQUAL(dcp.cpls()[0]->reels().size(), 1U); + auto reel_asset = get_asset(dcp.cpls()[0]->reels()[0]); + + /* Encrypted */ + BOOST_CHECK(!reel_asset->can_be_read()); + + dcp::DecryptedKDM wrong_kdm( + dcp::EncryptedKDM( + dcp::file_to_string("test/data/other_kdm.xml") + ), + dcp::file_to_string("test/data/private.key") + ); + dcp.add(wrong_kdm); + + /* Wrong KDM */ + BOOST_CHECK(!reel_asset->can_be_read()); + + dcp::DecryptedKDM right_kdm( + dcp::EncryptedKDM(dcp::file_to_string(private_test / "encrypted_dcp_with_subs_and_atmos.xml")), + dcp::file_to_string("test/data/private.key") + ); + dcp.add(right_kdm); + + /* Right KDM */ + BOOST_CHECK(reel_asset->can_be_read()); +} + + +BOOST_AUTO_TEST_CASE(can_be_read_in_reel_encrypted) +{ + can_be_read_in_reel_encrypted_one([](shared_ptr reel) { return reel->main_picture(); }); + can_be_read_in_reel_encrypted_one([](shared_ptr reel) { return reel->main_sound(); }); + can_be_read_in_reel_encrypted_one([](shared_ptr reel) { return reel->main_subtitle(); }); + can_be_read_in_reel_encrypted_one([](shared_ptr reel) { return reel->atmos(); }); +} + diff --git a/test/data/other_kdm.xml b/test/data/other_kdm.xml new file mode 100644 index 00000000..d7b2a22f --- /dev/null +++ b/test/data/other_kdm.xml @@ -0,0 +1,190 @@ + + + + urn:uuid:30b00f08-6fcf-414a-8924-831fd4daf05d + http://www.smpte-ra.org/430-1/2006/KDM#kdm-key-type + Test_FTR-1_F-133_EN-XX_MOS_2K_20251217_SMPTE_OV + 2025-12-17T23:46:43+01:00 + + dnQualifier=63rNM95i2Qy0MmrcDFMXewtrA\+c=,CN=.dcpomatic.smpte-430-2.INTERMEDIATE,OU=dcpomatic.com,O=dcpomatic.com + 7 + + + + + + dnQualifier=enjbKYhZ9JszBVjy71Lg9QrYmV4=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org + 7 + + dnQualifier=MekIXGBkYdh28siMnnF/Zs2JeK8=,CN=CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION,OU=example.org,O=example.org + + urn:uuid:67334526-342c-475d-bb64-d8fd8318f954 + Test_FTR-1_F-133_EN-XX_MOS_2K_20251217_SMPTE_OV + 2018-04-17T17:46:18+00:00 + 2028-04-10T17:46:18+00:00 + + urn:uuid:bf5b481b-1516-40f2-ba6c-4eca275083bc + smpte-430-2.LEAF.NOT_FOR_PRODUCTION + + 2jmj7l5rSw0yVb/vlWAYkK/YBwk= + + + + + MDIK + urn:uuid:8380c321-7412-405b-a725-e9251f2de4a5 + + + MDAK + urn:uuid:79d60a9e-382f-4fc0-963f-5d643cd8fa7d + + + + http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-picture-disable + http://www.smpte-ra.org/430-1/2006/KDM#mrkflg-audio-disable + + + + + + + + + + + + LJE29EIGAw9gJ8s+jGuBuIn6Sh/lbVo75bWbiD1ejoIafXHHigRLbjlnIaNtJZeY +SqpAWjDk5hCq0wouwu16xub1dCkUCHiKyWpnuaHG+hpInyn+2kAHdrwTp1yIZ1yO +wnIBwljlnyuqjrFs/CZCpc+LfBxDdRwKkY287XlikGtsFlt2zf97ETAfJBtttumE +biZe7+DW+He1sgOdu8Oljcxn1NqOpzn4cIeZMQ/JSoucmuVFpB1PvXG9qlQAoeSH +iBfQXopF1HQsAuAQIvuDdtSISzAslLTu3epg95hR60QYyOjL0zljpkl9pK+Y8ubJ +cfrGVP7OBgLv2Wxop02CYA== + + + + + + + + H7zg5PJxKCINheJo9uEdxS7FIayhO0OsKmOgcud9kEFWT39Z3l/IPsdEdenLH+4E +dU6wo8UmW2MsC+o9DvNVVedUPialaE2GxUEifXstB47U513tQth00OCogWXFmsv4 +KlMGk9pvhlUBz9XcykXfWYuFa7uYDGrtuFWvWZbqLAQ4vAnl16Gms2NzCDZgbVzI +6dhI5U6maGWPRl3KFKiTiPahOHciI56B+lgxDUzGfOThzPrYGYHRBpYOt7f4hPIu +N8UuSHxsT2fZGjWeYjOX0IRU0zeUkt7oZmzJ5ZfYByp+YQGjIFzczmuDca44/DtV +2QZhSQ4EpYRPPPzaS32hOw== + + + + + + + + + + HaW+lb5HQwllprsijEzwKyBd/XSI5Bnbh20hpu9syC8= + + + + 1IDrybztmDAN1aweduNBecVn2sohLHdvrXnlbyG/AkY= + + + UvRcABlbB+dyRFiaiYl3p6bbU2DOD+brzKeX2ky1eRcEyYQhhDbOD5GlHj+yyjXm +LZXaOY392T9QIS0Qq92KxD4XWmFnzeX+q/KdaQtFYzHtQxINRjhfD6CdXLIBg/O3 +zc+s0jUaneLAo3ZEI1v+dxinglLAB1CVdZMhOOYNK1Kk3oE9X+YQFSumhUmBGHnA +IdGAQnVEem+qMoFUuEt+emtqnvzdwuv2Xw2xB/f4LqMA3nBRt/Zkn6sqKZ8QwphM +nnCQlY35/CJdzX7BcCi/agU1hai9Q4UHmDcwwk4+PYL0BQYFQjTssv9R2fht2EBn +zT4uAQ37egPSTEulTc0llw== + + + + dnQualifier=63rNM95i2Qy0MmrcDFMXewtrA\+c=,CN=.dcpomatic.smpte-430-2.INTERMEDIATE,OU=dcpomatic.com,O=dcpomatic.com + 7 + + MIIEaTCCA1GgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBhTEWMBQGA1UEChMNZGNw +b21hdGljLmNvbTEWMBQGA1UECxMNZGNwb21hdGljLmNvbTEsMCoGA1UEAxMjLmRj +cG9tYXRpYy5zbXB0ZS00MzAtMi5JTlRFUk1FRElBVEUxJTAjBgNVBC4THDYzck5N +OTVpMlF5ME1tcmNERk1YZXd0ckErYz0wHhcNMTgwNDE2MTc0NjE4WhcNMjgwNDEx +MTc0NjE4WjB/MRYwFAYDVQQKEw1kY3BvbWF0aWMuY29tMRYwFAYDVQQLEw1kY3Bv +bWF0aWMuY29tMSYwJAYDVQQDEx1DUy5kY3BvbWF0aWMuc21wdGUtNDMwLTIuTEVB +RjElMCMGA1UELhMcWHVpL25wcjE3NlJxaENXTmhINUsra3dEMDZVPTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAML7KTWdJSRq9HDqGoN2fUY6c8fO0wvW +inwR8qcQE2qZXt2swwRJD6pfIzZLHrD/WxNfOne8/+bU1S8OxECZaRDkkW9kReP8 +vSvksFJsAnhenP7KT4VaoCX6D2CTHQYvLGwdQcg0UmRKFbmPxiMcyxO6UCAyYFw+ +kRoeqk7pHwSxhqLCwPiOwiy+3Cv8cygNo3i+yeZTAi0YGOeMD8aEBRfohIlmdOeP +d38pLAJhERH2aOXqTVEEXE6w3d+JzitNpicwi8miSD71wxKi0XNrH47HFhCgE5Wj +KyoFXzAHVZTujTc1MpzBaGoEFiBIVOkp1KDEmnxtOC2NaOjx37/BDrECAwEAAaOB +6DCB5TAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIFoDAdBgNVHQ4EFgQUXui/npr1 +76RqhCWNhH5K+kwD06UwgagGA1UdIwSBoDCBnYAU63rNM95i2Qy0MmrcDFMXewtr +A+ehgYGkfzB9MRYwFAYDVQQKEw1kY3BvbWF0aWMuY29tMRYwFAYDVQQLEw1kY3Bv +bWF0aWMuY29tMSQwIgYDVQQDExsuZGNwb21hdGljLnNtcHRlLTQzMC0yLlJPT1Qx +JTAjBgNVBC4THEJKSzZSMjcrWkYzNTR1NFM0ZitCMFpQclBFTT2CAQYwDQYJKoZI +hvcNAQELBQADggEBAC9NX+aZ5JfOooUDyEpCTdyk7KJsHt7Ye7bxt2IXXgerfPfO +zoBua54GORUtjcWpvXMqzhbfD1mAJu2FwhtbF2MQF2d1sowwWhMa9cnwfqsmDylz +yMFk+meHXTjfZ7AeC6IGnUJOXM1wPCaG3A39rQhP8mWbk1jloF221Gx4Fd4s53t4 +h/zv0ObkP9XiDUhsvqu1/oyysuyLscCXQZL1aWLsKxSfOqunaZjP16MFUyst0GJV +JuoaqQ260nM/wQO7ieE+c80eGu28ov5W3kjtqowjvM8UB4ep3NrJxZ1y/Xypjnyh +WsbVStLDVPHxlorfibB4EzSEKyIDBVVPhXs/hGE= + + + + dnQualifier=BJK6R27\+ZF354u4S4f\+B0ZPrPEM=,CN=.dcpomatic.smpte-430-2.ROOT,OU=dcpomatic.com,O=dcpomatic.com + 6 + + MIIEbTCCA1WgAwIBAgIBBjANBgkqhkiG9w0BAQsFADB9MRYwFAYDVQQKEw1kY3Bv +bWF0aWMuY29tMRYwFAYDVQQLEw1kY3BvbWF0aWMuY29tMSQwIgYDVQQDExsuZGNw +b21hdGljLnNtcHRlLTQzMC0yLlJPT1QxJTAjBgNVBC4THEJKSzZSMjcrWkYzNTR1 +NFM0ZitCMFpQclBFTT0wHhcNMTgwNDE2MTc0NjE3WhcNMjgwNDEyMTc0NjE3WjCB +hTEWMBQGA1UEChMNZGNwb21hdGljLmNvbTEWMBQGA1UECxMNZGNwb21hdGljLmNv +bTEsMCoGA1UEAxMjLmRjcG9tYXRpYy5zbXB0ZS00MzAtMi5JTlRFUk1FRElBVEUx +JTAjBgNVBC4THDYzck5NOTVpMlF5ME1tcmNERk1YZXd0ckErYz0wggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwPTjVL6DwnBgMdGYgIT5nwRA/TtOAOeU5 +Irqqgjj8wKRLa1H5jBxtEHMLwf2jMiR2aXAiorWLUvdiGhC23KV4bTOy4jGgjNNV +3Ij6TnKKqhF7NTfLshh7WO4wQqgChDV5smu2wJL2vHYEhmlJp5BUibyyNJiJc7Vw +223cqJRvIHXFYeclOxlZQnGuU4gDwHZk7hyYxCwdvyr8qt/VBb7oaCvVNw2r/pPB +DDDzWoANOIHaLufaidauCIm8+pH4TER2qNguRvZi8PwSNYpgiePWvpWDTiUUsOge +yknoceg9rAdGNQujUgqJPeKmoxGbTlcw5TdzkCfqBmAGFgcjZrGBAgMBAAGjge4w +geswEgYDVR0TAQH/BAgwBgEB/wIBAjALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFOt6 +zTPeYtkMtDJq3AxTF3sLawPnMIGoBgNVHSMEgaAwgZ2AFASSukdu/mRd+eLuEuH/ +gdGT6zxDoYGBpH8wfTEWMBQGA1UEChMNZGNwb21hdGljLmNvbTEWMBQGA1UECxMN +ZGNwb21hdGljLmNvbTEkMCIGA1UEAxMbLmRjcG9tYXRpYy5zbXB0ZS00MzAtMi5S +T09UMSUwIwYDVQQuExxCSks2UjI3K1pGMzU0dTRTNGYrQjBaUHJQRU09ggEFMA0G +CSqGSIb3DQEBCwUAA4IBAQCjMLdot0fGH4n8ZPbCJX5OLXWm6EXdClsjZlngMTAx +ENB2nvEOxkBte7C400mLFDlFhnGhWJ8boSrN7sEYuFitXA/X5tI50XfHWzl9o/+2 +VWUsEa1D4e+kCmA8kjwf/lzlMnmsdhlPUdsEFEWNbyh4qAC5smhuXKsZxbqZEizA +NK1oJ+Np0Hv4g7tX69uQvw5iWQMGYV/RCxh915ILHWeoKG22Tlcf7AxU5VhkOw5F +Muqu5wgZXbpQ2Mj1ajeL/kwGGI1YbCWm/zHc8jw/LFRWEnCo1wBSkXBHToQVoJF1 +GTtWUcT84jioqTojoFPp1jiOw8oQu8KAFNV9cBH8xShW + + + + dnQualifier=BJK6R27\+ZF354u4S4f\+B0ZPrPEM=,CN=.dcpomatic.smpte-430-2.ROOT,OU=dcpomatic.com,O=dcpomatic.com + 5 + + MIIEZDCCA0ygAwIBAgIBBTANBgkqhkiG9w0BAQsFADB9MRYwFAYDVQQKEw1kY3Bv +bWF0aWMuY29tMRYwFAYDVQQLEw1kY3BvbWF0aWMuY29tMSQwIgYDVQQDExsuZGNw +b21hdGljLnNtcHRlLTQzMC0yLlJPT1QxJTAjBgNVBC4THEJKSzZSMjcrWkYzNTR1 +NFM0ZitCMFpQclBFTT0wHhcNMTgwNDE2MTc0NjE2WhcNMjgwNDEzMTc0NjE2WjB9 +MRYwFAYDVQQKEw1kY3BvbWF0aWMuY29tMRYwFAYDVQQLEw1kY3BvbWF0aWMuY29t +MSQwIgYDVQQDExsuZGNwb21hdGljLnNtcHRlLTQzMC0yLlJPT1QxJTAjBgNVBC4T +HEJKSzZSMjcrWkYzNTR1NFM0ZitCMFpQclBFTT0wggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDeT0ysrx62MNINCICJeUY6GxAJrScKNE0qa3ahRKeslA6n +K4TIpS2uciAFrmvcqpge5HgoMaR3R+mmJGElWruz4gTh/fYU/Lva2EGmwH4UA803 +u0W1HoWqeut11oAUAx3dCmJFORtlOwj+S7sHlyPP3UJLWjIFnemOK3DORNnjlUw1 +sLAaXoi56xHpJysnNzVhXQeVvzT/7njELsxI85UfSZEpUJ3rSQPRl4nrVep5qGug +pFO6prbA8w+SIJ9trTBlmSG8In2QlajQnFsO2Y9wYj8kaLewQco1Prb1qODt/h3m +aeh/+IHjsE494s//zzBNWXbtB5pdKcuVcjnqwELVAgMBAAGjge4wgeswEgYDVR0T +AQH/BAgwBgEB/wIBAzALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFASSukdu/mRd+eLu +EuH/gdGT6zxDMIGoBgNVHSMEgaAwgZ2AFASSukdu/mRd+eLuEuH/gdGT6zxDoYGB +pH8wfTEWMBQGA1UEChMNZGNwb21hdGljLmNvbTEWMBQGA1UECxMNZGNwb21hdGlj +LmNvbTEkMCIGA1UEAxMbLmRjcG9tYXRpYy5zbXB0ZS00MzAtMi5ST09UMSUwIwYD +VQQuExxCSks2UjI3K1pGMzU0dTRTNGYrQjBaUHJQRU09ggEFMA0GCSqGSIb3DQEB +CwUAA4IBAQCgHdUDSWR+8yN+GDKUpXdrhFylFsiP/QWoOS5qSM7QTP7pihEcB2QF +Ay4Z9mn1ZIcUFUund4EKaJTRXNZ8341Tm7wyHbrHTy9rb9c/VFIXDnOJMBi8Ac9O +EM1Z0ZwdBAhmtbm9zUddeHe/lZlPLKTHd+NZ7Pa1hxaamIeCfAiWS5Cmmd7CAOmS +xnaGf0k/0tCDEp86rWdVW1q0JT/0fbh1IO/rtNrHP1Kz86A5Bc4bYsdMTiqkjcFR +KwDhgmLrsGYibIgZ0kmcIaP2pd06zRqWa+fgzH+KQI0Lvk7hjqX5qKWxwpLjES1Q +Kp+MTXgFCZK3CSvMvnmTL9qC5zd3SulH + + + + diff --git a/test/wscript b/test/wscript index b4f526bf..3eaef516 100644 --- a/test/wscript +++ b/test/wscript @@ -69,6 +69,7 @@ def build(bld): obj.source = """ asset_test.cc atmos_test.cc + can_be_read_test.cc certificates_test.cc colour_test.cc colour_conversion_test.cc -- cgit v1.2.3