mirror of
https://github.com/openharmony/developtools_global_resource_tool.git
synced 2026-07-18 09:14:48 -04:00
@@ -41,6 +41,7 @@ ohos_executable("restool") {
|
||||
"src/resource_table.cpp",
|
||||
"src/resource_util.cpp",
|
||||
"src/restool.cpp",
|
||||
"src/select_compile_parse.cpp",
|
||||
"src/task_handle.cpp",
|
||||
]
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
const std::string &GetIdDefinedOutput() const;
|
||||
const std::string &GetIdDefinedInputPath() const;
|
||||
bool GetIconCheck() const;
|
||||
const TargetConfig &GetTargetConfigValues() const;
|
||||
bool IsTargetConfig() const;
|
||||
|
||||
private:
|
||||
void InitCommand();
|
||||
@@ -79,6 +81,7 @@ private:
|
||||
bool IsAscii(const std::string& argValue) const;
|
||||
bool IsLongOpt(char *argv[]) const;
|
||||
uint32_t IconCheck();
|
||||
uint32_t ParseTargetConfig(const std::string& argValue);
|
||||
|
||||
static const struct option CMD_OPTS[];
|
||||
static const std::string CMD_PARAMS;
|
||||
@@ -100,6 +103,8 @@ private:
|
||||
std::string idDefinedOutput_;
|
||||
std::string idDefinedInputPath_;
|
||||
bool isIconCheck_ = false;
|
||||
TargetConfig targetConfig_;
|
||||
bool isTtargetConfig_;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
@@ -140,6 +145,7 @@ void CmdParser<T>::ShowUseage()
|
||||
std::cout << " --dependEntry Build result directory of the specified entry module when the feature";
|
||||
std::cout << " module resources are independently built in the FA model.\n";
|
||||
std::cout << " --icon-check Enable the PNG image verification function for icons and startwindows.\n";
|
||||
std::cout << " --target-config When used with '-i', selective compilation is supported.\n";
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace Restool {
|
||||
class KeyParser {
|
||||
public:
|
||||
static bool Parse(const std::string &folderName, std::vector<KeyParam> &keyparams);
|
||||
static bool ParseLimit(const std::string &func, std::vector<std::string> &limitValues,
|
||||
TargetConfig &targetConfig);
|
||||
|
||||
private:
|
||||
typedef bool (*parse_key_founction)(const std::string &folderName, std::vector<KeyParam> &keyparams);
|
||||
|
||||
+54
-1
@@ -39,7 +39,7 @@ const static std::string LONG_PATH_HEAD = "\\\\?\\";
|
||||
const static std::string ID_DEFINED_INDENTATION = " ";
|
||||
const static int32_t VERSION_MAX_LEN = 128;
|
||||
const static int32_t INT_TO_BYTES = sizeof(uint32_t);
|
||||
static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 4.103" };
|
||||
static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 4.104" };
|
||||
const static int32_t TAG_LEN = 4;
|
||||
|
||||
enum class KeyType {
|
||||
@@ -55,6 +55,7 @@ enum class KeyType {
|
||||
// RESERVER 9
|
||||
INPUTDEVICE = 10,
|
||||
KEY_TYPE_MAX,
|
||||
OTHER,
|
||||
};
|
||||
|
||||
enum class ResType {
|
||||
@@ -117,6 +118,7 @@ enum Option {
|
||||
DEFINED_IDS = 2,
|
||||
DEPENDENTRY = 3,
|
||||
ICON_CHECK = 4,
|
||||
TARGET_CONFIG = 5,
|
||||
STARTID = 'e',
|
||||
FORCEWRITE = 'f',
|
||||
HELP = 'h',
|
||||
@@ -169,6 +171,10 @@ const std::map<std::string, InputDevice> g_inputDeviceMap = {
|
||||
struct KeyParam {
|
||||
KeyType keyType;
|
||||
uint32_t value;
|
||||
bool operator == (const KeyParam &other)
|
||||
{
|
||||
return keyType == other.keyType && value == other.value;
|
||||
}
|
||||
};
|
||||
|
||||
struct IdData {
|
||||
@@ -250,6 +256,53 @@ struct FileInfo : DirectoryInfo {
|
||||
std::string filename;
|
||||
ResType fileType;
|
||||
};
|
||||
|
||||
struct TargetConfig {
|
||||
std::vector<KeyParam> mccmnc;
|
||||
std::vector<KeyParam> locale;
|
||||
std::vector<KeyParam> orientation;
|
||||
std::vector<KeyParam> device;
|
||||
std::vector<KeyParam> colormode;
|
||||
std::vector<KeyParam> density;
|
||||
};
|
||||
|
||||
struct Mccmnc {
|
||||
KeyParam mcc;
|
||||
KeyParam mnc;
|
||||
bool operator == (const Mccmnc &other)
|
||||
{
|
||||
if (mcc.value != other.mcc.value) {
|
||||
return false;
|
||||
}
|
||||
if (mnc.keyType != KeyType::OTHER && other.mnc.keyType != KeyType::OTHER &&
|
||||
mnc.value != other.mnc.value) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Locale {
|
||||
KeyParam language;
|
||||
KeyParam script;
|
||||
KeyParam region;
|
||||
bool operator == (const Locale &other)
|
||||
{
|
||||
if (language.value != other.language.value) {
|
||||
return false;
|
||||
}
|
||||
if (script.keyType != KeyType::OTHER && other.script.keyType != KeyType::OTHER &&
|
||||
script.value != other.script.value) {
|
||||
return false;
|
||||
}
|
||||
if (region.keyType != KeyType::OTHER && other.region.keyType != KeyType::OTHER &&
|
||||
region.value != other.region.value) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +216,12 @@ public:
|
||||
*/
|
||||
static bool isUnicodeInPlane15or16(int unicode);
|
||||
|
||||
/**
|
||||
* @brief Remove spaces before and after strings
|
||||
* @param str input string
|
||||
*/
|
||||
static void RemoveSpaces(std::string &str);
|
||||
|
||||
private:
|
||||
enum class IgnoreType {
|
||||
IGNORE_FILE,
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_RESTOOL_SELECT_COMPILE_PARSE_H
|
||||
#define OHOS_RESTOOL_SELECT_COMPILE_PARSE_H
|
||||
|
||||
#include "resource_data.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace Global {
|
||||
namespace Restool {
|
||||
class SelectCompileParse {
|
||||
public:
|
||||
static bool ParseTargetConfig(const std::string &limitParams, TargetConfig &targetConfig);
|
||||
static bool IsSelectCompile(std::vector<KeyParam> &keyParams);
|
||||
|
||||
private:
|
||||
static bool IsSelectableMccmnc(std::vector<KeyParam> &keyParams, size_t &index, std::vector<KeyParam> &limit);
|
||||
static bool IsSelectableLocale(std::vector<KeyParam> &keyParams, size_t &index, std::vector<KeyParam> &limit);
|
||||
static bool IsSelectableOther(std::vector<KeyParam> &keyParams, size_t &index, std::vector<KeyParam> &limit);
|
||||
static void InitMccmnc(std::vector<KeyParam> &limit);
|
||||
static void InitLocale(std::vector<KeyParam> &limit);
|
||||
static std::vector<Mccmnc> mccmncArray_;
|
||||
static std::vector<Locale> localeArray_;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <algorithm>
|
||||
#include "cmd_list.h"
|
||||
#include "resource_util.h"
|
||||
#include "select_compile_parse.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace Global {
|
||||
@@ -40,6 +41,7 @@ const struct option PackageParser::CMD_OPTS[] = {
|
||||
{ "ids", required_argument, nullptr, Option::IDS},
|
||||
{ "defined-ids", required_argument, nullptr, Option::DEFINED_IDS},
|
||||
{ "icon-check", no_argument, nullptr, Option::ICON_CHECK},
|
||||
{ "target-config", required_argument, nullptr, Option::TARGET_CONFIG},
|
||||
{ 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
@@ -242,9 +244,15 @@ uint32_t PackageParser::CheckParam() const
|
||||
return RESTOOL_ERROR;
|
||||
}
|
||||
|
||||
if (isTtargetConfig_ && !append_.empty()) {
|
||||
cerr << "Error: -x and --target-config cannot be used together." << endl;
|
||||
return RESTOOL_ERROR;
|
||||
}
|
||||
|
||||
if (!append_.empty()) {
|
||||
return RESTOOL_SUCCESS;
|
||||
}
|
||||
|
||||
if (packageName_.empty()) {
|
||||
cerr << "Error: package name empty." << endl;
|
||||
return RESTOOL_ERROR;
|
||||
@@ -350,6 +358,30 @@ bool PackageParser::GetIconCheck() const
|
||||
return isIconCheck_;
|
||||
}
|
||||
|
||||
uint32_t PackageParser::ParseTargetConfig(const string& argValue)
|
||||
{
|
||||
if (isTtargetConfig_) {
|
||||
cerr << "Error: repeat input '--target-config'" << endl;
|
||||
return RESTOOL_ERROR;
|
||||
}
|
||||
if (!SelectCompileParse::ParseTargetConfig(argValue, targetConfig_)) {
|
||||
cerr << "Error: '" << argValue << "' is not valid parameter." << endl;
|
||||
return RESTOOL_ERROR;
|
||||
}
|
||||
isTtargetConfig_ = true;
|
||||
return RESTOOL_SUCCESS;
|
||||
}
|
||||
|
||||
const TargetConfig &PackageParser::GetTargetConfigValues() const
|
||||
{
|
||||
return targetConfig_;
|
||||
}
|
||||
|
||||
bool PackageParser::IsTargetConfig() const
|
||||
{
|
||||
return isTtargetConfig_;
|
||||
}
|
||||
|
||||
bool PackageParser::IsAscii(const string& argValue) const
|
||||
{
|
||||
#ifdef __WIN32
|
||||
@@ -386,6 +418,7 @@ void PackageParser::InitCommand()
|
||||
handles_.emplace(Option::IDS, bind(&PackageParser::SetIdDefinedOutput, this, _1));
|
||||
handles_.emplace(Option::DEFINED_IDS, bind(&PackageParser::SetIdDefinedInputPath, this, _1));
|
||||
handles_.emplace(Option::ICON_CHECK, [this](const string &) -> uint32_t { return IconCheck(); });
|
||||
handles_.emplace(Option::TARGET_CONFIG, bind(&PackageParser::ParseTargetConfig, this, _1));
|
||||
}
|
||||
|
||||
uint32_t PackageParser::HandleProcess(int c, const string& argValue)
|
||||
|
||||
@@ -73,6 +73,37 @@ bool KeyParser::ParseMatch(const vector<string> &keys,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyParser::ParseLimit(const string &func, std::vector<std::string> &limitValues,
|
||||
TargetConfig &targetConfig)
|
||||
{
|
||||
map<string, function<bool(const string &)>> parseLimitFunc {
|
||||
{"mccmnc", [&targetConfig](const string &limitValue) { return ParseMccMnc(limitValue,
|
||||
targetConfig.mccmnc); }},
|
||||
{"locale", [&targetConfig](const string &limitValue) { return ParseLSR(limitValue,
|
||||
targetConfig.locale); }},
|
||||
{"orientation", [&targetConfig](const string &limitValue) { return ParseOrientation(limitValue,
|
||||
targetConfig.orientation); }},
|
||||
{"device", [&targetConfig](const string &limitValue) { return ParseDeviceType(limitValue,
|
||||
targetConfig.device); }},
|
||||
{"colormode", [&targetConfig](const string &limitValue) { return ParseNightMode(limitValue,
|
||||
targetConfig.colormode); }},
|
||||
{"density", [&targetConfig](const string &limitValue) { return ParseResolution(limitValue,
|
||||
targetConfig.density); }}
|
||||
};
|
||||
|
||||
auto iter = parseLimitFunc.find(func);
|
||||
if (iter == parseLimitFunc.end()) {
|
||||
return false;
|
||||
}
|
||||
for (auto &limitValue : limitValues) {
|
||||
ResourceUtil::RemoveSpaces(limitValue);
|
||||
if (!iter->second(limitValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyParser::ParseMatchBySeq(const vector<string> &keys,
|
||||
vector<KeyParam> &keyparams, const vector<parse_key_founction> &founctions)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "reference_parser.h"
|
||||
#include "resource_table.h"
|
||||
#include "resource_util.h"
|
||||
#include "select_compile_parse.h"
|
||||
#ifdef __WIN32
|
||||
#include "windows.h"
|
||||
#endif
|
||||
@@ -532,6 +533,9 @@ bool ResourceAppend::LoadResourceItemFromMem(const char buffer[], int32_t length
|
||||
keyParam.value = ParseInt32(buffer, length, offset);
|
||||
keyParams.push_back(keyParam);
|
||||
}
|
||||
if (limitKeyStr != "base" && !limitKeyStr.empty() && !SelectCompileParse::IsSelectCompile(keyParams)) {
|
||||
return true;
|
||||
}
|
||||
// data
|
||||
string data = ParseString(buffer, length, offset);
|
||||
if (resType == ResType::RAW) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include<iostream>
|
||||
#include "file_entry.h"
|
||||
#include "resource_util.h"
|
||||
#include "select_compile_parse.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace Global {
|
||||
@@ -60,7 +61,9 @@ bool ResourceDirectory::ScanResourceLimitKeyDir(const string &resourceTypeDir, c
|
||||
cerr << "Error: invalid limit key '" << limitKey << "'." << NEW_LINE_PATH << resourceTypeDir << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SelectCompileParse::IsSelectCompile(keyParams)) {
|
||||
return true;
|
||||
}
|
||||
FileEntry f(resourceTypeDir);
|
||||
if (!f.Init()) {
|
||||
return false;
|
||||
|
||||
@@ -428,6 +428,12 @@ bool ResourceUtil::isUnicodeInPlane15or16(int unicode)
|
||||
return (unicode >= 0xF0000 && unicode <= 0xFFFFF) || (unicode >= 0x100000 && unicode <= 0x10FFFF);
|
||||
}
|
||||
|
||||
void ResourceUtil::RemoveSpaces(string &str)
|
||||
{
|
||||
str.erase(0, str.find_first_not_of(" "));
|
||||
str.erase(str.find_last_not_of(" ") + 1); // move back one place
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "select_compile_parse.h"
|
||||
#include <algorithm>
|
||||
#include "key_parser.h"
|
||||
#include "cmd_parser.h"
|
||||
#include "resource_util.h"
|
||||
|
||||
namespace OHOS {
|
||||
namespace Global {
|
||||
namespace Restool {
|
||||
using namespace std;
|
||||
vector<Mccmnc> SelectCompileParse::mccmncArray_ = {};
|
||||
vector<Locale> SelectCompileParse::localeArray_ = {};
|
||||
|
||||
// eg: Device[ phone, car ];ColorMode[ dark ]
|
||||
bool SelectCompileParse::ParseTargetConfig(const string &limitParams, TargetConfig &targetConfig)
|
||||
{
|
||||
vector<string> limitArray;
|
||||
ResourceUtil::Split(limitParams, limitArray, ";");
|
||||
if (limitArray.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (auto &it : limitArray) {
|
||||
vector<string> limit;
|
||||
ResourceUtil::Split(it, limit, "[");
|
||||
if (limit.size() != 2) { // 2 means the size of the valid parameter after split by '['
|
||||
return false;
|
||||
}
|
||||
ResourceUtil::RemoveSpaces(limit.back());
|
||||
if (limit.size() < 2 || limit.back().back() != ']') { // 2 means characters other than ']'
|
||||
return false;
|
||||
}
|
||||
limit.back().pop_back();
|
||||
vector<string> limitValues;
|
||||
ResourceUtil::Split(limit.back(), limitValues, ",");
|
||||
if (limitValues.empty()) {
|
||||
return false;
|
||||
}
|
||||
auto &limitType = limit.front();
|
||||
ResourceUtil::RemoveSpaces(limitType);
|
||||
transform(limitType.begin(), limitType.end(), limitType.begin(), ::tolower);
|
||||
if (!KeyParser::ParseLimit(limitType, limitValues, targetConfig)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SelectCompileParse::IsSelectCompile(vector<KeyParam> &keyParams)
|
||||
{
|
||||
if (keyParams.empty()) {
|
||||
return true;
|
||||
}
|
||||
auto &cmdParser = CmdParser<PackageParser>::GetInstance().GetCmdParser();
|
||||
bool isTtargetConfig = cmdParser.IsTargetConfig();
|
||||
if (!isTtargetConfig) {
|
||||
return true;
|
||||
}
|
||||
TargetConfig targetConfig = cmdParser.GetTargetConfigValues();
|
||||
map<KeyType, function<bool(size_t &)>> selectableFuncMatch {
|
||||
{KeyType::MCC, bind(&IsSelectableMccmnc, keyParams, placeholders::_1, targetConfig.mccmnc)},
|
||||
{KeyType::LANGUAGE, bind(&IsSelectableLocale, keyParams, placeholders::_1, targetConfig.locale)},
|
||||
{KeyType::ORIENTATION, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.orientation)},
|
||||
{KeyType::DEVICETYPE, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.device)},
|
||||
{KeyType::NIGHTMODE, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.colormode)},
|
||||
{KeyType::RESOLUTION, bind(&IsSelectableOther, keyParams, placeholders::_1, targetConfig.density)},
|
||||
};
|
||||
for (size_t index = 0; index < keyParams.size(); index++) {
|
||||
auto iter = selectableFuncMatch.find(keyParams[index].keyType);
|
||||
if (iter == selectableFuncMatch.end()) {
|
||||
continue;
|
||||
}
|
||||
if (!iter->second(index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// {KeyType::OTHER, 0} indicates that the default value is equal to null
|
||||
void SelectCompileParse::InitMccmnc(vector<KeyParam> &limit)
|
||||
{
|
||||
if (!mccmncArray_.empty()) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < limit.size(); i++) {
|
||||
if (limit[i].keyType == KeyType::MCC) {
|
||||
mccmncArray_.push_back({limit[i], {KeyType::OTHER, 0}});
|
||||
}
|
||||
if (limit[i].keyType == KeyType::MNC) {
|
||||
mccmncArray_.back().mnc = limit[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SelectCompileParse::IsSelectableMccmnc(vector<KeyParam> &keyParams, size_t &index, vector<KeyParam> &limit)
|
||||
{
|
||||
if (limit.empty()) {
|
||||
return true;
|
||||
}
|
||||
Mccmnc mccmncLimit({keyParams[index++], {KeyType::OTHER, 0}});
|
||||
if (index < keyParams.size() && keyParams[index].keyType == KeyType::MNC) {
|
||||
mccmncLimit.mnc = keyParams[index];
|
||||
} else {
|
||||
index--;
|
||||
}
|
||||
InitMccmnc(limit);
|
||||
return find(mccmncArray_.begin(), mccmncArray_.end(), mccmncLimit) != mccmncArray_.end();
|
||||
}
|
||||
|
||||
void SelectCompileParse::InitLocale(vector<KeyParam> &limit)
|
||||
{
|
||||
if (!localeArray_.empty()) {
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < limit.size(); i++) {
|
||||
if (limit[i].keyType == KeyType::LANGUAGE) {
|
||||
localeArray_.push_back({limit[i], {KeyType::OTHER, 0},
|
||||
{KeyType::OTHER, 0}});
|
||||
}
|
||||
if (limit[i].keyType == KeyType::SCRIPT) {
|
||||
localeArray_.back().script = limit[i];
|
||||
}
|
||||
if (limit[i].keyType == KeyType::REGION) {
|
||||
localeArray_.back().region = limit[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SelectCompileParse::IsSelectableLocale(vector<KeyParam> &keyParams, size_t &index, vector<KeyParam> &limit)
|
||||
{
|
||||
if (limit.empty()) {
|
||||
return true;
|
||||
}
|
||||
Locale localeLimit({keyParams[index++], {KeyType::OTHER, 0}, {KeyType::OTHER, 0}});
|
||||
for (; index < keyParams.size(); index++) {
|
||||
if (keyParams[index].keyType == KeyType::SCRIPT) {
|
||||
localeLimit.script = keyParams[index];
|
||||
continue;
|
||||
}
|
||||
if (keyParams[index].keyType == KeyType::REGION) {
|
||||
localeLimit.region = keyParams[index];
|
||||
break;
|
||||
}
|
||||
index--;
|
||||
break;
|
||||
}
|
||||
InitLocale(limit);
|
||||
return find(localeArray_.begin(), localeArray_.end(), localeLimit) != localeArray_.end();;
|
||||
}
|
||||
|
||||
bool SelectCompileParse::IsSelectableOther(vector<KeyParam> &keyParams, size_t &index, vector<KeyParam> &limit)
|
||||
{
|
||||
if (limit.empty()) {
|
||||
return true;
|
||||
}
|
||||
return find(limit.begin(), limit.end(), keyParams[index]) != limit.end();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user