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