1 /* 2 * Core Definitions for QAPI Visitor Classes 3 * 4 * Copyright (C) 2012-2016 Red Hat, Inc. 5 * Copyright IBM, Corp. 2011 6 * 7 * Authors: 8 * Anthony Liguori <aliguori@us.ibm.com> 9 * 10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 11 * See the COPYING.LIB file in the top-level directory. 12 * 13 */ 14 15 #include "qemu/osdep.h" 16 #include "qapi/error.h" 17 #include "qemu-common.h" 18 #include "qapi/qmp/qerror.h" 19 #include "qapi/visitor.h" 20 #include "qapi/visitor-impl.h" 21 #include "trace.h" 22 23 void visit_complete(Visitor *v, void *opaque) 24 { 25 assert(v->type != VISITOR_OUTPUT || v->complete); 26 trace_visit_complete(v, opaque); 27 if (v->complete) { 28 v->complete(v, opaque); 29 } 30 } 31 32 void visit_free(Visitor *v) 33 { 34 trace_visit_free(v); 35 if (v) { 36 v->free(v); 37 } 38 } 39 40 void visit_start_struct(Visitor *v, const char *name, void **obj, 41 size_t size, Error **errp) 42 { 43 Error *err = NULL; 44 45 trace_visit_start_struct(v, name, obj, size); 46 if (obj) { 47 assert(size); 48 assert(!(v->type & VISITOR_OUTPUT) || *obj); 49 } 50 v->start_struct(v, name, obj, size, &err); 51 if (obj && (v->type & VISITOR_INPUT)) { 52 assert(!err != !*obj); 53 } 54 error_propagate(errp, err); 55 } 56 57 void visit_check_struct(Visitor *v, Error **errp) 58 { 59 trace_visit_check_struct(v); 60 if (v->check_struct) { 61 v->check_struct(v, errp); 62 } 63 } 64 65 void visit_end_struct(Visitor *v, void **obj) 66 { 67 trace_visit_end_struct(v, obj); 68 v->end_struct(v, obj); 69 } 70 71 void visit_start_list(Visitor *v, const char *name, GenericList **list, 72 size_t size, Error **errp) 73 { 74 Error *err = NULL; 75 76 assert(!list || size >= sizeof(GenericList)); 77 trace_visit_start_list(v, name, list, size); 78 v->start_list(v, name, list, size, &err); 79 if (list && (v->type & VISITOR_INPUT)) { 80 assert(!(err && *list)); 81 } 82 error_propagate(errp, err); 83 } 84 85 GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) 86 { 87 assert(tail && size >= sizeof(GenericList)); 88 trace_visit_next_list(v, tail, size); 89 return v->next_list(v, tail, size); 90 } 91 92 void visit_check_list(Visitor *v, Error **errp) 93 { 94 trace_visit_check_list(v); 95 if (v->check_list) { 96 v->check_list(v, errp); 97 } 98 } 99 100 void visit_end_list(Visitor *v, void **obj) 101 { 102 trace_visit_end_list(v, obj); 103 v->end_list(v, obj); 104 } 105 106 void visit_start_alternate(Visitor *v, const char *name, 107 GenericAlternate **obj, size_t size, 108 Error **errp) 109 { 110 Error *err = NULL; 111 112 assert(obj && size >= sizeof(GenericAlternate)); 113 assert(!(v->type & VISITOR_OUTPUT) || *obj); 114 trace_visit_start_alternate(v, name, obj, size); 115 if (v->start_alternate) { 116 v->start_alternate(v, name, obj, size, &err); 117 } 118 if (v->type & VISITOR_INPUT) { 119 assert(v->start_alternate && !err != !*obj); 120 } 121 error_propagate(errp, err); 122 } 123 124 void visit_end_alternate(Visitor *v, void **obj) 125 { 126 trace_visit_end_alternate(v, obj); 127 if (v->end_alternate) { 128 v->end_alternate(v, obj); 129 } 130 } 131 132 bool visit_optional(Visitor *v, const char *name, bool *present) 133 { 134 trace_visit_optional(v, name, present); 135 if (v->optional) { 136 v->optional(v, name, present); 137 } 138 return *present; 139 } 140 141 bool visit_is_input(Visitor *v) 142 { 143 return v->type == VISITOR_INPUT; 144 } 145 146 void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) 147 { 148 assert(obj); 149 trace_visit_type_int(v, name, obj); 150 v->type_int64(v, name, obj, errp); 151 } 152 153 static void visit_type_uintN(Visitor *v, uint64_t *obj, const char *name, 154 uint64_t max, const char *type, Error **errp) 155 { 156 Error *err = NULL; 157 uint64_t value = *obj; 158 159 v->type_uint64(v, name, &value, &err); 160 if (err) { 161 error_propagate(errp, err); 162 } else if (value > max) { 163 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 164 name ? name : "null", type); 165 } else { 166 *obj = value; 167 } 168 } 169 170 void visit_type_uint8(Visitor *v, const char *name, uint8_t *obj, 171 Error **errp) 172 { 173 uint64_t value; 174 175 trace_visit_type_uint8(v, name, obj); 176 value = *obj; 177 visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp); 178 *obj = value; 179 } 180 181 void visit_type_uint16(Visitor *v, const char *name, uint16_t *obj, 182 Error **errp) 183 { 184 uint64_t value; 185 186 trace_visit_type_uint16(v, name, obj); 187 value = *obj; 188 visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp); 189 *obj = value; 190 } 191 192 void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, 193 Error **errp) 194 { 195 uint64_t value; 196 197 trace_visit_type_uint32(v, name, obj); 198 value = *obj; 199 visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp); 200 *obj = value; 201 } 202 203 void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, 204 Error **errp) 205 { 206 assert(obj); 207 trace_visit_type_uint64(v, name, obj); 208 v->type_uint64(v, name, obj, errp); 209 } 210 211 static void visit_type_intN(Visitor *v, int64_t *obj, const char *name, 212 int64_t min, int64_t max, const char *type, 213 Error **errp) 214 { 215 Error *err = NULL; 216 int64_t value = *obj; 217 218 v->type_int64(v, name, &value, &err); 219 if (err) { 220 error_propagate(errp, err); 221 } else if (value < min || value > max) { 222 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 223 name ? name : "null", type); 224 } else { 225 *obj = value; 226 } 227 } 228 229 void visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp) 230 { 231 int64_t value; 232 233 trace_visit_type_int8(v, name, obj); 234 value = *obj; 235 visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp); 236 *obj = value; 237 } 238 239 void visit_type_int16(Visitor *v, const char *name, int16_t *obj, 240 Error **errp) 241 { 242 int64_t value; 243 244 trace_visit_type_int16(v, name, obj); 245 value = *obj; 246 visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t", errp); 247 *obj = value; 248 } 249 250 void visit_type_int32(Visitor *v, const char *name, int32_t *obj, 251 Error **errp) 252 { 253 int64_t value; 254 255 trace_visit_type_int32(v, name, obj); 256 value = *obj; 257 visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t", errp); 258 *obj = value; 259 } 260 261 void visit_type_int64(Visitor *v, const char *name, int64_t *obj, 262 Error **errp) 263 { 264 assert(obj); 265 trace_visit_type_int64(v, name, obj); 266 v->type_int64(v, name, obj, errp); 267 } 268 269 void visit_type_size(Visitor *v, const char *name, uint64_t *obj, 270 Error **errp) 271 { 272 assert(obj); 273 trace_visit_type_size(v, name, obj); 274 if (v->type_size) { 275 v->type_size(v, name, obj, errp); 276 } else { 277 v->type_uint64(v, name, obj, errp); 278 } 279 } 280 281 void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) 282 { 283 assert(obj); 284 trace_visit_type_bool(v, name, obj); 285 v->type_bool(v, name, obj, errp); 286 } 287 288 void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) 289 { 290 Error *err = NULL; 291 292 assert(obj); 293 /* TODO: Fix callers to not pass NULL when they mean "", so that we 294 * can enable: 295 assert(!(v->type & VISITOR_OUTPUT) || *obj); 296 */ 297 trace_visit_type_str(v, name, obj); 298 v->type_str(v, name, obj, &err); 299 if (v->type & VISITOR_INPUT) { 300 assert(!err != !*obj); 301 } 302 error_propagate(errp, err); 303 } 304 305 void visit_type_number(Visitor *v, const char *name, double *obj, 306 Error **errp) 307 { 308 assert(obj); 309 trace_visit_type_number(v, name, obj); 310 v->type_number(v, name, obj, errp); 311 } 312 313 void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) 314 { 315 Error *err = NULL; 316 317 assert(obj); 318 assert(v->type != VISITOR_OUTPUT || *obj); 319 trace_visit_type_any(v, name, obj); 320 v->type_any(v, name, obj, &err); 321 if (v->type == VISITOR_INPUT) { 322 assert(!err != !*obj); 323 } 324 error_propagate(errp, err); 325 } 326 327 void visit_type_null(Visitor *v, const char *name, QNull **obj, 328 Error **errp) 329 { 330 trace_visit_type_null(v, name, obj); 331 v->type_null(v, name, obj, errp); 332 } 333 334 static void output_type_enum(Visitor *v, const char *name, int *obj, 335 const QEnumLookup *lookup, Error **errp) 336 { 337 int value = *obj; 338 char *enum_str; 339 340 /* 341 * TODO why is this an error, not an assertion? If assertion: 342 * delete, and rely on qapi_enum_lookup() 343 */ 344 if (value < 0 || value >= lookup->size) { 345 error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null"); 346 return; 347 } 348 349 enum_str = (char *)qapi_enum_lookup(lookup, value); 350 visit_type_str(v, name, &enum_str, errp); 351 } 352 353 static void input_type_enum(Visitor *v, const char *name, int *obj, 354 const QEnumLookup *lookup, Error **errp) 355 { 356 Error *local_err = NULL; 357 int64_t value; 358 char *enum_str; 359 360 visit_type_str(v, name, &enum_str, &local_err); 361 if (local_err) { 362 error_propagate(errp, local_err); 363 return; 364 } 365 366 value = qapi_enum_parse(lookup, enum_str, -1, NULL); 367 if (value < 0) { 368 error_setg(errp, QERR_INVALID_PARAMETER, enum_str); 369 g_free(enum_str); 370 return; 371 } 372 373 g_free(enum_str); 374 *obj = value; 375 } 376 377 void visit_type_enum(Visitor *v, const char *name, int *obj, 378 const QEnumLookup *lookup, Error **errp) 379 { 380 assert(obj && lookup); 381 trace_visit_type_enum(v, name, obj); 382 switch (v->type) { 383 case VISITOR_INPUT: 384 input_type_enum(v, name, obj, lookup, errp); 385 break; 386 case VISITOR_OUTPUT: 387 output_type_enum(v, name, obj, lookup, errp); 388 break; 389 case VISITOR_CLONE: 390 /* nothing further to do, scalar value was already copied by 391 * g_memdup() during visit_start_*() */ 392 break; 393 case VISITOR_DEALLOC: 394 /* nothing to deallocate for a scalar */ 395 break; 396 } 397 } 398