xml.c 13.6 KB
Newer Older
1 2 3
/*
 * xml.c: XML based interfaces for the libvir library
 *
4
 * Copyright (C) 2005, 2007-2009 Red Hat, Inc.
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

11
#include <config.h>
12

13 14 15 16
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
17
#include <limits.h>
18
#include <math.h>               /* for isnan() */
19 20

#include "virterror_internal.h"
21
#include "xml.h"
22
#include "buf.h"
23
#include "util.h"
24
#include "memory.h"
25

26 27
#define VIR_FROM_THIS VIR_FROM_XML

28
#define virXMLError(conn, code, fmt...)                                      \
29
        virReportErrorHelper(conn, VIR_FROM_XML, code, __FILE__,           \
30
                               __FUNCTION__, __LINE__, fmt)
31

32 33 34 35 36 37 38

/************************************************************************
 *									*
 * Wrappers around libxml2 XPath specific functions			*
 *									*
 ************************************************************************/

39 40 41 42 43 44 45 46 47 48 49
/**
 * virXPathString:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath string
 *
 * Returns a new string which must be deallocated by the caller or NULL
 *         if the evaluation failed.
 */
char *
50 51 52
virXPathString(virConnectPtr conn,
               const char *xpath,
               xmlXPathContextPtr ctxt)
53
{
54
    xmlXPathObjectPtr obj;
55
    xmlNodePtr relnode;
56 57 58
    char *ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
59
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
60
                    "%s", _("Invalid parameter to virXPathString()"));
61
        return (NULL);
62
    }
63
    relnode = ctxt->node;
64
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
65
    ctxt->node = relnode;
66
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
D
Daniel P. Berrange 已提交
67
        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
68
        xmlXPathFreeObject(obj);
69
        return (NULL);
D
Daniel P. Berrange 已提交
70
    }
71 72 73
    ret = strdup((char *) obj->stringval);
    xmlXPathFreeObject(obj);
    if (ret == NULL) {
74
        virReportOOMError(conn);
75
    }
76
    return (ret);
77 78
}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
/**
 * virXPathStringLimit:
 * @xpath: the XPath string to evaluate
 * @maxlen: maximum length permittred string
 * @ctxt: an XPath context
 *
 * Wrapper for virXPathString, which validates the length of the returned
 * string.
 *
 * Returns a new string which must be deallocated by the caller or NULL if
 * the evaluation failed.
 */
char *
virXPathStringLimit(virConnectPtr conn,
                    const char *xpath,
                    size_t maxlen,
                    xmlXPathContextPtr ctxt)
{
    char *tmp = virXPathString(conn, xpath, ctxt);

    if (tmp != NULL && strlen(tmp) >= maxlen) {
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
                    _("\'%s\' value longer than %Zd bytes in virXPathStringLimit()"),
                    xpath, maxlen);
            return NULL;
    }

    return tmp;
}

109 110 111 112 113 114 115 116 117 118 119 120
/**
 * virXPathNumber:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned double value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the evaluation failed.
 */
int
121 122 123 124
virXPathNumber(virConnectPtr conn,
               const char *xpath,
               xmlXPathContextPtr ctxt,
               double *value)
125
{
126
    xmlXPathObjectPtr obj;
127
    xmlNodePtr relnode;
128 129

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
130
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
131
                    "%s", _("Invalid parameter to virXPathNumber()"));
132
        return (-1);
133
    }
134
    relnode = ctxt->node;
135
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
136
    ctxt->node = relnode;
137 138
    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
        (isnan(obj->floatval))) {
139 140
        xmlXPathFreeObject(obj);
        return (-1);
141
    }
142

143 144
    *value = obj->floatval;
    xmlXPathFreeObject(obj);
145
    return (0);
146 147
}

148 149 150 151 152 153
static int
virXPathLongBase(virConnectPtr conn,
                 const char *xpath,
                 xmlXPathContextPtr ctxt,
                 int base,
                 long *value)
154
{
155
    xmlXPathObjectPtr obj;
156
    xmlNodePtr relnode;
157 158 159
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
160
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
161
                    "%s", _("Invalid parameter to virXPathLong()"));
162
        return (-1);
163
    }
164
    relnode = ctxt->node;
165
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
166
    ctxt->node = relnode;
167 168 169
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
170
        long val;
171

172
        val = strtol((const char *) obj->stringval, &conv, base);
173
        if (conv == (const char *) obj->stringval) {
174 175
            ret = -2;
        } else {
176 177
            *value = val;
        }
178 179
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
180 181 182 183
        *value = (long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
184
    } else {
185
        ret = -1;
186
    }
187

188
    xmlXPathFreeObject(obj);
189
    return (ret);
190 191
}

