Bundles / src /
data.c
/*
* Copyright (c) 2016 Samsung Electronics Co., Ltd
*
* Licensed under the Flora License, Version 1.1 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://floralicense.org/license/
*
* 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 <Eina.h>
#include <bundle.h>
#include <message_port.h>
#include "$(appName).h"
#include "data.h"
#include <efl_extension.h>
#define MESSAGE_PORT_RCV_NAME PACKAGE"_msg_port_local_rcv"
typedef struct data_callbacks {
message_data_new_cb new_data_cb;
} data_callbacks_t;
static struct data_info {
data_callbacks_t callbacks;
Eina_List *bundles_received;
bundle *bundle_obj;
int msg_port_rcv_id;
} s_info = {
.callbacks = {0,},
.bundles_received = NULL,
.bundle_obj = NULL,
.msg_port_rcv_id = 0,
};
static void _header_iterator_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data);
static void _bundle_clear_iterator_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data);
static void _keys_iterator_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data);
static void _message_received_cb(int local_port_id, const char *remote_app_id, const char *remote_port, bool trusted_remote_port, bundle *message, void *user_data);
static inline bundle *_get_bundle(int index);
static inline void _free_string_array(int count, char** keys);
/**
* @brief Initialize functions for data module.
* @param[in] new_data_cb Callback invoked when a new message is received. It is used to inform the view module about the message.
*/
void data_initialize(message_data_new_cb new_data_cb)
{
s_info.callbacks.new_data_cb = new_data_cb;
int ret = message_port_register_local_port(MESSAGE_PORT_RCV_NAME, _message_received_cb, NULL);
if (ret < 0) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] message_port_register_local_port() failed. Error: %s", __FILE__, __LINE__, get_error_message(ret));
return;
} else {
s_info.msg_port_rcv_id = ret;
}
data_create_bundle();
}
/**
* @brief Finalize function for data module.
*/
void data_finalize(void)
{
data_destroy_bundle();
/*
* all the s_info.items_list items shall be released
*/
if (s_info.bundles_received)
s_info.bundles_received = eina_list_free(s_info.bundles_received);
if (s_info.msg_port_rcv_id > 0)
message_port_unregister_local_port(s_info.msg_port_rcv_id);
}
/**
* @brief Function creates a bundle handle, adds a header and fills it with relevant data.
* If the bundle handle already exists, then it is destroyed and a new one is created.
* The newly created bundle handle is stored internally.
* @return The function returns 'true' if the bundle handle is created successfully,
* otherwise 'false' is returned.
*/
bool data_create_bundle(void)
{
s_info.bundle_obj = bundle_create();
if (!s_info.bundle_obj) {
dlog_print(DLOG_ERROR, LOG_TAG, "bundle_create() failed.");
return false;
}
return true;
}
/**
* @brief Function destroys a bundle handle.
* If the bundle handle does not exist, then it nothing happens.
*/
void data_destroy_bundle(void)
{
int ret;
if (!s_info.bundle_obj)
return;
ret = bundle_free(s_info.bundle_obj);
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "bundle_free() failed. Err = %d.", ret);
return;
}
s_info.bundle_obj = NULL;
}
/**
* @brief Function which adds a numeric value to the bundle object.
* If a bundle handle is not prior created, the function fails.
* @param[in] key The key name for value identification.
* @param[in] value The value assigned to the given key.
* @return The function returns 'true' if the value is added successfully,
* otherwise 'false' is returned.
*/
bool data_add_byte(const char *key, int value)
{
int ret;
data_delete_key(-1, key);
ret = bundle_add_byte(s_info.bundle_obj, key, &value, sizeof(value));
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "_add_byte() failed. Err = %s.", get_error_message(ret));
return false;
}
return true;
}
/**
* @brief Function which adds a string value to the bundle object.
* If a bundle handle is not prior created, the function fails.
* @param[in] key The key name for value identification.
* @param[in] value The value assigned to the given key.
* @return The function returns 'true' if the value is added successfully,
* otherwise 'false' is returned.
*/
bool data_add_string(const char *key, const char *value)
{
int ret;
data_delete_key(-1, key);
ret = bundle_add_str(s_info.bundle_obj, key, value);
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "_add_string() failed. Err = %s.", get_error_message(ret));
return false;
}
return true;
}
/**
* @brief Internal function that creates a key-value pair of the string array type. The array is then filled with key names and the data types.
* @param[in] count Number of keys stored in a bundle
* @return true on success or false on fail.
*/
static bool _add_header_data(int count)
{
int ret;
char** keys = calloc(count, sizeof(char*));
data_delete_key(-1, BUNDLE_HEADER_DATA_KEY);
bundle_foreach(s_info.bundle_obj, _header_iterator_cb, (void*)keys);
ret = bundle_add_str_array(s_info.bundle_obj, BUNDLE_HEADER_DATA_KEY, (const char**)keys, count);
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "_add_string() failed. Err = %s.", get_error_message(ret));
_free_string_array(count, keys);
return false;
}
_free_string_array(count, keys);
return true;
}
/**
* @brief Creates a header pair containing the count of the remaining pairs
* @return true on success or false on fail.
*/
bool data_add_header(void)
{
int count = 0;
int ret = 0;
bundle_del(s_info.bundle_obj, BUNDLE_HEADER_KEY);
bundle_del(s_info.bundle_obj, BUNDLE_HEADER_DATA_KEY);
count = bundle_get_count(s_info.bundle_obj);
if (!_add_header_data(count)) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] Function _add_header_data() failed", __FILE__, __LINE__);
return false;
}
ret = bundle_add_byte(s_info.bundle_obj, BUNDLE_HEADER_KEY, (void *)&count, sizeof(int));
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] bundle_add_byte() error: %s", __FILE__, __LINE__, get_error_message(ret));
return false;
}
return true;
}
/**
* @brief Check if the given key exist in the bundle with the given index.
* @param[in] index Bundle's index (>=0 bundles received in a message, <0 bundle prepared using the source view).
* @param[in] key The key to search for.
* @return true - key exists, false the key doesn't exist.
*/
bool data_key_exists(int index, const char *key)
{
bundle* bun = _get_bundle(index);
bundle_get_type(bun, key);
return !(get_last_result() == BUNDLE_ERROR_KEY_NOT_AVAILABLE);
}
/**
* @brief Check whether the given key contains a byte or a string value.
* @param[in] index The bundle index.
* @param[in] key The key name.
* @return false - value type is byte, false - otherwise.
*/
int data_is_byte(int index, const char *key)
{
bundle* bun = _get_bundle(index);
set_last_result(BUNDLE_ERROR_NONE);
int type = bundle_get_type(bun, key);
int ret = get_last_result();
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] bundle_get_type error: %s", __FILE__, __LINE__, get_error_message(ret));
return 0;
}
return (type == BUNDLE_TYPE_BYTE);
}
/**
* @brief Function returns a text with the key's type.
* @param[in] index The bundle index.
* @param[in] key The key name.
* @return String containing the value's type name (e.g. "byte", "string").
*/
char *data_get_type_text(int index, const char *key)
{
int type;
int ret;
bundle* bun = _get_bundle(index);
set_last_result(BUNDLE_ERROR_NONE);
type = bundle_get_type(bun, key);
ret = get_last_result();
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] bundle_get_type error: %s", __FILE__, __LINE__, get_error_message(ret));
return NULL;
}
if (type == BUNDLE_TYPE_BYTE)
return "byte";
else
return "string";
}
/**
* @brief Function returns the number of key-value pairs in the given bundle.
* @param[in] index The bundle's index.
* @return Number of key-value pairs stored in a bundle.
*/
int data_get_count(int index)
{
bundle* bun = _get_bundle(index);
return bundle_get_count(bun);
}
/**
* @brief Function returns a byte value associated with given key stored in a bundle under given index.
* @param[in] index The bundle index.
* @param[in] key The key name.
* @return The value stored in a bundle under provided index and associated with given key.
*/
int data_get_byte(int index, const char *key)
{
int *val = NULL;
size_t size = 0;
bundle *bun = _get_bundle(index);
int ret = bundle_get_byte(bun, key, (void**)&val, &size);
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] bundle_get_byte() error: %s", __FILE__, __LINE__, get_error_message(ret));
return 0;
}
return *val;
}
/**
* @brief Function returns a string value associated with given key stored in a bundle under given index.
* @param[in] index The bundle index.
* @param[in] key The key name.
* @return The value stored in a bundle under provided index and associated with given key.
*/
char *data_get_string(int index, const char *key)
{
char *str = NULL;
bundle *bun = _get_bundle(index);
int ret = bundle_get_str(bun, key, &str);
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] data_get_string() error: %s", __FILE__, __LINE__, get_error_message(ret));
return NULL;
}
return str;
}
/**
* @brief Function returns a byte value associated with given key stored in a bundle under given index.
* @param[in] index The bundle index.
* @param[in] key The key name.
* @param[out] len Length of the string array
* @return The value stored in a bundle under provided index and associated with given key.
*/
const char **data_get_string_array(int index, const char *key, int *len)
{
int ret;
const char **values = NULL;
bundle *bun = _get_bundle(index);
values = bundle_get_str_array(bun, key, len);
ret = get_last_result();
if (ret != BUNDLE_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] bundle_get_str_array() error: %s", __FILE__, __LINE__, get_error_message(ret));
return NULL;
}
return values;
}
/**
* @brief Functions deletes the given key-value pair from the bundle.
* @param[in] index bundle's index.
* @param[in] key Key to remove.
*/
void data_delete_key(int index, const char *key)
{
int ret;
bundle *bun = _get_bundle(index);
ret = bundle_del(bun, key);
if (ret != BUNDLE_ERROR_NONE && ret != BUNDLE_ERROR_KEY_NOT_AVAILABLE) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] bundle_del() error: %s", __FILE__, __LINE__, get_error_message(ret));
return;
}
}
/**
* @brief Function removes all key-value pairs from a bundle.
*/
void data_clear_bundle(void)
{
bundle_foreach(s_info.bundle_obj, _bundle_clear_iterator_cb, NULL);
}
Eina_List *data_get_keys(int index)
{
bundle *bun = _get_bundle(index);
Eina_List *keys = NULL;
bundle_foreach(bun, _keys_iterator_cb, (void*)&keys);
return keys;
}
/**
* @brief Function sends a message containing the bundle data.
* @return true on success or false on fail.
*/
bool data_send_message(void)
{
int ret = message_port_send_message(PACKAGE, MESSAGE_PORT_RCV_NAME, s_info.bundle_obj);
if (ret != MESSAGE_PORT_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "message_port_send_message() failed. Err = %s.", get_error_message(ret));
return false;
}
return true;
}
/**
* @brief Internal function used to retrieve a bundle with the given index.
* @param[in] index Index of a bundle object to be returned.
* @return A bundle object. If a non-negative index value is provided, then a relevant bundle object, received via Message Port, is returned. For negative index value, the bundle object prepared for sending is returned.
*/
static inline bundle *_get_bundle(int index)
{
bundle *bun = NULL;
if (index < 0)
bun = s_info.bundle_obj;
else
bun = eina_list_nth(s_info.bundles_received, index);
return bun;
}
/**
* @brief Internal callback function invoked by a bundle iterator. It is used to delete all the key-value pairs from the given bundle.
* @param[in] key Current key.
* @param[in] type Value type.
* @param[in] kv Bundle value container.
* @param[in] user_data User data.
*/
static void _bundle_clear_iterator_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data)
{
bundle_del(s_info.bundle_obj, key);
}
/**
* @brief Internal callback function invoked by a bundle iterator. It is used to fill the header data array.
* @param[in] key Current key.
* @param[in] type Value type.
* @param[in] kv Bundle value container.
* @param[out] user_data The array to store the keys.
*/
static void _header_iterator_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data)
{
char *type_name = NULL;
char **keys = (char**)user_data;
char buf[NAME_MAX];
static int iter = 0;
int count = bundle_get_count(s_info.bundle_obj);
if (type == BUNDLE_TYPE_BYTE)
type_name = "byte";
else
type_name = "string";
snprintf(buf, NAME_MAX, "%s\2%s", key, type_name);
keys[iter] = strdup(buf);
if (iter < count -1)
iter++;
else
iter = 0;
}
/**
* @brief Internal callback function invoked by a bundle iterator used to create an eina_list for all of the available keys from the given bundle storage.
* @param[in] key Current key.
* @param[in] type Value type.
* @param[in] kv Bundle value container.
* @param[out] user_data List to store the keys.
*/
static void _keys_iterator_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data)
{
Eina_List **keys = (Eina_List **)user_data;
*keys = eina_list_append(*keys, strdup(key));
}
/**
* @brief Internal callback function invoked when a message is received. The bundle received is appended to an eina_list. This callback function is invoked to inform the view module that the message had just been received.
* @param[in] local_port_id Local port id
* @param[in] remote_app_id Remote app id (In this case "org.example.bundles")
* @param[in] remote_port Remote port name
* @param[in] trusted_remote_port true - the port is trusted.
* @param[in] message The message received.
* @param[in] user_data User data.
*/
static void _message_received_cb(int local_port_id, const char *remote_app_id, const char *remote_port, bool trusted_remote_port, bundle *message, void *user_data)
{
bundle *message_cpy = bundle_dup(message);
if (!message_cpy) {
dlog_print(DLOG_ERROR, LOG_TAG, "[%s:%d] message_cpy == NULL", __FILE__, __LINE__);
return;
}
s_info.bundles_received = eina_list_append(s_info.bundles_received, (void*)message_cpy);
s_info.callbacks.new_data_cb(eina_list_count(s_info.bundles_received) - 1);
}
/**
* @brief Internal function that frees a string array and all of its content.
* @param[in] count The array length.
* @param[in] keys The array to free.
*/
static inline void _free_string_array(int count, char** keys)
{
int i;
for (i = 0; i < count; ++i)
free(keys[i]);
free(keys);
}