1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #define LOG_TAG "UtdCfgsChecker"
16 #include "utd_cfgs_checker.h"
17
18 #include <regex>
19 #include "utd_graph.h"
20 #include "logger.h"
21
22 namespace OHOS {
23 namespace UDMF {
24 constexpr const char *TYPE_ID_REGEX = "[a-zA-Z0-9/.-]+$";
25 constexpr const char FILE_EXTENSION_PREFIX = '.';
26 constexpr const int32_t MAX_UTD_SIZE = 50;
27
UtdCfgsChecker()28 UtdCfgsChecker::UtdCfgsChecker()
29 {
30 }
31
~UtdCfgsChecker()32 UtdCfgsChecker::~UtdCfgsChecker()
33 {
34 }
35
GetInstance()36 UtdCfgsChecker &UtdCfgsChecker::GetInstance()
37 {
38 static auto instance = new UtdCfgsChecker();
39 return *instance;
40 }
41
CheckTypeDescriptors(CustomUtdCfgs & typeCfgs,const std::vector<TypeDescriptorCfg> & presetCfgs,const std::vector<TypeDescriptorCfg> & customCfgs,const std::string & bundleName)42 bool UtdCfgsChecker::CheckTypeDescriptors(CustomUtdCfgs &typeCfgs, const std::vector<TypeDescriptorCfg> &presetCfgs,
43 const std::vector<TypeDescriptorCfg> &customCfgs, const std::string &bundleName)
44 {
45 if (!CheckTypesFormat(typeCfgs, bundleName)) {
46 LOG_ERROR(UDMF_CLIENT, "CheckTypesFormat not pass, bundleName: %{public}s.", bundleName.c_str());
47 return false;
48 }
49 if (!CheckTypesRelation(typeCfgs, presetCfgs, customCfgs)) {
50 LOG_ERROR(UDMF_CLIENT, "CheckTypesRelation not pass, bundleName: %{public}s.", bundleName.c_str());
51 return false;
52 }
53 return true;
54 }
55
CheckTypesFormat(CustomUtdCfgs & typeCfgs,const std::string & bundleName)56 bool UtdCfgsChecker::CheckTypesFormat(CustomUtdCfgs &typeCfgs, const std::string &bundleName)
57 {
58 for (auto declarationType: typeCfgs.first) {
59 if (!std::regex_match(declarationType.typeId, std::regex(bundleName + TYPE_ID_REGEX))) {
60 LOG_ERROR(UDMF_CLIENT, "Declaration typeId check failed, id: %{public}s, bundleName: %{public}s.",
61 declarationType.typeId.c_str(), bundleName.c_str());
62 return false;
63 }
64 }
65 for (auto referenceTypes: typeCfgs.second) {
66 if (!std::regex_match(referenceTypes.typeId, std::regex(TYPE_ID_REGEX))) {
67 LOG_ERROR(UDMF_CLIENT, "Reference typeId check failed, id: %{public}s, bundleName: %{public}s.",
68 referenceTypes.typeId.c_str(), bundleName.c_str());
69 return false;
70 }
71 }
72 std::vector<TypeDescriptorCfg> inputTypeCfgs;
73 if (!typeCfgs.first.empty()) {
74 inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.first.begin(), typeCfgs.first.end());
75 }
76 if (!typeCfgs.second.empty()) {
77 inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.second.begin(), typeCfgs.second.end());
78 }
79 for (TypeDescriptorCfg &typeCfg : inputTypeCfgs) {
80 for (std::string filenames : typeCfg.filenameExtensions) {
81 if (filenames.size() <= 1 || filenames[0] != FILE_EXTENSION_PREFIX) {
82 LOG_ERROR(UDMF_CLIENT, "Extension not valid, extension: %{public}s, bundleName: %{public}s.",
83 filenames.c_str(), bundleName.c_str());
84 return false;
85 }
86 }
87 if (typeCfg.belongingToTypes.empty()) {
88 LOG_ERROR(UDMF_CLIENT, "BelongingToTypes can not be empty, bundleName: %{public}s.", bundleName.c_str());
89 return false;
90 }
91 for (std::string mimeType : typeCfg.mimeTypes) {
92 if (mimeType.empty()) {
93 LOG_ERROR(UDMF_CLIENT, "mimeType can not be an empty string, typeId: %{public}s.",
94 typeCfg.typeId.c_str());
95 return false;
96 }
97 }
98 }
99 return true;
100 }
101
CheckTypesRelation(CustomUtdCfgs & typeCfgs,const std::vector<TypeDescriptorCfg> & presetCfgs,const std::vector<TypeDescriptorCfg> & customCfgs)102 bool UtdCfgsChecker::CheckTypesRelation(CustomUtdCfgs &typeCfgs, const std::vector<TypeDescriptorCfg> &presetCfgs,
103 const std::vector<TypeDescriptorCfg> &customCfgs)
104 {
105 std::vector<TypeDescriptorCfg> inputTypeCfgs;
106 if (!typeCfgs.first.empty()) {
107 inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.first.begin(), typeCfgs.first.end());
108 }
109 if (!typeCfgs.second.empty()) {
110 inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.second.begin(), typeCfgs.second.end());
111 }
112 std::vector<std::string> typeIds;
113 for (auto &inputTypeCfg: inputTypeCfgs) {
114 typeIds.push_back(inputTypeCfg.typeId);
115 }
116 if (typeIds.size() > MAX_UTD_SIZE) {
117 LOG_ERROR(UDMF_CLIENT, "Create more UTDs than limit.");
118 return false;
119 }
120 for (auto &presetCfg: presetCfgs) {
121 typeIds.push_back(presetCfg.typeId);
122 }
123 if (std::set<std::string>(typeIds.begin(), typeIds.end()).size() != typeIds.size()) {
124 LOG_ERROR(UDMF_CLIENT, "Find duplicated typeIds.");
125 return false;
126 }
127 if (!CheckBelongingToTypes(inputTypeCfgs, presetCfgs)) {
128 LOG_ERROR(UDMF_CLIENT, "BelongingToType check failed.");
129 return false;
130 }
131 if (!CanConstructDAG(typeCfgs, presetCfgs, customCfgs)) {
132 LOG_ERROR(UDMF_CLIENT, "Can not construct DAG.");
133 return false;
134 }
135 return true;
136 }
137
CheckBelongingToTypes(const std::vector<TypeDescriptorCfg> & typeCfgs,const std::vector<TypeDescriptorCfg> & presetCfgs)138 bool UtdCfgsChecker::CheckBelongingToTypes(const std::vector<TypeDescriptorCfg> &typeCfgs,
139 const std::vector<TypeDescriptorCfg> &presetCfgs)
140 {
141 std::vector<std::string> typeIds;
142 for (auto &typeCfg: typeCfgs) {
143 typeIds.push_back(typeCfg.typeId);
144 }
145 for (auto &presetCfg: presetCfgs) {
146 typeIds.push_back(presetCfg.typeId);
147 }
148 for (auto &inputCfg : typeCfgs) {
149 for (std::string belongingToType : inputCfg.belongingToTypes) {
150 if (belongingToType.empty()) {
151 LOG_ERROR(UDMF_CLIENT, "BelongingToType can not be an empty string, typeId: %{public}s.",
152 inputCfg.typeId.c_str());
153 return false;
154 }
155 if (inputCfg.typeId == belongingToType) {
156 LOG_ERROR(UDMF_CLIENT, "TypeId cannot equals belongingToType, typeId: %{public}s.",
157 inputCfg.typeId.c_str());
158 return false;
159 }
160 if (find(typeIds.begin(), typeIds.end(), belongingToType) == typeIds.end()) {
161 LOG_ERROR(UDMF_CLIENT, "BelongingToType can not find in typeids, belongingToType: %{public}s.",
162 belongingToType.c_str());
163 return false;
164 }
165 }
166 }
167 return true;
168 }
169
CanConstructDAG(CustomUtdCfgs & typeCfgs,const std::vector<TypeDescriptorCfg> & presetCfgs,const std::vector<TypeDescriptorCfg> & customCfgs)170 bool UtdCfgsChecker::CanConstructDAG(CustomUtdCfgs &typeCfgs, const std::vector<TypeDescriptorCfg> &presetCfgs,
171 const std::vector<TypeDescriptorCfg> &customCfgs)
172 {
173 std::vector<TypeDescriptorCfg> allTypeCfgs;
174 if (!customCfgs.empty()) {
175 allTypeCfgs.insert(allTypeCfgs.end(), customCfgs.begin(), customCfgs.end());
176 }
177 for (TypeDescriptorCfg &declarationType : typeCfgs.first) {
178 for (auto iter = allTypeCfgs.begin(); iter != allTypeCfgs.end();) {
179 if (iter->typeId == declarationType.typeId) {
180 iter = allTypeCfgs.erase(iter);
181 } else {
182 iter ++;
183 }
184 }
185 allTypeCfgs.push_back(declarationType);
186 }
187 for (TypeDescriptorCfg &referenceTypes : typeCfgs.second) {
188 bool found = false;
189 for (auto &typeCfg : allTypeCfgs) {
190 if (typeCfg.typeId == referenceTypes.typeId) {
191 found = true;
192 break;
193 }
194 }
195 if (!found) {
196 allTypeCfgs.push_back(referenceTypes);
197 }
198 }
199 if (!presetCfgs.empty()) {
200 allTypeCfgs.insert(allTypeCfgs.end(), presetCfgs.begin(), presetCfgs.end());
201 }
202 if (!allTypeCfgs.empty()) {
203 auto graph = UtdGraph::GetInstance().ConstructNewGraph(allTypeCfgs);
204 if (graph->IsDAG()) {
205 return true;
206 }
207 }
208 return false;
209 }
210 } // namespace UDMF
211 } // namespace OHOS
212