| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/common/media/component_widevine_cdm_hint_file_linux.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/check.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/important_file_writer.h" |
| #include "base/json/json_string_value_serializer.h" |
| #include "base/logging.h" |
| #include "base/path_service.h" |
| #include "base/values.h" |
| #include "base/version.h" |
| #include "chrome/common/chrome_paths.h" |
| |
| namespace { |
| |
| // Fields used inside the hint file. |
| const char kPath[] = "Path"; |
| const char kLastBundledVersion[] = "LastBundledVersion"; |
| |
| // Returns the hint file contents as a Value::Dict. Returned result may be an |
| // empty dictionary if the hint file does not exist or is formatted incorrectly. |
| base::Value::Dict GetHintFileContents() { |
| base::FilePath hint_file_path; |
| CHECK(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT, |
| &hint_file_path)); |
| |
| DVLOG(1) << __func__ << " checking " << hint_file_path; |
| if (!base::PathExists(hint_file_path)) { |
| DVLOG(1) << "CDM hint file at " << hint_file_path << " does not exist."; |
| return base::Value::Dict(); |
| } |
| |
| std::string json_string; |
| if (!base::ReadFileToString(hint_file_path, &json_string)) { |
| DLOG(ERROR) << "Could not read the CDM hint file at " << hint_file_path; |
| return base::Value::Dict(); |
| } |
| |
| std::string error_message; |
| JSONStringValueDeserializer deserializer(json_string); |
| std::unique_ptr<base::Value> dict = |
| deserializer.Deserialize(/*error_code=*/nullptr, &error_message); |
| |
| if (!dict || !dict->is_dict()) { |
| DLOG(ERROR) << "Could not deserialize the CDM hint file. Error: " |
| << error_message; |
| return base::Value::Dict(); |
| } |
| |
| return std::move(*dict).TakeDict(); |
| } |
| |
| } // namespace |
| |
| bool UpdateWidevineCdmHintFile(const base::FilePath& cdm_base_path, |
| std::optional<base::Version> bundled_version) { |
| DCHECK(!cdm_base_path.empty()); |
| |
| base::FilePath hint_file_path; |
| CHECK(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT, |
| &hint_file_path)); |
| |
| base::Value::Dict dict; |
| dict.Set(kPath, cdm_base_path.value()); |
| if (bundled_version.has_value()) { |
| dict.Set(kLastBundledVersion, bundled_version.value().GetString()); |
| } |
| |
| std::string json_string; |
| JSONStringValueSerializer serializer(&json_string); |
| if (!serializer.Serialize(dict)) { |
| DLOG(ERROR) << "Could not serialize the CDM hint file."; |
| return false; |
| } |
| |
| DVLOG(1) << __func__ << " setting " << cdm_base_path << " to " << json_string; |
| return base::ImportantFileWriter::WriteFileAtomically(hint_file_path, |
| json_string); |
| } |
| |
| base::FilePath GetHintedWidevineCdmDirectory() { |
| base::Value::Dict dict = GetHintFileContents(); |
| |
| auto* path_str = dict.FindString(kPath); |
| if (!path_str) { |
| DVLOG(1) << "CDM hint file missing " << kPath; |
| return base::FilePath(); |
| } |
| |
| const base::FilePath path(*path_str); |
| DLOG_IF(ERROR, path.empty()) |
| << "CDM hint file path " << *path_str << " is invalid."; |
| DVLOG(1) << __func__ << " returns " << path; |
| return path; |
| } |
| |
| std::optional<base::Version> GetBundledVersionDuringLastComponentUpdate() { |
| base::Value::Dict dict = GetHintFileContents(); |
| |
| auto* version_str = dict.FindString(kLastBundledVersion); |
| if (!version_str) { |
| DVLOG(1) << "CDM hint file missing " << kLastBundledVersion; |
| return std::nullopt; |
| } |
| |
| const base::Version version(*version_str); |
| DLOG_IF(ERROR, !version.IsValid()) |
| << "CDM hint file version " << *version_str << " is invalid."; |
| DVLOG(1) << __func__ << " returns " << version; |
| return version; |
| } |