blob: ffb36ee6777186b90739d3fe714dac9b0508a443 [file] [log] [blame]
/*
*
* 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