| /* |
| * |
| * Copyright (c) 2021-2022 Project CHIP Authors |
| * |
| * 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 "AppPreference.h" |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <cstring> |
| #include <memory> |
| #include <utility> |
| |
| #include <app_preference.h> |
| #include <tizen.h> |
| |
| #include <lib/support/Base64.h> |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/ScopedBuffer.h> |
| #include <lib/support/Span.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| |
| namespace chip { |
| namespace DeviceLayer { |
| namespace PersistedStorage { |
| namespace Internal { |
| namespace AppPreference { |
| |
| CHIP_ERROR CheckData(const char * key) |
| { |
| bool isExist = false; |
| int err = preference_is_existing(key, &isExist); |
| VerifyOrReturnError(err == PREFERENCE_ERROR_NONE, CHIP_ERROR_INCORRECT_STATE); |
| return isExist ? CHIP_NO_ERROR : CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; |
| } |
| |
| CHIP_ERROR GetData(const char * key, void * data, size_t dataSize, size_t * getDataSize, size_t offset) |
| { |
| VerifyOrReturnError(data != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| char * encodedData = nullptr; |
| // Make sure that string allocated by preference_get_string() will be freed |
| std::unique_ptr<char, decltype(&::free)> _{ encodedData, &::free }; |
| |
| int err = preference_get_string(key, &encodedData); |
| if (err == PREFERENCE_ERROR_NO_KEY) |
| { |
| return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; |
| } |
| if (err == PREFERENCE_ERROR_OUT_OF_MEMORY) |
| { |
| return CHIP_ERROR_NO_MEMORY; |
| } |
| if (err != PREFERENCE_ERROR_NONE) |
| { |
| ChipLogError(DeviceLayer, "Failed to get preference [%s]: %s", StringOrNullMarker(key), get_error_message(err)); |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| size_t encodedDataSize = strlen(encodedData); |
| |
| Platform::ScopedMemoryBuffer<uint8_t> decodedData; |
| size_t expectedMaxDecodedSize = BASE64_MAX_DECODED_LEN(encodedDataSize); |
| VerifyOrReturnError(decodedData.Alloc(expectedMaxDecodedSize), CHIP_ERROR_NO_MEMORY); |
| |
| size_t decodedDataSize = Base64Decode(encodedData, static_cast<uint16_t>(encodedDataSize), decodedData.Get()); |
| VerifyOrReturnError(dataSize >= decodedDataSize - offset, CHIP_ERROR_BUFFER_TOO_SMALL); |
| |
| size_t copySize = std::min(dataSize, decodedDataSize - offset); |
| if (getDataSize != nullptr) |
| { |
| *getDataSize = copySize; |
| } |
| ::memcpy(data, decodedData.Get() + offset, copySize); |
| |
| ChipLogDetail(DeviceLayer, "Get preference data: key=%s len=%u", key, static_cast<unsigned int>(copySize)); |
| ChipLogByteSpan(DeviceLayer, ByteSpan(reinterpret_cast<uint8_t *>(data), copySize)); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR SaveData(const char * key, const void * data, size_t dataSize) |
| { |
| // Expected size for null-terminated base64 string |
| size_t expectedEncodedSize = BASE64_ENCODED_LEN(dataSize) + 1; |
| |
| Platform::ScopedMemoryBuffer<char> encodedData; |
| VerifyOrReturnError(encodedData.Alloc(expectedEncodedSize), CHIP_ERROR_NO_MEMORY); |
| |
| size_t encodedDataSize = Base64Encode(static_cast<const uint8_t *>(data), static_cast<uint16_t>(dataSize), encodedData.Get()); |
| encodedData[encodedDataSize] = '\0'; |
| |
| int err = preference_set_string(key, encodedData.Get()); |
| if (err == PREFERENCE_ERROR_OUT_OF_MEMORY) |
| { |
| return CHIP_ERROR_NO_MEMORY; |
| } |
| if (err != PREFERENCE_ERROR_NONE) |
| { |
| ChipLogError(DeviceLayer, "Failed to set preference [%s]: %s", StringOrNullMarker(key), get_error_message(err)); |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| ChipLogDetail(DeviceLayer, "Save preference data: key=%s len=%u", key, static_cast<unsigned int>(dataSize)); |
| ChipLogByteSpan(DeviceLayer, ByteSpan(reinterpret_cast<const uint8_t *>(data), dataSize)); |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR RemoveData(const char * key) |
| { |
| int err = preference_remove(key); |
| if (err == PREFERENCE_ERROR_NO_KEY) |
| { |
| return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; |
| } |
| if (err != PREFERENCE_ERROR_NONE) |
| { |
| ChipLogError(DeviceLayer, "Failed to remove preference [%s]: %s", StringOrNullMarker(key), get_error_message(err)); |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| ChipLogProgress(DeviceLayer, "Remove preference data: key=%s", key); |
| return CHIP_NO_ERROR; |
| } |
| |
| } // namespace AppPreference |
| } // namespace Internal |
| } // namespace PersistedStorage |
| } // namespace DeviceLayer |
| } // namespace chip |