192
/**
193
 * virXPathLong:
194 195 196 197 198 199 200 201 202 203 204
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
virXPathLong(virConnectPtr conn,
             const char *xpath,
             xmlXPathContextPtr ctxt,
             long *value)
{
    return virXPathLongBase(conn, xpath, ctxt, 10, value);
}

/**
 * virXPathLongHex:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 * according to a base of 16
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
virXPathLongHex(virConnectPtr conn,
                const char *xpath,
                xmlXPathContextPtr ctxt,
                long *value)
{
    return virXPathLongBase(conn, xpath, ctxt, 16, value);
}

static int
virXPathULongBase(virConnectPtr conn,
                  const char *xpath,
                  xmlXPathContextPtr ctxt,
                  int base,
                  unsigned long *value)
241 242 243 244 245 246
{
    xmlXPathObjectPtr obj;
    xmlNodePtr relnode;
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
247
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
248
                    "%s", _("Invalid parameter to virXPathULong()"));
249 250 251 252
        return (-1);
    }
    relnode = ctxt->node;
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
253
    ctxt->node = relnode;
254 255 256 257 258
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
        long val;

259
        val = strtoul((const char *) obj->stringval, &conv, base);
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
        if (conv == (const char *) obj->stringval) {
            ret = -2;
        } else {
            *value = val;
        }
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
        *value = (unsigned long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
    } else {
        ret = -1;
    }

    xmlXPathFreeObject(obj);
    return (ret);
}

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
/**
 * virXPathULong:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
virXPathULong(virConnectPtr conn,
              const char *xpath,
              xmlXPathContextPtr ctxt,
              unsigned long *value)
{
    return virXPathULongBase(conn, xpath, ctxt, 10, value);
}

/**
 * virXPathUHex:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 * according to base of 16
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
virXPathULongHex(virConnectPtr conn,
                 const char *xpath,
                 xmlXPathContextPtr ctxt,
                 unsigned long *value)
{
    return virXPathULongBase(conn, xpath, ctxt, 16, value);
}

M
Mark McLoughlin 已提交
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
/**
 * virXPathULongLong:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
 */
int
virXPathULongLong(virConnectPtr conn,
                  const char *xpath,
                  xmlXPathContextPtr ctxt,
                  unsigned long long *value)
{
    xmlXPathObjectPtr obj;
    xmlNodePtr relnode;
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
                    "%s", _("Invalid parameter to virXPathULong()"));
        return (-1);
    }
    relnode = ctxt->node;
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
351
    ctxt->node = relnode;
M
Mark McLoughlin 已提交
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
        unsigned long long val;

        val = strtoull((const char *) obj->stringval, &conv, 10);
        if (conv == (const char *) obj->stringval) {
            ret = -2;
        } else {
            *value = val;
        }
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
        *value = (unsigned long long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
    } else {
        ret = -1;
    }

    xmlXPathFreeObject(obj);
    return (ret);
}

377 378 379 380 381 382 383
char *
virXMLPropString(xmlNodePtr node,
                 const char *name)
{
    return (char *)xmlGetProp(node, BAD_CAST name);
}

384 385 386 387 388 389 390 391 392 393
/**
 * virXPathBoolean:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath boolean
 *
 * Returns 0 if false, 1 if true, or -1 if the evaluation failed.
 */
int
394 395 396
virXPathBoolean(virConnectPtr conn,
                const char *xpath,
                xmlXPathContextPtr ctxt)
397
{
398
    xmlXPathObjectPtr obj;
399
    xmlNodePtr relnode;
400 401 402
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
403
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
404
                    "%s", _("Invalid parameter to virXPathBoolean()"));
405
        return (-1);
406
    }
407
    relnode = ctxt->node;
408
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
409
    ctxt->node = relnode;
410 411
    if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
        (obj->boolval < 0) || (obj->boolval > 1)) {
412 413
        xmlXPathFreeObject(obj);
        return (-1);
414 415
    }
    ret = obj->boolval;
416

417
    xmlXPathFreeObject(obj);
418
    return (ret);
419 420 421 422 423 424 425 426 427 428 429 430 431
}

/**
 * virXPathNode:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath node set and returning
 * only one node, the first one in the set if any
 *
 * Returns a pointer to the node or NULL if the evaluation failed.
 */
xmlNodePtr
432 433 434
virXPathNode(virConnectPtr conn,
             const char *xpath,
             xmlXPathContextPtr ctxt)
435
{
436
    xmlXPathObjectPtr obj;
437
    xmlNodePtr relnode;
438 439 440
    xmlNodePtr ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
441
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
442
                    "%s", _("Invalid parameter to virXPathNode()"));
443
        return (NULL);
444
    }
445
    relnode = ctxt->node;
446
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
447
    ctxt->node = relnode;
448 449
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
450 451 452
        (obj->nodesetval->nodeTab == NULL)) {
        xmlXPathFreeObject(obj);
        return (NULL);
453
    }
454

455 456
    ret = obj->nodesetval->nodeTab[0];
    xmlXPathFreeObject(obj);
457
    return (ret);
458
}
459

460 461 462 463 464 465 466 467 468 469 470 471
/**
 * virXPathNodeSet:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @list: the returned list of nodes (or NULL if only count matters)
 *
 * Convenience function to evaluate an XPath node set
 *
 * Returns the number of nodes found in which case @list is set (and
 *         must be freed) or -1 if the evaluation failed.
 */
int
472 473 474 475
virXPathNodeSet(virConnectPtr conn,
                const char *xpath,
                xmlXPathContextPtr ctxt,
                xmlNodePtr **list)
476
{
477
    xmlXPathObjectPtr obj;
478
    xmlNodePtr relnode;
479 480 481
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
482
        virXMLError(conn, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
483
                    "%s", _("Invalid parameter to virXPathNodeSet()"));
484
        return (-1);
485
    }
486 487 488 489

    if (list != NULL)
        *list = NULL;

490
    relnode = ctxt->node;
491
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
492
    ctxt->node = relnode;
493
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
494
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) {
495 496
        xmlXPathFreeObject(obj);
        return (-1);
497
    }
498

499
    ret = obj->nodesetval->nodeNr;
500
    if (list != NULL && ret) {
501
        if (VIR_ALLOC_N(*list, ret) < 0) {
502
            virReportOOMError(conn);
503
            ret = -1;
504 505 506 507
        } else {
            memcpy(*list, obj->nodesetval->nodeTab,
                   ret * sizeof(xmlNodePtr));
        }
508 509
    }
    xmlXPathFreeObject(obj);
510
    return (ret);
511
}