1 /*
2 * Copyright (c) 2024-2025 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
16 #define LOG_TAG "UtdClient"
17 #include <fstream>
18 #include <regex>
19 #include <thread>
20 #include "utd_client.h"
21 #include "logger.h"
22 #include "utd_graph.h"
23 #include "custom_utd_store.h"
24
25 namespace OHOS {
26 namespace UDMF {
27 constexpr const int MAX_UTD_LENGTH = 256;
28 constexpr const char *CUSTOM_UTD_HAP_DIR = "/data/utd/utd-adt.json";
29
UtdClient()30 UtdClient::UtdClient()
31 {
32 Init();
33 }
34
~UtdClient()35 UtdClient::~UtdClient()
36 {
37 }
38
GetInstance()39 UtdClient &UtdClient::GetInstance()
40 {
41 static auto instance = new UtdClient();
42 return *instance;
43 }
44
GetHapTypeCfgs()45 std::vector<TypeDescriptorCfg> GetHapTypeCfgs()
46 {
47 LOG_DEBUG(UDMF_CLIENT, "get utdcustom from cfg, Path:%{public}s.", CUSTOM_UTD_HAP_DIR);
48 std::string jsonStr;
49 std::ifstream fin(CUSTOM_UTD_HAP_DIR);
50 while (fin.good()) {
51 std::string line;
52 std::getline(fin, line);
53 jsonStr += line;
54 }
55 std::vector<TypeDescriptorCfg> customUtdTypes;
56 CustomUtdJsonParser utdJsonParser;
57 utdJsonParser.ParseStoredCustomUtdJson(jsonStr, customUtdTypes);
58 LOG_DEBUG(UDMF_CLIENT, "GetTypeCfgs, customUtdTypes total:%{public}zu.", customUtdTypes.size());
59 return customUtdTypes;
60 }
61
Init()62 void UtdClient::Init()
63 {
64 std::unique_lock<std::shared_mutex> lock(utdMutex_);
65 descriptorCfgs_ = PresetTypeDescriptors::GetInstance().GetPresetTypes();
66 std::vector<TypeDescriptorCfg> customTypes;
67 customTypes = GetHapTypeCfgs();
68 LOG_INFO(UDMF_CLIENT, "get customUtd, size:%{public}zu", customTypes.size());
69 if (!customTypes.empty()) {
70 descriptorCfgs_.insert(descriptorCfgs_.end(), customTypes.begin(), customTypes.end());
71 }
72 UtdGraph::GetInstance().InitUtdGraph(descriptorCfgs_);
73 }
74
IsHapTokenType()75 bool UtdClient::IsHapTokenType()
76 {
77 return true;
78 }
79
GetCurrentActiveUserId(int32_t & userId)80 Status UtdClient::GetCurrentActiveUserId(int32_t &userId)
81 {
82 return Status::E_OK;
83 }
84
GetTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)85 Status UtdClient::GetTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
86 {
87 {
88 std::shared_lock<std::shared_mutex> guard(utdMutex_);
89 for (const auto &utdTypeCfg : descriptorCfgs_) {
90 if (utdTypeCfg.typeId == typeId) {
91 descriptor = std::make_shared<TypeDescriptor>(utdTypeCfg);
92 return Status::E_OK;
93 }
94 }
95 }
96 if (typeId.find(FLEXIBLE_TYPE_FLAG) != typeId.npos) {
97 return GetFlexibleTypeDescriptor(typeId, descriptor);
98 }
99 return Status::E_OK;
100 }
101
IsValidFileExtension(const std::string & fileExtension)102 bool UtdClient::IsValidFileExtension(const std::string &fileExtension)
103 {
104 if (fileExtension.empty()) {
105 return false;
106 }
107 if (fileExtension[0] != '.' || fileExtension.find("?") != fileExtension.npos ||
108 fileExtension.find(":") != fileExtension.npos || fileExtension.find("=") != fileExtension.npos ||
109 fileExtension.find("\\") != fileExtension.npos) {
110 return false;
111 }
112
113 return true;
114 }
115
IsValidMimeType(const std::string & mimeType)116 bool UtdClient::IsValidMimeType(const std::string &mimeType)
117 {
118 if (mimeType.empty()) {
119 return false;
120 }
121 if (mimeType.find("?") != mimeType.npos || mimeType.find(":") != mimeType.npos ||
122 mimeType.find("=") != mimeType.npos || mimeType.find("\\") != mimeType.npos) {
123 return false;
124 }
125 return true;
126 }
127
GetFlexibleTypeDescriptor(const std::string & typeId,std::shared_ptr<TypeDescriptor> & descriptor)128 Status UtdClient::GetFlexibleTypeDescriptor(const std::string &typeId, std::shared_ptr<TypeDescriptor> &descriptor)
129 {
130 TypeDescriptorCfg flexibleTypeDescriptorCfg;
131 if (!FlexibleType::ParseFlexibleUtd(typeId, flexibleTypeDescriptorCfg)) {
132 LOG_ERROR(UDMF_CLIENT, "ParseFlexibleUtd failed, invalid typeId");
133 return Status::E_ERROR;
134 }
135 descriptor = std::make_shared<TypeDescriptor>(flexibleTypeDescriptorCfg);
136 return Status::E_OK;
137 }
138
GetUniformDataTypeByFilenameExtension(const std::string & fileExtension,std::string & typeId,std::string belongsTo)139 Status UtdClient::GetUniformDataTypeByFilenameExtension(const std::string &fileExtension, std::string &typeId,
140 std::string belongsTo)
141 {
142 std::string lowerFileExtension = fileExtension;
143 std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
144 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
145 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
146 return Status::E_INVALID_PARAMETERS;
147 }
148 {
149 std::shared_lock<std::shared_mutex> guard(utdMutex_);
150 bool found = false;
151 for (const auto &utdTypeCfg : descriptorCfgs_) {
152 for (auto fileEx : utdTypeCfg.filenameExtensions) {
153 std::transform(fileEx.begin(), fileEx.end(), fileEx.begin(), ::tolower);
154 if (fileEx == lowerFileExtension) {
155 typeId = utdTypeCfg.typeId;
156 found = true;
157 break;
158 }
159 }
160 if (found) {
161 break;
162 }
163 }
164 }
165 // the find typeId is not belongsTo to the belongsTo.
166 if (!typeId.empty() && belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
167 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
168 typeId = "";
169 }
170
171 if (typeId.empty()) {
172 if (!IsValidFileExtension(lowerFileExtension)) {
173 LOG_ERROR(UDMF_CLIENT, "invalid fileExtension.");
174 return Status::E_INVALID_PARAMETERS;
175 }
176 typeId = FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo);
177 }
178 return Status::E_OK;
179 }
180
GetUniformDataTypeByMIMEType(const std::string & mimeType,std::string & typeId,std::string belongsTo)181 Status UtdClient::GetUniformDataTypeByMIMEType(const std::string &mimeType, std::string &typeId,
182 std::string belongsTo)
183 {
184 std::string lowerMimeType = mimeType;
185 std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
186 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
187 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
188 return Status::E_INVALID_PARAMETERS;
189 }
190 typeId = GetTypeIdFromCfg(lowerMimeType);
191 // the find typeId is not belongsTo to the belongsTo.
192 if (!typeId.empty() && belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
193 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
194 typeId = "";
195 }
196 if (typeId.empty()) {
197 if (!IsValidMimeType(mimeType)) {
198 LOG_ERROR(UDMF_CLIENT, "invalid mimeType.");
199 return Status::E_INVALID_PARAMETERS;
200 }
201 typeId = FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo);
202 }
203 return Status::E_OK;
204 }
205
IsUtd(std::string typeId,bool & result)206 Status UtdClient::IsUtd(std::string typeId, bool &result)
207 {
208 if (typeId.empty() || typeId.size() > MAX_UTD_LENGTH) {
209 result = false;
210 return Status::E_INVALID_PARAMETERS;
211 }
212 if (typeId[0] == '.' || find(typeId.begin(), typeId.end(), '/') != typeId.end()) {
213 result = false;
214 return Status::E_OK;
215 }
216 constexpr const char *preSetTypeIdRegexRule =
217 R"(^(general\.|openharmony\.|org\.|com\.|macos\.|debian\.|redhat\.|io\.|de\.|net\.)[a-z0-9-\.]+(\-[a-z0-9-]+)*$)";
218 if (std::regex_match(typeId, std::regex(preSetTypeIdRegexRule))) {
219 result = true;
220 return Status::E_OK;
221 }
222 constexpr const char *customUtdRegexRule =
223 R"(^([A-Za-z]\w*)(\.\w+)+(\.[A-Za-z\d-]+)+)";
224 if (std::regex_match(typeId, std::regex(customUtdRegexRule))) {
225 result = true;
226 return Status::E_OK;
227 }
228 result = false;
229 LOG_ERROR(UDMF_CLIENT, "is not utd");
230 return Status::E_OK;
231 }
232
GetUniformDataTypesByFilenameExtension(const std::string & fileExtension,std::vector<std::string> & typeIds,const std::string & belongsTo)233 Status UtdClient::GetUniformDataTypesByFilenameExtension(const std::string &fileExtension,
234 std::vector<std::string> &typeIds, const std::string &belongsTo)
235 {
236 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
237 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
238 return Status::E_INVALID_PARAMETERS;
239 }
240 if (!IsValidFileExtension(fileExtension)) {
241 LOG_ERROR(UDMF_CLIENT, "invalid fileExtension.");
242 return Status::E_INVALID_PARAMETERS;
243 }
244
245 std::string lowerFileExtension = fileExtension;
246 std::transform(lowerFileExtension.begin(), lowerFileExtension.end(), lowerFileExtension.begin(), ::tolower);
247 std::vector<std::string> typeIdsInCfg;
248 {
249 std::shared_lock<std::shared_mutex> guard(utdMutex_);
250 for (const auto &utdTypeCfg : descriptorCfgs_) {
251 for (auto fileEx : utdTypeCfg.filenameExtensions) {
252 std::transform(fileEx.begin(), fileEx.end(), fileEx.begin(), ::tolower);
253 if (fileEx == lowerFileExtension) {
254 typeIdsInCfg.push_back(utdTypeCfg.typeId);
255 break;
256 }
257 }
258 }
259 }
260 typeIds.clear();
261 for (const auto &typeId : typeIdsInCfg) {
262 // the find typeId is not belongsTo to the belongsTo.
263 if (belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
264 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
265 continue;
266 }
267 typeIds.emplace_back(typeId);
268 }
269 if (typeIds.empty()) {
270 typeIds.emplace_back(FlexibleType::GenFlexibleUtd("", lowerFileExtension, belongsTo));
271 }
272 return Status::E_OK;
273 }
274
GetTypeIdFromCfg(const std::string & mimeType)275 std::string UtdClient::GetTypeIdFromCfg(const std::string &mimeType)
276 {
277 std::shared_lock<std::shared_mutex> guard(utdMutex_);
278 for (const auto &utdTypeCfg : descriptorCfgs_) {
279 for (auto mime : utdTypeCfg.mimeTypes) {
280 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
281 if (mime == mimeType) {
282 return utdTypeCfg.typeId;
283 }
284 }
285 }
286 if (mimeType.empty() || mimeType.back() != '*') {
287 return "";
288 }
289 std::string prefixType = mimeType.substr(0, mimeType.length() - 1);
290 for (const auto &utdTypeCfg : descriptorCfgs_) {
291 for (auto mime : utdTypeCfg.mimeTypes) {
292 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
293 if (mime.rfind(prefixType, 0) == 0 && utdTypeCfg.belongingToTypes.size() > 0) {
294 return utdTypeCfg.belongingToTypes[0];
295 }
296 }
297 }
298 return "";
299 }
300
GetTypeIdsFromCfg(const std::string & mimeType)301 std::vector<std::string> UtdClient::GetTypeIdsFromCfg(const std::string &mimeType)
302 {
303 bool prefixMatch = false;
304 std::string prefixType;
305 if (!mimeType.empty() && mimeType.back() == '*') {
306 prefixType = mimeType.substr(0, mimeType.length() - 1);
307 prefixMatch = true;
308 }
309 std::vector<std::string> typeIdsInCfg;
310
311 std::shared_lock<std::shared_mutex> guard(utdMutex_);
312 for (const auto &utdTypeCfg : descriptorCfgs_) {
313 for (auto mime : utdTypeCfg.mimeTypes) {
314 std::transform(mime.begin(), mime.end(), mime.begin(), ::tolower);
315 if ((mime == mimeType) || (prefixMatch && mime.rfind(prefixType, 0) == 0)) {
316 typeIdsInCfg.push_back(utdTypeCfg.typeId);
317 break;
318 }
319 }
320 }
321 return typeIdsInCfg;
322 }
323
SubscribeUtdChange()324 void UtdClient::SubscribeUtdChange()
325 {
326 }
327
GetUniformDataTypesByMIMEType(const std::string & mimeType,std::vector<std::string> & typeIds,const std::string & belongsTo)328 Status UtdClient::GetUniformDataTypesByMIMEType(const std::string &mimeType, std::vector<std::string> &typeIds,
329 const std::string &belongsTo)
330 {
331 if (belongsTo != DEFAULT_TYPE_ID && !UtdGraph::GetInstance().IsValidType(belongsTo)) {
332 LOG_ERROR(UDMF_CLIENT, "invalid belongsTo.");
333 return Status::E_INVALID_PARAMETERS;
334 }
335 if (!IsValidMimeType(mimeType)) {
336 LOG_ERROR(UDMF_CLIENT, "invalid mimeType.");
337 return Status::E_INVALID_PARAMETERS;
338 }
339
340 std::string lowerMimeType = mimeType;
341 std::transform(lowerMimeType.begin(), lowerMimeType.end(), lowerMimeType.begin(), ::tolower);
342 std::vector<std::string> typeIdsInCfg = GetTypeIdsFromCfg(lowerMimeType);
343 typeIds.clear();
344 for (const auto &typeId : typeIdsInCfg) {
345 // the find typeId is not belongsTo to the belongsTo.
346 if (belongsTo != DEFAULT_TYPE_ID && belongsTo != typeId &&
347 !UtdGraph::GetInstance().IsLowerLevelType(belongsTo, typeId)) {
348 continue;
349 }
350 typeIds.emplace_back(typeId);
351 }
352 if (typeIds.empty()) {
353 typeIds.emplace_back(FlexibleType::GenFlexibleUtd(lowerMimeType, "", belongsTo));
354 }
355 return Status::E_OK;
356 }
357 } // namespace UDMF
358 } // namespace OHOS
359