+
+list<DCPTextTrack>
+Film::closed_caption_tracks () const
+{
+ list<DCPTextTrack> tt;
+ BOOST_FOREACH (shared_ptr<Content> i, content()) {
+ BOOST_FOREACH (shared_ptr<TextContent> j, i->text) {
+ /* XXX: Empty DCPTextTrack ends up being a magic value here - the "unknown" or "not specified" track */
+ DCPTextTrack dtt = j->dcp_track().get_value_or(DCPTextTrack());
+ if (j->type() == TEXT_CLOSED_CAPTION && find(tt.begin(), tt.end(), dtt) == tt.end()) {
+ tt.push_back (dtt);
+ }
+ }
+ }
+
+ return tt;
+}
+
+void
+Film::set_marker (dcp::Marker type, DCPTime time)
+{
+ ChangeSignaller<Film> ch (this, MARKERS);
+ _markers[type] = time;
+}
+
+void
+Film::unset_marker (dcp::Marker type)
+{
+ ChangeSignaller<Film> ch (this, MARKERS);
+ _markers.erase (type);
+}
+
+
+void
+Film::clear_markers ()
+{
+ ChangeSignaller<Film> ch (this, MARKERS);
+ _markers.clear ();
+}
+
+
+void
+Film::set_ratings (vector<dcp::Rating> r)
+{
+ ChangeSignaller<Film> ch (this, RATINGS);
+ _ratings = r;
+}
+
+void
+Film::set_content_version (string v)
+{
+ ChangeSignaller<Film> ch (this, CONTENT_VERSION);
+ _content_version = v;
+}
+
+optional<DCPTime>
+Film::marker (dcp::Marker type) const
+{
+ map<dcp::Marker, DCPTime>::const_iterator i = _markers.find (type);
+ if (i == _markers.end()) {
+ return optional<DCPTime>();
+ }
+ return i->second;
+}
+
+shared_ptr<InfoFileHandle>
+Film::info_file_handle (DCPTimePeriod period, bool read) const
+{
+ return shared_ptr<InfoFileHandle> (new InfoFileHandle(_info_file_mutex, info_file(period), read));
+}
+
+InfoFileHandle::InfoFileHandle (boost::mutex& mutex, boost::filesystem::path file, bool read)
+ : _lock (mutex)
+ , _file (file)
+{
+ if (read) {
+ _handle = fopen_boost (file, "rb");
+ if (!_handle) {
+ throw OpenFileError (file, errno, OpenFileError::READ);
+ }
+ } else {
+ bool const exists = boost::filesystem::exists (file);
+ if (exists) {
+ _handle = fopen_boost (file, "r+b");
+ } else {
+ _handle = fopen_boost (file, "wb");
+ }
+
+ if (!_handle) {
+ throw OpenFileError (file, errno, exists ? OpenFileError::READ_WRITE : OpenFileError::WRITE);
+ }
+ }
+}
+
+InfoFileHandle::~InfoFileHandle ()
+{
+ fclose (_handle);
+}