114cf0368Sopenharmony_ci/*
214cf0368Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
314cf0368Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
414cf0368Sopenharmony_ci * you may not use this file except in compliance with the License.
514cf0368Sopenharmony_ci * You may obtain a copy of the License at
614cf0368Sopenharmony_ci *
714cf0368Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
814cf0368Sopenharmony_ci *
914cf0368Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1014cf0368Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1114cf0368Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1214cf0368Sopenharmony_ci * See the License for the specific language governing permissions and
1314cf0368Sopenharmony_ci * limitations under the License.
1414cf0368Sopenharmony_ci */
1514cf0368Sopenharmony_ci#define LOG_TAG "UtdCfgsChecker"
1614cf0368Sopenharmony_ci#include "utd_cfgs_checker.h"
1714cf0368Sopenharmony_ci
1814cf0368Sopenharmony_ci#include <regex>
1914cf0368Sopenharmony_ci#include "utd_graph.h"
2014cf0368Sopenharmony_ci#include "logger.h"
2114cf0368Sopenharmony_ci
2214cf0368Sopenharmony_cinamespace OHOS {
2314cf0368Sopenharmony_cinamespace UDMF {
2414cf0368Sopenharmony_ciconstexpr const char *TYPE_ID_REGEX = "[a-zA-Z0-9/.-]+$";
2514cf0368Sopenharmony_ciconstexpr const char FILE_EXTENSION_PREFIX = '.';
2614cf0368Sopenharmony_ciconstexpr const int32_t MAX_UTD_SIZE = 50;
2714cf0368Sopenharmony_ci
2814cf0368Sopenharmony_ciUtdCfgsChecker::UtdCfgsChecker()
2914cf0368Sopenharmony_ci{
3014cf0368Sopenharmony_ci}
3114cf0368Sopenharmony_ci
3214cf0368Sopenharmony_ciUtdCfgsChecker::~UtdCfgsChecker()
3314cf0368Sopenharmony_ci{
3414cf0368Sopenharmony_ci}
3514cf0368Sopenharmony_ci
3614cf0368Sopenharmony_ciUtdCfgsChecker &UtdCfgsChecker::GetInstance()
3714cf0368Sopenharmony_ci{
3814cf0368Sopenharmony_ci    static auto instance = new UtdCfgsChecker();
3914cf0368Sopenharmony_ci    return *instance;
4014cf0368Sopenharmony_ci}
4114cf0368Sopenharmony_ci
4214cf0368Sopenharmony_cibool UtdCfgsChecker::CheckTypeDescriptors(CustomUtdCfgs &typeCfgs, const std::vector<TypeDescriptorCfg> &presetCfgs,
4314cf0368Sopenharmony_ci    const std::vector<TypeDescriptorCfg> &customCfgs, const std::string &bundleName)
4414cf0368Sopenharmony_ci{
4514cf0368Sopenharmony_ci    if (!CheckTypesFormat(typeCfgs, bundleName)) {
4614cf0368Sopenharmony_ci        LOG_ERROR(UDMF_CLIENT, "CheckTypesFormat not pass, bundleName: %{public}s.", bundleName.c_str());
4714cf0368Sopenharmony_ci        return false;
4814cf0368Sopenharmony_ci    }
4914cf0368Sopenharmony_ci    if (!CheckTypesRelation(typeCfgs, presetCfgs, customCfgs)) {
5014cf0368Sopenharmony_ci        LOG_ERROR(UDMF_CLIENT, "CheckTypesRelation not pass, bundleName: %{public}s.", bundleName.c_str());
5114cf0368Sopenharmony_ci        return false;
5214cf0368Sopenharmony_ci    }
5314cf0368Sopenharmony_ci    return true;
5414cf0368Sopenharmony_ci}
5514cf0368Sopenharmony_ci
5614cf0368Sopenharmony_cibool UtdCfgsChecker::CheckTypesFormat(CustomUtdCfgs &typeCfgs, const std::string &bundleName)
5714cf0368Sopenharmony_ci{
5814cf0368Sopenharmony_ci    for (auto declarationType: typeCfgs.first) {
5914cf0368Sopenharmony_ci        if (!std::regex_match(declarationType.typeId, std::regex(bundleName + TYPE_ID_REGEX))) {
6014cf0368Sopenharmony_ci            LOG_ERROR(UDMF_CLIENT, "Declaration typeId check failed, id: %{public}s, bundleName: %{public}s.",
6114cf0368Sopenharmony_ci                declarationType.typeId.c_str(), bundleName.c_str());
6214cf0368Sopenharmony_ci            return false;
6314cf0368Sopenharmony_ci        }
6414cf0368Sopenharmony_ci    }
6514cf0368Sopenharmony_ci    for (auto referenceTypes: typeCfgs.second) {
6614cf0368Sopenharmony_ci        if (!std::regex_match(referenceTypes.typeId, std::regex(TYPE_ID_REGEX))) {
6714cf0368Sopenharmony_ci            LOG_ERROR(UDMF_CLIENT, "Reference typeId check failed, id: %{public}s, bundleName: %{public}s.",
6814cf0368Sopenharmony_ci                referenceTypes.typeId.c_str(), bundleName.c_str());
6914cf0368Sopenharmony_ci            return false;
7014cf0368Sopenharmony_ci        }
7114cf0368Sopenharmony_ci    }
7214cf0368Sopenharmony_ci    std::vector<TypeDescriptorCfg> inputTypeCfgs;
7314cf0368Sopenharmony_ci    if (!typeCfgs.first.empty()) {
7414cf0368Sopenharmony_ci        inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.first.begin(), typeCfgs.first.end());
7514cf0368Sopenharmony_ci    }
7614cf0368Sopenharmony_ci    if (!typeCfgs.second.empty()) {
7714cf0368Sopenharmony_ci        inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.second.begin(), typeCfgs.second.end());
7814cf0368Sopenharmony_ci    }
7914cf0368Sopenharmony_ci    for (TypeDescriptorCfg &typeCfg : inputTypeCfgs) {
8014cf0368Sopenharmony_ci        for (std::string filenames : typeCfg.filenameExtensions) {
8114cf0368Sopenharmony_ci            if (filenames.size() <= 1 || filenames[0] != FILE_EXTENSION_PREFIX) {
8214cf0368Sopenharmony_ci                LOG_ERROR(UDMF_CLIENT, "Extension not valid, extension: %{public}s, bundleName: %{public}s.",
8314cf0368Sopenharmony_ci                    filenames.c_str(), bundleName.c_str());
8414cf0368Sopenharmony_ci                return false;
8514cf0368Sopenharmony_ci            }
8614cf0368Sopenharmony_ci        }
8714cf0368Sopenharmony_ci        if (typeCfg.belongingToTypes.empty()) {
8814cf0368Sopenharmony_ci            LOG_ERROR(UDMF_CLIENT, "BelongingToTypes can not be empty, bundleName: %{public}s.", bundleName.c_str());
8914cf0368Sopenharmony_ci            return false;
9014cf0368Sopenharmony_ci        }
9114cf0368Sopenharmony_ci        for (std::string mimeType : typeCfg.mimeTypes) {
9214cf0368Sopenharmony_ci            if (mimeType.empty()) {
9314cf0368Sopenharmony_ci                LOG_ERROR(UDMF_CLIENT, "mimeType can not be an empty string, typeId: %{public}s.",
9414cf0368Sopenharmony_ci                    typeCfg.typeId.c_str());
9514cf0368Sopenharmony_ci                return false;
9614cf0368Sopenharmony_ci            }
9714cf0368Sopenharmony_ci        }
9814cf0368Sopenharmony_ci    }
9914cf0368Sopenharmony_ci    return true;
10014cf0368Sopenharmony_ci}
10114cf0368Sopenharmony_ci
10214cf0368Sopenharmony_cibool UtdCfgsChecker::CheckTypesRelation(CustomUtdCfgs &typeCfgs, const std::vector<TypeDescriptorCfg> &presetCfgs,
10314cf0368Sopenharmony_ci    const std::vector<TypeDescriptorCfg> &customCfgs)
10414cf0368Sopenharmony_ci{
10514cf0368Sopenharmony_ci    std::vector<TypeDescriptorCfg> inputTypeCfgs;
10614cf0368Sopenharmony_ci    if (!typeCfgs.first.empty()) {
10714cf0368Sopenharmony_ci        inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.first.begin(), typeCfgs.first.end());
10814cf0368Sopenharmony_ci    }
10914cf0368Sopenharmony_ci    if (!typeCfgs.second.empty()) {
11014cf0368Sopenharmony_ci        inputTypeCfgs.insert(inputTypeCfgs.end(), typeCfgs.second.begin(), typeCfgs.second.end());
11114cf0368Sopenharmony_ci    }
11214cf0368Sopenharmony_ci    std::vector<std::string> typeIds;
11314cf0368Sopenharmony_ci    for (auto &inputTypeCfg: inputTypeCfgs) {
11414cf0368Sopenharmony_ci        typeIds.push_back(inputTypeCfg.typeId);
11514cf0368Sopenharmony_ci    }
11614cf0368Sopenharmony_ci    if (typeIds.size() > MAX_UTD_SIZE) {
11714cf0368Sopenharmony_ci        LOG_ERROR(UDMF_CLIENT, "Create more UTDs than limit.");
11814cf0368Sopenharmony_ci        return false;
11914cf0368Sopenharmony_ci    }
12014cf0368Sopenharmony_ci    for (auto &presetCfg: presetCfgs) {
12114cf0368Sopenharmony_ci        typeIds.push_back(presetCfg.typeId);
12214cf0368Sopenharmony_ci    }
12314cf0368Sopenharmony_ci    if (std::set<std::string>(typeIds.begin(), typeIds.end()).size() != typeIds.size()) {
12414cf0368Sopenharmony_ci        LOG_ERROR(UDMF_CLIENT, "Find duplicated typeIds.");
12514cf0368Sopenharmony_ci        return false;
12614cf0368Sopenharmony_ci    }
12714cf0368Sopenharmony_ci    if (!CheckBelongingToTypes(inputTypeCfgs, presetCfgs)) {
12814cf0368Sopenharmony_ci        LOG_ERROR(UDMF_CLIENT, "BelongingToType check failed.");
12914cf0368Sopenharmony_ci        return false;
13014cf0368Sopenharmony_ci    }
13114cf0368Sopenharmony_ci    if (!CanConstructDAG(typeCfgs, presetCfgs, customCfgs)) {
13214cf0368Sopenharmony_ci        LOG_ERROR(UDMF_CLIENT, "Can not construct DAG.");
13314cf0368Sopenharmony_ci        return false;
13414cf0368Sopenharmony_ci    }
13514cf0368Sopenharmony_ci    return true;
13614cf0368Sopenharmony_ci}
13714cf0368Sopenharmony_ci
13814cf0368Sopenharmony_cibool UtdCfgsChecker::CheckBelongingToTypes(const std::vector<TypeDescriptorCfg> &typeCfgs,
13914cf0368Sopenharmony_ci    const std::vector<TypeDescriptorCfg> &presetCfgs)
14014cf0368Sopenharmony_ci{
14114cf0368Sopenharmony_ci    std::vector<std::string> typeIds;
14214cf0368Sopenharmony_ci    for (auto &typeCfg: typeCfgs) {
14314cf0368Sopenharmony_ci        typeIds.push_back(typeCfg.typeId);
14414cf0368Sopenharmony_ci    }
14514cf0368Sopenharmony_ci    for (auto &presetCfg: presetCfgs) {
14614cf0368Sopenharmony_ci        typeIds.push_back(presetCfg.typeId);
14714cf0368Sopenharmony_ci    }
14814cf0368Sopenharmony_ci    for (auto &inputCfg : typeCfgs) {
14914cf0368Sopenharmony_ci        for (std::string belongingToType : inputCfg.belongingToTypes) {
15014cf0368Sopenharmony_ci            if (belongingToType.empty()) {
15114cf0368Sopenharmony_ci                LOG_ERROR(UDMF_CLIENT, "BelongingToType can not be an empty string, typeId: %{public}s.",
15214cf0368Sopenharmony_ci                    inputCfg.typeId.c_str());
15314cf0368Sopenharmony_ci                return false;
15414cf0368Sopenharmony_ci            }
15514cf0368Sopenharmony_ci            if (inputCfg.typeId == belongingToType) {
15614cf0368Sopenharmony_ci                LOG_ERROR(UDMF_CLIENT, "TypeId cannot equals belongingToType, typeId: %{public}s.",
15714cf0368Sopenharmony_ci                    inputCfg.typeId.c_str());
15814cf0368Sopenharmony_ci                return false;
15914cf0368Sopenharmony_ci            }
16014cf0368Sopenharmony_ci            if (find(typeIds.begin(), typeIds.end(), belongingToType) == typeIds.end()) {
16114cf0368Sopenharmony_ci                LOG_ERROR(UDMF_CLIENT, "BelongingToType can not find in typeids, belongingToType: %{public}s.",
16214cf0368Sopenharmony_ci                    belongingToType.c_str());
16314cf0368Sopenharmony_ci                return false;
16414cf0368Sopenharmony_ci            }
16514cf0368Sopenharmony_ci        }
16614cf0368Sopenharmony_ci    }
16714cf0368Sopenharmony_ci    return true;
16814cf0368Sopenharmony_ci}
16914cf0368Sopenharmony_ci
17014cf0368Sopenharmony_cibool UtdCfgsChecker::CanConstructDAG(CustomUtdCfgs &typeCfgs, const std::vector<TypeDescriptorCfg> &presetCfgs,
17114cf0368Sopenharmony_ci    const std::vector<TypeDescriptorCfg> &customCfgs)
17214cf0368Sopenharmony_ci{
17314cf0368Sopenharmony_ci    std::vector<TypeDescriptorCfg> allTypeCfgs;
17414cf0368Sopenharmony_ci    if (!customCfgs.empty()) {
17514cf0368Sopenharmony_ci        allTypeCfgs.insert(allTypeCfgs.end(), customCfgs.begin(), customCfgs.end());
17614cf0368Sopenharmony_ci    }
17714cf0368Sopenharmony_ci    for (TypeDescriptorCfg &declarationType : typeCfgs.first) {
17814cf0368Sopenharmony_ci        for (auto iter = allTypeCfgs.begin(); iter != allTypeCfgs.end();) {
17914cf0368Sopenharmony_ci            if (iter->typeId == declarationType.typeId) {
18014cf0368Sopenharmony_ci                iter = allTypeCfgs.erase(iter);
18114cf0368Sopenharmony_ci            } else {
18214cf0368Sopenharmony_ci                iter ++;
18314cf0368Sopenharmony_ci            }
18414cf0368Sopenharmony_ci        }
18514cf0368Sopenharmony_ci        allTypeCfgs.push_back(declarationType);
18614cf0368Sopenharmony_ci    }
18714cf0368Sopenharmony_ci    for (TypeDescriptorCfg &referenceTypes : typeCfgs.second) {
18814cf0368Sopenharmony_ci        bool found = false;
18914cf0368Sopenharmony_ci        for (auto &typeCfg : allTypeCfgs) {
19014cf0368Sopenharmony_ci            if (typeCfg.typeId == referenceTypes.typeId) {
19114cf0368Sopenharmony_ci                found = true;
19214cf0368Sopenharmony_ci                break;
19314cf0368Sopenharmony_ci            }
19414cf0368Sopenharmony_ci        }
19514cf0368Sopenharmony_ci        if (!found) {
19614cf0368Sopenharmony_ci            allTypeCfgs.push_back(referenceTypes);
19714cf0368Sopenharmony_ci        }
19814cf0368Sopenharmony_ci    }
19914cf0368Sopenharmony_ci    if (!presetCfgs.empty()) {
20014cf0368Sopenharmony_ci        allTypeCfgs.insert(allTypeCfgs.end(), presetCfgs.begin(), presetCfgs.end());
20114cf0368Sopenharmony_ci    }
20214cf0368Sopenharmony_ci    if (!allTypeCfgs.empty()) {
20314cf0368Sopenharmony_ci        auto graph = UtdGraph::GetInstance().ConstructNewGraph(allTypeCfgs);
20414cf0368Sopenharmony_ci        if (graph->IsDAG()) {
20514cf0368Sopenharmony_ci            return true;
20614cf0368Sopenharmony_ci        }
20714cf0368Sopenharmony_ci    }
20814cf0368Sopenharmony_ci    return false;
20914cf0368Sopenharmony_ci}
21014cf0368Sopenharmony_ci} // namespace UDMF
21114cf0368Sopenharmony_ci} // namespace OHOS
212