Loading include/input/PropertyMap.h +11 −16 Original line number Diff line number Diff line Loading @@ -18,10 +18,8 @@ #define _UTILS_PROPERTY_MAP_H #include <android-base/result.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/String8.h> #include <utils/Tokenizer.h> #include <unordered_map> namespace android { Loading Loading @@ -58,30 +56,27 @@ public: /* Adds a property. * Replaces the property with the same key if it is already present. */ void addProperty(const String8& key, const String8& value); /* Returns true if the property map contains the specified key. */ bool hasProperty(const String8& key) const; void addProperty(const std::string& key, const std::string& value); /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) */ bool tryGetProperty(const String8& key, String8& outValue) const; bool tryGetProperty(const String8& key, bool& outValue) const; bool tryGetProperty(const String8& key, int32_t& outValue) const; bool tryGetProperty(const String8& key, float& outValue) const; bool tryGetProperty(const std::string& key, std::string& outValue) const; bool tryGetProperty(const std::string& key, bool& outValue) const; bool tryGetProperty(const std::string& key, int32_t& outValue) const; bool tryGetProperty(const std::string& key, float& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); /* Gets the underlying property map. */ inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; } /* Loads a property map from a file. */ static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename); private: /* Returns true if the property map contains the specified key. */ bool hasProperty(const std::string& key) const; class Parser { PropertyMap* mMap; Tokenizer* mTokenizer; Loading @@ -95,11 +90,11 @@ private: status_t parseType(); status_t parseKey(); status_t parseKeyProperty(); status_t parseModifier(const String8& token, int32_t* outMetaState); status_t parseModifier(const std::string& token, int32_t* outMetaState); status_t parseCharacterLiteral(char16_t* outCharacter); }; KeyedVector<String8, String8> mProperties; std::unordered_map<std::string, std::string> mProperties; }; } // namespace android Loading libs/input/Keyboard.cpp +10 −13 Original line number Diff line number Diff line Loading @@ -49,25 +49,23 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { std::string keyLayoutName; if (deviceConfiguration->tryGetProperty("keyboard.layout", keyLayoutName)) { status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", deviceIdentifier.name.c_str(), keyLayoutName.string()); deviceIdentifier.name.c_str(), keyLayoutName.c_str()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { std::string keyCharacterMapName; if (deviceConfiguration->tryGetProperty("keyboard.characterMap", keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", deviceIdentifier.name.c_str(), keyCharacterMapName.string()); deviceIdentifier.name.c_str(), keyCharacterMapName.c_str()); } } Loading Loading @@ -165,7 +163,7 @@ bool isKeyboardSpecialFunction(const PropertyMap* config) { return false; } bool isSpecialFunction = false; config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction); config->tryGetProperty("keyboard.specialFunction", isSpecialFunction); return isSpecialFunction; } Loading @@ -180,8 +178,7 @@ bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, if (deviceConfiguration) { bool builtIn = false; if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) && builtIn) { if (deviceConfiguration->tryGetProperty("keyboard.builtIn", builtIn) && builtIn) { return true; } } Loading libs/input/PropertyMap.cpp +24 −23 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "PropertyMap" #include <input/PropertyMap.h> #include <log/log.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 Loading @@ -39,25 +40,25 @@ void PropertyMap::clear() { mProperties.clear(); } void PropertyMap::addProperty(const String8& key, const String8& value) { mProperties.add(key, value); void PropertyMap::addProperty(const std::string& key, const std::string& value) { mProperties.emplace(key, value); } bool PropertyMap::hasProperty(const String8& key) const { return mProperties.indexOfKey(key) >= 0; bool PropertyMap::hasProperty(const std::string& key) const { return mProperties.find(key) != mProperties.end(); } bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const { ssize_t index = mProperties.indexOfKey(key); if (index < 0) { bool PropertyMap::tryGetProperty(const std::string& key, std::string& outValue) const { auto it = mProperties.find(key); if (it == mProperties.end()) { return false; } outValue = mProperties.valueAt(index); outValue = it->second; return true; } bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { bool PropertyMap::tryGetProperty(const std::string& key, bool& outValue) const { int32_t intValue; if (!tryGetProperty(key, intValue)) { return false; Loading @@ -67,34 +68,34 @@ bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { return true; } bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { String8 stringValue; bool PropertyMap::tryGetProperty(const std::string& key, int32_t& outValue) const { std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; int value = strtol(stringValue.string(), &end, 10); int value = strtol(stringValue.c_str(), &end, 10); if (*end != '\0') { ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.string(), stringValue.string()); ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(), stringValue.c_str()); return false; } outValue = value; return true; } bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { String8 stringValue; bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const { std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; float value = strtof(stringValue.string(), &end); float value = strtof(stringValue.c_str(), &end); if (*end != '\0') { ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.string(), stringValue.string()); ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(), stringValue.c_str()); return false; } outValue = value; Loading @@ -102,8 +103,8 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { } void PropertyMap::addAll(const PropertyMap* map) { for (size_t i = 0; i < map->mProperties.size(); i++) { mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); for (const auto& [key, value] : map->mProperties) { mProperties.emplace(key, value); } } Loading Loading @@ -184,13 +185,13 @@ status_t PropertyMap::Parser::parse() { return BAD_VALUE; } if (mMap->hasProperty(keyToken)) { if (mMap->hasProperty(keyToken.string())) { ALOGE("%s: Duplicate property value for key '%s'.", mTokenizer->getLocation().string(), keyToken.string()); return BAD_VALUE; } mMap->addProperty(keyToken, valueToken); mMap->addProperty(keyToken.string(), valueToken.string()); } mTokenizer->nextLine(); Loading libs/input/PropertyMap_fuzz.cpp +10 −22 Original line number Diff line number Diff line Loading @@ -17,32 +17,22 @@ #include "android-base/file.h" #include "fuzzer/FuzzedDataProvider.h" #include "input/PropertyMap.h" #include "utils/String8.h" static constexpr int MAX_FILE_SIZE = 256; static constexpr int MAX_STR_LEN = 2048; static constexpr int MAX_OPERATIONS = 1000; static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap)>> static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap&)>> operations = { [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { propertyMap.getProperties(); }, [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { [](FuzzedDataProvider*, android::PropertyMap& propertyMap) -> void { propertyMap.clear(); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); android::String8 key = android::String8(keyStr.c_str()); propertyMap.hasProperty(key); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); android::String8 key = android::String8(keyStr.c_str()); android::String8 out; [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); std::string out; propertyMap.tryGetProperty(key, out); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap /*unused*/) -> void { [](FuzzedDataProvider* dataProvider, android::PropertyMap& /*unused*/) -> void { TemporaryFile tf; // Generate file contents std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE); Loading @@ -54,17 +44,15 @@ static const std::vector<std::function<void(FuzzedDataProvider*, android::Proper } android::PropertyMap::load(tf.path); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); android::String8 key = android::String8(keyStr.c_str()); android::String8 val = android::String8(valStr.c_str()); [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); std::string val = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); propertyMap.addProperty(key, val); }, }; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider dataProvider(data, size); android::PropertyMap propertyMap = android::PropertyMap(); android::PropertyMap propertyMap; int opsRun = 0; while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) { Loading services/inputflinger/host/InputDriver.cpp +8 −11 Original line number Diff line number Diff line Loading @@ -240,19 +240,16 @@ input_property_map_t* InputDriver::inputGetDevicePropertyMap(input_device_identi return nullptr; } input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) { String8 keyString(key); input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) { if (map != nullptr) { if (map->propertyMap->hasProperty(keyString)) { auto prop = new input_property_t(); if (!map->propertyMap->tryGetProperty(keyString, prop->value)) { delete prop; std::string value; auto prop = std::make_unique<input_property_t>(); if (!map->propertyMap->tryGetProperty(key, value)) { return nullptr; } prop->key = keyString; return prop; } prop->key = key; prop->value = value.c_str(); return prop.release(); } return nullptr; } Loading Loading
include/input/PropertyMap.h +11 −16 Original line number Diff line number Diff line Loading @@ -18,10 +18,8 @@ #define _UTILS_PROPERTY_MAP_H #include <android-base/result.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/String8.h> #include <utils/Tokenizer.h> #include <unordered_map> namespace android { Loading Loading @@ -58,30 +56,27 @@ public: /* Adds a property. * Replaces the property with the same key if it is already present. */ void addProperty(const String8& key, const String8& value); /* Returns true if the property map contains the specified key. */ bool hasProperty(const String8& key) const; void addProperty(const std::string& key, const std::string& value); /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) */ bool tryGetProperty(const String8& key, String8& outValue) const; bool tryGetProperty(const String8& key, bool& outValue) const; bool tryGetProperty(const String8& key, int32_t& outValue) const; bool tryGetProperty(const String8& key, float& outValue) const; bool tryGetProperty(const std::string& key, std::string& outValue) const; bool tryGetProperty(const std::string& key, bool& outValue) const; bool tryGetProperty(const std::string& key, int32_t& outValue) const; bool tryGetProperty(const std::string& key, float& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); /* Gets the underlying property map. */ inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; } /* Loads a property map from a file. */ static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename); private: /* Returns true if the property map contains the specified key. */ bool hasProperty(const std::string& key) const; class Parser { PropertyMap* mMap; Tokenizer* mTokenizer; Loading @@ -95,11 +90,11 @@ private: status_t parseType(); status_t parseKey(); status_t parseKeyProperty(); status_t parseModifier(const String8& token, int32_t* outMetaState); status_t parseModifier(const std::string& token, int32_t* outMetaState); status_t parseCharacterLiteral(char16_t* outCharacter); }; KeyedVector<String8, String8> mProperties; std::unordered_map<std::string, std::string> mProperties; }; } // namespace android Loading
libs/input/Keyboard.cpp +10 −13 Original line number Diff line number Diff line Loading @@ -49,25 +49,23 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { std::string keyLayoutName; if (deviceConfiguration->tryGetProperty("keyboard.layout", keyLayoutName)) { status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", deviceIdentifier.name.c_str(), keyLayoutName.string()); deviceIdentifier.name.c_str(), keyLayoutName.c_str()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { std::string keyCharacterMapName; if (deviceConfiguration->tryGetProperty("keyboard.characterMap", keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", deviceIdentifier.name.c_str(), keyCharacterMapName.string()); deviceIdentifier.name.c_str(), keyCharacterMapName.c_str()); } } Loading Loading @@ -165,7 +163,7 @@ bool isKeyboardSpecialFunction(const PropertyMap* config) { return false; } bool isSpecialFunction = false; config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction); config->tryGetProperty("keyboard.specialFunction", isSpecialFunction); return isSpecialFunction; } Loading @@ -180,8 +178,7 @@ bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, if (deviceConfiguration) { bool builtIn = false; if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) && builtIn) { if (deviceConfiguration->tryGetProperty("keyboard.builtIn", builtIn) && builtIn) { return true; } } Loading
libs/input/PropertyMap.cpp +24 −23 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "PropertyMap" #include <input/PropertyMap.h> #include <log/log.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 Loading @@ -39,25 +40,25 @@ void PropertyMap::clear() { mProperties.clear(); } void PropertyMap::addProperty(const String8& key, const String8& value) { mProperties.add(key, value); void PropertyMap::addProperty(const std::string& key, const std::string& value) { mProperties.emplace(key, value); } bool PropertyMap::hasProperty(const String8& key) const { return mProperties.indexOfKey(key) >= 0; bool PropertyMap::hasProperty(const std::string& key) const { return mProperties.find(key) != mProperties.end(); } bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const { ssize_t index = mProperties.indexOfKey(key); if (index < 0) { bool PropertyMap::tryGetProperty(const std::string& key, std::string& outValue) const { auto it = mProperties.find(key); if (it == mProperties.end()) { return false; } outValue = mProperties.valueAt(index); outValue = it->second; return true; } bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { bool PropertyMap::tryGetProperty(const std::string& key, bool& outValue) const { int32_t intValue; if (!tryGetProperty(key, intValue)) { return false; Loading @@ -67,34 +68,34 @@ bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { return true; } bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { String8 stringValue; bool PropertyMap::tryGetProperty(const std::string& key, int32_t& outValue) const { std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; int value = strtol(stringValue.string(), &end, 10); int value = strtol(stringValue.c_str(), &end, 10); if (*end != '\0') { ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.string(), stringValue.string()); ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(), stringValue.c_str()); return false; } outValue = value; return true; } bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { String8 stringValue; bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const { std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; float value = strtof(stringValue.string(), &end); float value = strtof(stringValue.c_str(), &end); if (*end != '\0') { ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.string(), stringValue.string()); ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(), stringValue.c_str()); return false; } outValue = value; Loading @@ -102,8 +103,8 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { } void PropertyMap::addAll(const PropertyMap* map) { for (size_t i = 0; i < map->mProperties.size(); i++) { mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); for (const auto& [key, value] : map->mProperties) { mProperties.emplace(key, value); } } Loading Loading @@ -184,13 +185,13 @@ status_t PropertyMap::Parser::parse() { return BAD_VALUE; } if (mMap->hasProperty(keyToken)) { if (mMap->hasProperty(keyToken.string())) { ALOGE("%s: Duplicate property value for key '%s'.", mTokenizer->getLocation().string(), keyToken.string()); return BAD_VALUE; } mMap->addProperty(keyToken, valueToken); mMap->addProperty(keyToken.string(), valueToken.string()); } mTokenizer->nextLine(); Loading
libs/input/PropertyMap_fuzz.cpp +10 −22 Original line number Diff line number Diff line Loading @@ -17,32 +17,22 @@ #include "android-base/file.h" #include "fuzzer/FuzzedDataProvider.h" #include "input/PropertyMap.h" #include "utils/String8.h" static constexpr int MAX_FILE_SIZE = 256; static constexpr int MAX_STR_LEN = 2048; static constexpr int MAX_OPERATIONS = 1000; static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap)>> static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap&)>> operations = { [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { propertyMap.getProperties(); }, [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { [](FuzzedDataProvider*, android::PropertyMap& propertyMap) -> void { propertyMap.clear(); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); android::String8 key = android::String8(keyStr.c_str()); propertyMap.hasProperty(key); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); android::String8 key = android::String8(keyStr.c_str()); android::String8 out; [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); std::string out; propertyMap.tryGetProperty(key, out); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap /*unused*/) -> void { [](FuzzedDataProvider* dataProvider, android::PropertyMap& /*unused*/) -> void { TemporaryFile tf; // Generate file contents std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE); Loading @@ -54,17 +44,15 @@ static const std::vector<std::function<void(FuzzedDataProvider*, android::Proper } android::PropertyMap::load(tf.path); }, [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); android::String8 key = android::String8(keyStr.c_str()); android::String8 val = android::String8(valStr.c_str()); [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); std::string val = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); propertyMap.addProperty(key, val); }, }; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider dataProvider(data, size); android::PropertyMap propertyMap = android::PropertyMap(); android::PropertyMap propertyMap; int opsRun = 0; while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) { Loading
services/inputflinger/host/InputDriver.cpp +8 −11 Original line number Diff line number Diff line Loading @@ -240,19 +240,16 @@ input_property_map_t* InputDriver::inputGetDevicePropertyMap(input_device_identi return nullptr; } input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) { String8 keyString(key); input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) { if (map != nullptr) { if (map->propertyMap->hasProperty(keyString)) { auto prop = new input_property_t(); if (!map->propertyMap->tryGetProperty(keyString, prop->value)) { delete prop; std::string value; auto prop = std::make_unique<input_property_t>(); if (!map->propertyMap->tryGetProperty(key, value)) { return nullptr; } prop->key = keyString; return prop; } prop->key = key; prop->value = value.c_str(); return prop.release(); } return nullptr; } Loading