(*stack)[(*nstack) - 1].types = types;
(*stack)[(*nstack) - 1].nstruct = nstruct;
(*stack)[(*nstack) - 1].narray = narray;
- VIR_DEBUG("Pushed '%s'", types);
+ VIR_DEBUG("Pushed types='%s' nstruct=%zu narray=%zu", types, nstruct, narray);
return 0;
}
*types = (*stack)[(*nstack) - 1].types;
*nstruct = (*stack)[(*nstack) - 1].nstruct;
*narray = (*stack)[(*nstack) - 1].narray;
- VIR_DEBUG("Popped '%s'", *types);
+ VIR_DEBUG("Popped types='%s' nstruct=%zu narray=%zu", *types, *nstruct, *narray);
VIR_SHRINK_N(*stack, *nstack, 1);
return 0;
# define SET_NEXT_VAL(dbustype, vargtype, sigtype, fmt) \
do { \
- dbustype x = (dbustype)va_arg(args, vargtype); \
+ dbustype x; \
+ if (arrayref) { \
+ vargtype *valarray = arrayptr; \
+ x = (dbustype)*valarray; \
+ valarray++; \
+ arrayptr = valarray; \
+ } else { \
+ x = (dbustype)va_arg(args, vargtype); \
+ } \
if (!dbus_message_iter_append_basic(iter, sigtype, &x)) { \
virReportError(VIR_ERR_INTERNAL_ERROR, \
- _("Cannot append basic type %s"), #vargtype); \
+ _("Cannot append basic type %s"), #vargtype);\
goto cleanup; \
} \
- VIR_DEBUG("Appended basic type '" #dbustype "' varg '" #vargtype \
+ VIR_DEBUG("Appended basic type '" #dbustype "' varg '" #vargtype\
"' sig '%c' val '" fmt "'", sigtype, (vargtype)x); \
} while (0)
+
static int
virDBusMessageIterEncode(DBusMessageIter *rootiter,
const char *types,
int ret = -1;
size_t narray;
size_t nstruct;
+ bool arrayref = false;
+ void *arrayptr = NULL;
virDBusTypeStack *stack = NULL;
size_t nstack = 0;
size_t siglen;
(narray == (size_t)-1 &&
nstruct == 0)) {
DBusMessageIter *thisiter = iter;
+ arrayref = false;
+ arrayptr = NULL;
VIR_DEBUG("Popping iter=%p", iter);
if (nstack == 0)
break;
break;
case DBUS_TYPE_ARRAY:
+ arrayptr = NULL;
+ if (t[1] == '&') {
+ VIR_DEBUG("Got array ref");
+ t++;
+ types++;
+ nstruct--;
+ arrayref = true;
+ } else {
+ VIR_DEBUG("Got array non-ref");
+ arrayref = false;
+ }
+
if (virDBusSignatureLength(t + 1, &siglen) < 0)
goto cleanup;
if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
goto cleanup;
+ if (arrayref && (strlen(contsig) > 1 ||
+ !virDBusIsBasicType(*contsig))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Got array ref but '%s' is not a single basic type"),
+ contsig);
+ goto cleanup;
+ }
+
if (narray == (size_t)-1) {
types += siglen;
nstruct -= siglen;
newiter = NULL;
types = t + 1;
nstruct = siglen;
- narray = va_arg(args, int);
+ narray = (size_t)va_arg(args, int);
+ if (arrayref)
+ arrayptr = va_arg(args, void *);
break;
case DBUS_TYPE_VARIANT:
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unknown type in signature '%s'"),
- types);
+ _("Unknown type '%c' in signature '%s'"),
+ *t, types);
+ goto cleanup;
}
}
# define GET_NEXT_VAL(dbustype, vargtype, fmt) \
do { \
- dbustype *x = (dbustype *)va_arg(args, vargtype *); \
+ dbustype *x; \
+ if (arrayref) { \
+ vargtype **xptrptr = arrayptr; \
+ if (VIR_EXPAND_N(*xptrptr, *narrayptr, 1) < 0) \
+ goto cleanup; \
+ x = (dbustype *)(*xptrptr + (*narrayptr - 1)); \
+ VIR_DEBUG("Expanded to %zu", *narrayptr); \
+ } else { \
+ x = (dbustype *)va_arg(args, vargtype *); \
+ } \
dbus_message_iter_get_basic(iter, x); \
VIR_DEBUG("Read basic type '" #dbustype "' varg '" #vargtype \
"' val '" fmt "'", (vargtype)*x); \
int ret = -1;
size_t narray;
size_t nstruct;
+ bool arrayref = false;
+ void *arrayptr = NULL;
+ size_t *narrayptr = 0;
virDBusTypeStack *stack = NULL;
size_t nstack = 0;
size_t siglen;
(narray == (size_t)-1 &&
nstruct == 0)) {
DBusMessageIter *thisiter = iter;
+ arrayref = false;
+ arrayptr = NULL;
VIR_DEBUG("Popping iter=%p", iter);
if (nstack == 0)
break;
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_SIGNATURE:
do {
- char **x = (char **)va_arg(args, char **);
+ char **x;
+ if (arrayref) {
+ char ***xptrptr = arrayptr;
+ if (VIR_EXPAND_N(*xptrptr, *narrayptr, 1) < 0)
+ goto cleanup;
+ x = (char **)(*xptrptr + (*narrayptr - 1));
+ VIR_DEBUG("Expanded to %zu", *narrayptr);
+ } else {
+ x = (char **)va_arg(args, char **);
+ }
char *s;
dbus_message_iter_get_basic(iter, &s);
if (VIR_STRDUP(*x, s) < 0)
break;
case DBUS_TYPE_ARRAY:
+ arrayptr = NULL;
+ if (t[1] == '&') {
+ VIR_DEBUG("Got array ref");
+ t++;
+ types++;
+ nstruct--;
+ arrayref = true;
+ } else {
+ VIR_DEBUG("Got array non-ref");
+ arrayref = false;
+ }
+
advanceiter = false;
if (virDBusSignatureLength(t + 1, &siglen) < 0)
goto cleanup;
if (VIR_STRNDUP(contsig, t + 1, siglen) < 0)
goto cleanup;
+ if (arrayref && (strlen(contsig) > 1 ||
+ !virDBusIsBasicType(*contsig))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Got array ref but '%s' is not a single basic type"),
+ contsig);
+ goto cleanup;
+ }
+
if (narray == (size_t)-1) {
types += siglen;
nstruct -= siglen;
newiter = NULL;
types = t + 1;
nstruct = siglen;
- narray = va_arg(args, int);
+ if (arrayref) {
+ narrayptr = va_arg(args, size_t *);
+ arrayptr = va_arg(args, void *);
+ *narrayptr = 0;
+ *(char **)arrayptr = NULL;
+ } else {
+ narray = va_arg(args, int);
+ }
break;
case DBUS_TYPE_VARIANT:
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unknown type in signature '%s'"),
- types);
+ _("Unknown type '%c' in signature '%s'"),
+ *t, types);
+ goto cleanup;
+ }
+
+ if (arrayref) {
+ if (*t == '&' ||
+ dbus_message_iter_has_next(iter))
+ narray = 1;
+ else
+ narray = 0;
}
VIR_DEBUG("After stack=%zu array=%zu struct=%zu type='%s'",
return ret;
}
+static int testMessageArrayRef(const void *args ATTRIBUTE_UNUSED)
+{
+ DBusMessage *msg = NULL;
+ int ret = -1;
+ const char *in_str1 = "Hello";
+ int in_int32[] = {
+ 100000000, 2000000000, -2000000000
+ };
+ const char *in_strv1[] = {
+ "Fishfood",
+ };
+ const char *in_strv2[] = {
+ "Hello", "World",
+ };
+ int *out_int32 = NULL;
+ size_t out_nint32 = 0;
+ char **out_strv1 = NULL;
+ char **out_strv2 = NULL;
+ size_t out_nstrv1 = 0;
+ size_t out_nstrv2 = 0;
+ const char *in_str2 = "World";
+ char *out_str1 = NULL, *out_str2 = NULL;
+
+ if (!(msg = dbus_message_new_method_call("org.libvirt.test",
+ "/org/libvirt/test",
+ "org.libvirt.test.astrochicken",
+ "cluck"))) {
+ VIR_DEBUG("Failed to allocate method call");
+ goto cleanup;
+ }
+
+ if (virDBusMessageEncode(msg,
+ "sa&sa&ia&ss",
+ in_str1,
+ 1, in_strv1,
+ 3, in_int32,
+ 2, in_strv2,
+ in_str2) < 0) {
+ VIR_DEBUG("Failed to encode arguments");
+ goto cleanup;
+ }
+
+ if (virDBusMessageDecode(msg,
+ "sa&sa&ia&ss",
+ &out_str1,
+ &out_nstrv1, &out_strv1,
+ &out_nint32, &out_int32,
+ &out_nstrv2, &out_strv2,
+ &out_str2) < 0) {
+ VIR_DEBUG("Failed to decode arguments");
+ goto cleanup;
+ }
+
+
+ VERIFY_STR("str1", in_str1, out_str1, "%s");
+ if (out_nstrv1 != 1) {
+ fprintf(stderr, "Expected 1 string, but got %zu\n",
+ out_nstrv1);
+ goto cleanup;
+ }
+ VERIFY_STR("strv1[0]", in_strv1[0], out_strv1[0], "%s");
+
+ if (out_nint32 != 3) {
+ fprintf(stderr, "Expected 3 integers, but got %zu\n",
+ out_nint32);
+ goto cleanup;
+ }
+ VERIFY("int32a", in_int32[0], out_int32[0], "%d");
+ VERIFY("int32b", in_int32[1], out_int32[1], "%d");
+ VERIFY("int32c", in_int32[2], out_int32[2], "%d");
+
+ if (out_nstrv2 != 2) {
+ fprintf(stderr, "Expected 2 strings, but got %zu\n",
+ out_nstrv2);
+ goto cleanup;
+ }
+ VERIFY_STR("strv2[0]", in_strv2[0], out_strv2[0], "%s");
+ VERIFY_STR("strv2[1]", in_strv2[1], out_strv2[1], "%s");
+
+ VERIFY_STR("str2", in_str2, out_str2, "%s");
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(out_int32);
+ VIR_FREE(out_str1);
+ VIR_FREE(out_str2);
+ dbus_message_unref(msg);
+ return ret;
+}
+
static int testMessageStruct(const void *args ATTRIBUTE_UNUSED)
{
DBusMessage *msg = NULL;
ret = -1;
if (virtTestRun("Test message array ", testMessageArray, NULL) < 0)
ret = -1;
+ if (virtTestRun("Test message array ref ", testMessageArrayRef, NULL) < 0)
+ ret = -1;
if (virtTestRun("Test message struct ", testMessageStruct, NULL) < 0)
ret = -1;
if (virtTestRun("Test message dict ", testMessageDict, NULL) < 0)