darling-libxpc/xpc_type.c
2017-02-12 10:35:29 +03:00

551 lines
10 KiB
C

/*
* Copyright 2014-2015 iXsystems, Inc.
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <sys/types.h>
#include <time.h>
#include "xpc/xpc.h"
#include "xpc_internal.h"
#include <mach/clock.h>
#include <mach/mach.h>
struct _xpc_type_s {
};
typedef const struct _xpc_type_s xt;
xt _xpc_type_array;
xt _xpc_type_bool;
xt _xpc_type_connection;
xt _xpc_type_data;
xt _xpc_type_date;
xt _xpc_type_dictionary;
xt _xpc_type_endpoint;
xt _xpc_type_null;
xt _xpc_type_error;
xt _xpc_type_fd;
xt _xpc_type_int64;
xt _xpc_type_uint64;
xt _xpc_type_shmem;
xt _xpc_type_string;
xt _xpc_type_uuid;
xt _xpc_type_double;
struct _xpc_bool_s {
};
typedef const struct _xpc_bool_s xb;
xb _xpc_bool_true;
xb _xpc_bool_false;
static size_t xpc_data_hash(const uint8_t *data, size_t length);
static xpc_type_t xpc_typemap[] = {
NULL,
XPC_TYPE_DICTIONARY,
XPC_TYPE_ARRAY,
XPC_TYPE_BOOL,
XPC_TYPE_CONNECTION,
XPC_TYPE_ENDPOINT,
XPC_TYPE_NULL,
NULL,
XPC_TYPE_INT64,
XPC_TYPE_UINT64,
XPC_TYPE_DATE,
XPC_TYPE_DATA,
XPC_TYPE_STRING,
XPC_TYPE_UUID,
XPC_TYPE_FD,
XPC_TYPE_SHMEM,
XPC_TYPE_ERROR,
XPC_TYPE_DOUBLE
};
static const char *xpc_typestr[] = {
"invalid",
"dictionary",
"array",
"bool",
"connection",
"endpoint",
"null",
"invalid",
"int64",
"uint64",
"date",
"data",
"string",
"uuid",
"fd",
"shmem",
"error",
"double"
};
__private_extern__ struct xpc_object *
_xpc_prim_create(int type, xpc_u value, size_t size)
{
return (_xpc_prim_create_flags(type, value, size, 0));
}
__private_extern__ struct xpc_object *
_xpc_prim_create_flags(int type, xpc_u value, size_t size, uint16_t flags)
{
struct xpc_object *xo;
if ((xo = malloc(sizeof(*xo))) == NULL)
return (NULL);
xo->xo_size = size;
xo->xo_xpc_type = type;
xo->xo_flags = flags;
xo->xo_u = value;
xo->xo_refcnt = 1;
#if MACH
xo->xo_audit_token = NULL;
#endif
if (type == _XPC_TYPE_DICTIONARY)
TAILQ_INIT(&xo->xo_dict);
if (type == _XPC_TYPE_ARRAY)
TAILQ_INIT(&xo->xo_array);
return (xo);
}
xpc_object_t
xpc_null_create(void)
{
xpc_u val;
return _xpc_prim_create(_XPC_TYPE_NULL, val, 0);
}
xpc_object_t
xpc_bool_create(bool value)
{
xpc_u val;
val.b = value;
return _xpc_prim_create(_XPC_TYPE_BOOL, val, 1);
}
bool
xpc_bool_get_value(xpc_object_t xbool)
{
struct xpc_object *xo;
xo = xbool;
if (xo == NULL)
return (0);
if (xo->xo_xpc_type == _XPC_TYPE_BOOL)
return (xo->xo_bool);
return (false);
}
xpc_object_t
xpc_int64_create(int64_t value)
{
xpc_u val;
val.i = value;
return _xpc_prim_create(_XPC_TYPE_INT64, val, 1);
}
int64_t
xpc_int64_get_value(xpc_object_t xint)
{
struct xpc_object *xo;
xo = xint;
if (xo == NULL)
return (0);
if (xo->xo_xpc_type == _XPC_TYPE_INT64)
return (xo->xo_int);
return (0);
}
xpc_object_t
xpc_uint64_create(uint64_t value)
{
xpc_u val;
val.ui = value;
return _xpc_prim_create(_XPC_TYPE_UINT64, val, 1);
}
uint64_t
xpc_uint64_get_value(xpc_object_t xuint)
{
struct xpc_object *xo;
xo = xuint;
if (xo == NULL)
return (0);
if (xo->xo_xpc_type == _XPC_TYPE_UINT64)
return (xo->xo_uint);
return (0);
}
xpc_object_t
xpc_double_create(double value)
{
xpc_u val;
val.d = value;
return _xpc_prim_create(_XPC_TYPE_DOUBLE, val, 1);
}
double
xpc_double_get_value(xpc_object_t xdouble)
{
struct xpc_object *xo = xdouble;
if (xo->xo_xpc_type == _XPC_TYPE_DOUBLE)
return (xo->xo_d);
return (0);
}
xpc_object_t
xpc_date_create(int64_t interval)
{
xpc_u val;
val.i = interval;
return _xpc_prim_create(_XPC_TYPE_DATE, val, 1);
}
xpc_object_t
xpc_date_create_from_current(void)
{
xpc_u val;
struct timespec tp;
// clock_gettime(CLOCK_REALTIME, &tp);
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
tp.tv_sec = mts.tv_sec;
tp.tv_nsec = mts.tv_nsec;
val.ui = *(uint64_t *)&tp;
return _xpc_prim_create(_XPC_TYPE_DATE, val, 1);
}
int64_t
xpc_date_get_value(xpc_object_t xdate)
{
struct xpc_object *xo = xdate;
if (xo == NULL)
return (0);
if (xo->xo_xpc_type == _XPC_TYPE_DATE)
return (xo->xo_int);
return (0);
}
xpc_object_t
xpc_data_create(const void *bytes, size_t length)
{
xpc_u val;
val.ptr = (uintptr_t)bytes;
return _xpc_prim_create(_XPC_TYPE_DATA, val, length);
}
#ifdef MACH
xpc_object_t
xpc_data_create_with_dispatch_data(dispatch_data_t ddata)
{
}
#endif
size_t
xpc_data_get_length(xpc_object_t xdata)
{
struct xpc_object *xo = xdata;
if (xo == NULL)
return (0);
if (xo->xo_xpc_type == _XPC_TYPE_DATA)
return (xo->xo_size);
return (0);
}
const void *
xpc_data_get_bytes_ptr(xpc_object_t xdata)
{
struct xpc_object *xo = xdata;
if (xo == NULL)
return (NULL);
if (xo->xo_xpc_type == _XPC_TYPE_DATA)
return ((const void *)xo->xo_ptr);
return (0);
}
size_t
xpc_data_get_bytes(xpc_object_t xdata, void *buffer, size_t off, size_t length)
{
/* XXX */
return (0);
}
xpc_object_t
xpc_string_create(const char *string)
{
xpc_u val;
val.str = __DECONST(char *, string);
return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(string));
}
xpc_object_t
xpc_string_create_with_format(const char *fmt, ...)
{
va_list ap;
xpc_u val;
va_start(ap, fmt);
vasprintf(&val.str, fmt, ap);
va_end(ap);
return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(val.str));
}
xpc_object_t
xpc_string_create_with_format_and_arguments(const char *fmt, va_list ap)
{
xpc_u val;
vasprintf(&val.str, fmt, ap);
return _xpc_prim_create(_XPC_TYPE_STRING, val, strlen(val.str));
}
size_t
xpc_string_get_length(xpc_object_t xstring)
{
struct xpc_object *xo = xstring;
if (xo == NULL)
return (0);
if (xo->xo_xpc_type == _XPC_TYPE_STRING)
return (xo->xo_size);
return (0);
}
const char *
xpc_string_get_string_ptr(xpc_object_t xstring)
{
struct xpc_object *xo = xstring;
if (xo == NULL)
return (NULL);
if (xo->xo_xpc_type == _XPC_TYPE_STRING)
return (xo->xo_str);
return (NULL);
}
xpc_object_t
xpc_uuid_create(const uuid_t uuid)
{
xpc_u val;
memcpy(val.uuid, uuid, sizeof(uuid_t));
return _xpc_prim_create(_XPC_TYPE_UUID, val, 1);
}
const uint8_t *
xpc_uuid_get_bytes(xpc_object_t xuuid)
{
struct xpc_object *xo;
xo = xuuid;
if (xo == NULL)
return (NULL);
if (xo->xo_xpc_type == _XPC_TYPE_UUID)
return ((uint8_t*)&xo->xo_uuid);
return (NULL);
}
xpc_type_t
xpc_get_type(xpc_object_t obj)
{
struct xpc_object *xo;
if (obj == (xpc_object_t) XPC_ERROR_CONNECTION_INTERRUPTED ||
obj == (xpc_object_t) XPC_ERROR_CONNECTION_INVALID ||
obj == (xpc_object_t) XPC_ERROR_TERMINATION_IMMINENT)
return XPC_TYPE_ERROR;
xo = obj;
return (xpc_typemap[xo->xo_xpc_type]);
}
bool
xpc_equal(xpc_object_t x1, xpc_object_t x2)
{
struct xpc_object *xo1, *xo2;
xo1 = x1;
xo2 = x2;
/* FIXME */
return (false);
}
xpc_object_t
xpc_copy(xpc_object_t obj)
{
struct xpc_object *xo, *xotmp;
const void *newdata;
xo = obj;
switch (xo->xo_xpc_type) {
case _XPC_TYPE_BOOL:
case _XPC_TYPE_INT64:
case _XPC_TYPE_UINT64:
case _XPC_TYPE_DATE:
case _XPC_TYPE_ENDPOINT:
return _xpc_prim_create(xo->xo_xpc_type, xo->xo_u, 1);
case _XPC_TYPE_STRING:
return xpc_string_create(strdup(
xpc_string_get_string_ptr(xo)));
case _XPC_TYPE_DATA:
newdata = xpc_data_get_bytes_ptr(obj);
return (xpc_data_create(newdata,
xpc_data_get_length(obj)));
case _XPC_TYPE_DICTIONARY:
xotmp = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_apply(obj, ^(const char *k, xpc_object_t v) {
xpc_dictionary_set_value(xotmp, k, xpc_copy(v));
return (bool)true;
});
return (xotmp);
case _XPC_TYPE_ARRAY:
xotmp = xpc_array_create(NULL, 0);
xpc_array_apply(obj, ^(size_t idx, xpc_object_t v) {
xpc_array_set_value(xotmp, idx, xpc_copy(v));
return ((bool)true);
});
return (xotmp);
}
return (0);
}
static size_t
xpc_data_hash(const uint8_t *data, size_t length)
{
size_t hash = 5381;
while (length--)
hash = ((hash << 5) + hash) + data[length];
return (hash);
}
size_t
xpc_hash(xpc_object_t obj)
{
struct xpc_object *xo;
__block size_t hash = 0;
xo = obj;
switch (xo->xo_xpc_type) {
case _XPC_TYPE_BOOL:
case _XPC_TYPE_INT64:
case _XPC_TYPE_UINT64:
case _XPC_TYPE_DATE:
case _XPC_TYPE_ENDPOINT:
return ((size_t)xo->xo_u.ui);
case _XPC_TYPE_STRING:
return (xpc_data_hash(
(const uint8_t *)xpc_string_get_string_ptr(obj),
xpc_string_get_length(obj)));
case _XPC_TYPE_DATA:
return (xpc_data_hash(
xpc_data_get_bytes_ptr(obj),
xpc_data_get_length(obj)));
case _XPC_TYPE_DICTIONARY:
xpc_dictionary_apply(obj, ^(const char *k, xpc_object_t v) {
hash ^= xpc_data_hash((const uint8_t *)k, strlen(k));
hash ^= xpc_hash(v);
return ((bool)true);
});
return (hash);
case _XPC_TYPE_ARRAY:
xpc_array_apply(obj, ^(size_t idx, xpc_object_t v) {
hash ^= xpc_hash(v);
return ((bool)true);
});
return (hash);
}
return (0);
}
__private_extern__ const char *
_xpc_get_type_name(xpc_object_t obj)
{
struct xpc_object *xo;
xo = obj;
return (xpc_typestr[xo->xo_xpc_type]);
}