blob: bc5859c6b86dec2070a423d898dced67165e25ef [file] [log] [blame]
/*
* blob - generic type for storing an array and a length.
*
* This file initially created by Google, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <connman/blob.h>
#include <glib.h>
#include <errno.h>
#include <string.h>
/*
* Allocate memory for a new blob structure and its internal buffer.
*
* If data is non-NULL, the first len bytes of it will be used to initialize
* the new blob's internal buffer. The internal buffer is automatically freed
* by blob_free().
*
* If data is NULL, it can be assigned by the caller to point to any buffer.
* That buffer will not be freed by blob_free().
*
* @blob: pointer to pointer to the new blob
* @len: length of new blob's data array
* @data: if not NULL, used to initialize new blob's data array.
* @return: -ENOMEM, or 0 on success.
*/
int blob_new(struct blob **blob, size_t len, const char *data)
{
/* Allocate struct followed by an internal buffer. */
*blob = g_try_malloc(sizeof(**blob) + len);
if (*blob == NULL)
return -ENOMEM;
(*blob)->len = len;
if (len == 0) {
/*
* When len ==0, there is no internal buffer.
* Instead point to caller's data, usually NULL.
* If not NULL, caller must manually set len, and free data.
*/
(*blob)->data = (char *)data;
} else {
/* Point to the internal buffer. */
(*blob)->data = (*blob)->buffer;
/* If data was provided, use it to initialize buffer */
if (data != NULL)
memcpy((*blob)->data, data, len);
}
return 0;
}
/*
* Allocate memory for a new blob structure, and initialize its buffer from the
* given '\0'-terminated string of ASCII hexadecimal digits.
*
* @blob: pointer to pointer to the new blob
* @hex: '\0'-terminated string whose length must be > 0,
* and must have an even number of digits.
* @return: -ENOMEM, -EINVAL or 0 on success.
*/
int blob_new_from_hex(struct blob **blob, const char *hex)
{
size_t hex_len;
size_t blob_len;
int ret;
int i;
for (i = 0; hex[i] != '\0'; i++)
if (!g_ascii_isxdigit(hex[i]))
return -EINVAL;
hex_len = i;
if (hex_len == 0 || (hex_len % 2) != 0)
return -EINVAL;
blob_len = hex_len / 2;
ret = blob_new(blob, blob_len, NULL);
if (ret < 0)
return ret;
for (i = 0; i < blob_len; i++)
(*blob)->data[i] = 16 * g_ascii_xdigit_value(hex[2*i])
+ g_ascii_xdigit_value(hex[2*i+1]);
return 0;
}
/*
* Free memory for blob structure and its internal buffer.
* @blob: blob to free
*/
void blob_free(struct blob *blob)
{
g_free(blob);
}