2007-03-15 17:30:04 +00:00
|
|
|
/*
|
2007-06-26 22:21:22 +00:00
|
|
|
* buf.c: buffers for libvirt
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2007-06-26 22:21:22 +00:00
|
|
|
* Copyright (C) 2005-2007 Red Hat, Inc.
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
|
|
|
* See COPYING.LIB for the License of this software
|
|
|
|
*
|
|
|
|
* Daniel Veillard <veillard@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-12-05 21:40:15 +00:00
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
#include "libvirt/libvirt.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
2007-12-17 10:05:35 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
#define __VIR_BUFFER_C__
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
#include "buf.h"
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
|
|
|
|
/* If adding more fields, ensure to edit buf.h to match
|
|
|
|
the number of fields */
|
|
|
|
struct _virBuffer {
|
|
|
|
unsigned int size;
|
|
|
|
unsigned int use;
|
|
|
|
unsigned int error;
|
|
|
|
char *content;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virBufferFail
|
|
|
|
* @buf: the buffer
|
|
|
|
*
|
|
|
|
* Mark the buffer has having failed a memory allocation,
|
|
|
|
* freeing the content and setting the error flag.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
virBufferNoMemory(const virBufferPtr buf)
|
|
|
|
{
|
|
|
|
free(buf->content);
|
|
|
|
buf->content = NULL;
|
|
|
|
buf->size = 0;
|
|
|
|
buf->use = 0;
|
|
|
|
buf->error = 1;
|
|
|
|
}
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
/**
|
2007-06-26 22:21:22 +00:00
|
|
|
* virBufferGrow:
|
2007-03-15 17:30:04 +00:00
|
|
|
* @buf: the buffer
|
2007-03-21 15:24:56 +00:00
|
|
|
* @len: the minimum free size to allocate on top of existing used space
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2007-03-21 15:24:56 +00:00
|
|
|
* Grow the available space of a buffer to at least @len bytes.
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Returns zero on success or -1 on error
|
2007-03-15 17:30:04 +00:00
|
|
|
*/
|
|
|
|
static int
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferGrow(virBufferPtr buf, unsigned int len)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
char *newbuf;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (buf->error)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ((len + buf->use) < buf->size)
|
|
|
|
return 0;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
|
|
|
size = buf->use + len + 1000;
|
|
|
|
|
2007-12-11 21:57:29 +00:00
|
|
|
newbuf = realloc(buf->content, size);
|
2008-04-28 15:14:59 +00:00
|
|
|
if (newbuf == NULL) {
|
|
|
|
virBufferNoMemory(buf);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-03-15 17:30:04 +00:00
|
|
|
buf->content = newbuf;
|
|
|
|
buf->size = size;
|
2008-04-28 15:14:59 +00:00
|
|
|
return 0;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-06-26 22:21:22 +00:00
|
|
|
* virBufferAdd:
|
2007-12-17 10:05:35 +00:00
|
|
|
* @buf: the buffer to add to
|
2007-03-15 17:30:04 +00:00
|
|
|
* @str: the string
|
|
|
|
* @len: the number of bytes to add
|
|
|
|
*
|
|
|
|
* Add a string range to an XML buffer. if len == -1, the length of
|
|
|
|
* str is recomputed to the full string.
|
|
|
|
*
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
|
|
|
__virBufferAdd(const virBufferPtr buf, const char *str, int len)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
|
|
|
unsigned int needSize;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if ((str == NULL) || (buf == NULL) || (len == 0))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
|
|
|
if (len < 0)
|
|
|
|
len = strlen(str);
|
|
|
|
|
|
|
|
needSize = buf->use + len + 2;
|
2008-04-28 15:14:59 +00:00
|
|
|
if (needSize > buf->size &&
|
|
|
|
virBufferGrow(buf, needSize - buf->use) < 0)
|
|
|
|
return;
|
2007-12-17 10:05:35 +00:00
|
|
|
|
|
|
|
memcpy (&buf->content[buf->use], str, len);
|
2007-03-15 17:30:04 +00:00
|
|
|
buf->use += len;
|
2008-04-28 15:14:59 +00:00
|
|
|
buf->content[buf->use] = '\0';
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2007-12-17 10:05:35 +00:00
|
|
|
/**
|
|
|
|
* virBufferAddChar:
|
|
|
|
* @buf: the buffer to add to
|
|
|
|
* @c: the character to add
|
|
|
|
*
|
|
|
|
* Add a single character 'c' to a buffer.
|
|
|
|
*
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2008-02-20 15:29:13 +00:00
|
|
|
__virBufferAddChar (virBufferPtr buf, char c)
|
2007-12-17 10:05:35 +00:00
|
|
|
{
|
|
|
|
unsigned int needSize;
|
|
|
|
|
|
|
|
if (buf == NULL)
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
2007-12-17 10:05:35 +00:00
|
|
|
|
|
|
|
needSize = buf->use + 2;
|
2008-04-28 15:14:59 +00:00
|
|
|
if (needSize > buf->size &&
|
|
|
|
virBufferGrow (buf, needSize - buf->use) < 0)
|
|
|
|
return;
|
2007-12-17 10:05:35 +00:00
|
|
|
|
|
|
|
buf->content[buf->use++] = c;
|
2008-04-28 15:14:59 +00:00
|
|
|
buf->content[buf->use] = '\0';
|
2007-12-17 10:05:35 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
2008-04-28 15:14:59 +00:00
|
|
|
* virBufferContentAndReset:
|
|
|
|
* @buf: Buffer
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Get the content from the buffer and free (only) the buffer structure.
|
|
|
|
* The caller owns the returned string & should free it when no longer
|
|
|
|
* required. The buffer object is reset to its initial state.
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Returns the buffer content or NULL in case of error.
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
char *
|
|
|
|
__virBufferContentAndReset(const virBufferPtr buf)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
2008-04-28 15:14:59 +00:00
|
|
|
char *str;
|
|
|
|
if (buf == NULL)
|
|
|
|
return NULL;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (buf->error) {
|
|
|
|
memset(buf, 0, sizeof(*buf));
|
2007-03-15 17:30:04 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
str = buf->content;
|
|
|
|
memset(buf, 0, sizeof(*buf));
|
|
|
|
return str;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2007-06-29 13:23:13 +00:00
|
|
|
/**
|
2008-04-28 15:14:59 +00:00
|
|
|
* virBufferError:
|
|
|
|
* @buf: the buffer
|
2007-06-29 13:23:13 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Check to see if the buffer is in an error state due
|
|
|
|
* to failed memory allocation
|
|
|
|
*
|
|
|
|
* Return true if in error, 0 if normal
|
2007-06-29 13:23:13 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
int
|
|
|
|
__virBufferError(const virBufferPtr buf)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
2008-04-28 15:14:59 +00:00
|
|
|
if (buf == NULL)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return buf->error;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-04-28 15:14:59 +00:00
|
|
|
* virBufferUse:
|
|
|
|
* @buf: the usage of the string in the buffer
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
2008-04-28 15:14:59 +00:00
|
|
|
* Return the string usage in bytes
|
2007-03-15 17:30:04 +00:00
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
unsigned int
|
|
|
|
virBufferUse(const virBufferPtr buf)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
2007-06-29 13:23:13 +00:00
|
|
|
if (buf == NULL)
|
2008-04-28 15:14:59 +00:00
|
|
|
return 0;
|
2007-03-15 17:30:04 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return buf->use;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-06-26 22:21:22 +00:00
|
|
|
* virBufferVSprintf:
|
2007-03-15 17:30:04 +00:00
|
|
|
* @buf: the buffer to dump
|
|
|
|
* @format: the format
|
2007-06-29 13:23:13 +00:00
|
|
|
* @...: the variable list of arguments
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
|
|
|
* Do a formatted print to an XML buffer.
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
|
|
|
__virBufferVSprintf(const virBufferPtr buf, const char *format, ...)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
2007-08-30 13:12:44 +00:00
|
|
|
int size, count, grow_size;
|
2007-03-15 17:30:04 +00:00
|
|
|
va_list locarg, argptr;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if ((format == NULL) || (buf == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
2008-02-20 15:29:13 +00:00
|
|
|
|
|
|
|
if (buf->size == 0 &&
|
|
|
|
virBufferGrow(buf, 100) < 0)
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
2008-02-20 15:29:13 +00:00
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
size = buf->size - buf->use - 1;
|
|
|
|
va_start(argptr, format);
|
|
|
|
va_copy(locarg, argptr);
|
|
|
|
while (((count = vsnprintf(&buf->content[buf->use], size, format,
|
|
|
|
locarg)) < 0) || (count >= size - 1)) {
|
|
|
|
buf->content[buf->use] = 0;
|
|
|
|
va_end(locarg);
|
2008-04-28 15:14:59 +00:00
|
|
|
|
2007-08-30 13:12:44 +00:00
|
|
|
grow_size = (count > 1000) ? count : 1000;
|
2008-04-28 15:14:59 +00:00
|
|
|
if (virBufferGrow(buf, grow_size) < 0)
|
|
|
|
return;
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
size = buf->size - buf->use - 1;
|
|
|
|
va_copy(locarg, argptr);
|
|
|
|
}
|
|
|
|
va_end(locarg);
|
|
|
|
buf->use += count;
|
2008-04-28 15:14:59 +00:00
|
|
|
buf->content[buf->use] = '\0';
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
|
2007-07-09 11:24:52 +00:00
|
|
|
/**
|
|
|
|
* virBufferEscapeString:
|
|
|
|
* @buf: the buffer to dump
|
|
|
|
* @format: a printf like format string but with only one %s parameter
|
|
|
|
* @str: the string argument which need to be escaped
|
|
|
|
*
|
|
|
|
* Do a formatted print with a single string to an XML buffer. The string
|
|
|
|
* is escaped to avoid generating a not well-formed XML instance.
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
|
|
|
virBufferEscapeString(const virBufferPtr buf, const char *format, const char *str)
|
2007-07-09 11:24:52 +00:00
|
|
|
{
|
2007-08-30 13:12:44 +00:00
|
|
|
int size, count, len, grow_size;
|
2007-07-09 11:24:52 +00:00
|
|
|
char *escaped, *out;
|
|
|
|
const char *cur;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if ((format == NULL) || (buf == NULL) || (str == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
2007-07-09 11:24:52 +00:00
|
|
|
|
|
|
|
len = strlen(str);
|
|
|
|
escaped = malloc(5 * len + 1);
|
|
|
|
if (escaped == NULL) {
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferNoMemory(buf);
|
|
|
|
return;
|
2007-07-09 11:24:52 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
|
2007-07-09 11:24:52 +00:00
|
|
|
cur = str;
|
|
|
|
out = escaped;
|
|
|
|
while (*cur != 0) {
|
|
|
|
if (*cur == '<') {
|
2008-04-10 16:54:54 +00:00
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'l';
|
|
|
|
*out++ = 't';
|
|
|
|
*out++ = ';';
|
|
|
|
} else if (*cur == '>') {
|
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'g';
|
|
|
|
*out++ = 't';
|
|
|
|
*out++ = ';';
|
|
|
|
} else if (*cur == '&') {
|
|
|
|
*out++ = '&';
|
|
|
|
*out++ = 'a';
|
|
|
|
*out++ = 'm';
|
|
|
|
*out++ = 'p';
|
|
|
|
*out++ = ';';
|
|
|
|
} else if ((*cur >= 0x20) || (*cur == '\n') || (*cur == '\t') ||
|
|
|
|
(*cur == '\r')) {
|
|
|
|
/*
|
|
|
|
* default case, just copy !
|
|
|
|
* Note that character over 0x80 are likely to give problem
|
|
|
|
* with UTF-8 XML, but since our string don't have an encoding
|
|
|
|
* it's hard to handle properly we have to assume it's UTF-8 too
|
|
|
|
*/
|
|
|
|
*out++ = *cur;
|
|
|
|
}
|
|
|
|
cur++;
|
2007-07-09 11:24:52 +00:00
|
|
|
}
|
|
|
|
*out = 0;
|
|
|
|
|
|
|
|
size = buf->size - buf->use - 1;
|
|
|
|
while (((count = snprintf(&buf->content[buf->use], size, format,
|
|
|
|
(char *)escaped)) < 0) || (count >= size - 1)) {
|
|
|
|
buf->content[buf->use] = 0;
|
2007-08-30 13:12:44 +00:00
|
|
|
grow_size = (count > 1000) ? count : 1000;
|
|
|
|
if (virBufferGrow(buf, grow_size) < 0) {
|
2008-04-10 16:54:54 +00:00
|
|
|
free(escaped);
|
2008-04-28 15:14:59 +00:00
|
|
|
return;
|
2007-07-09 11:24:52 +00:00
|
|
|
}
|
|
|
|
size = buf->size - buf->use - 1;
|
|
|
|
}
|
|
|
|
buf->use += count;
|
2008-04-28 15:14:59 +00:00
|
|
|
buf->content[buf->use] = '\0';
|
2007-07-09 11:24:52 +00:00
|
|
|
free(escaped);
|
|
|
|
}
|
|
|
|
|
2007-12-17 10:05:35 +00:00
|
|
|
/**
|
|
|
|
* virBufferURIEncodeString:
|
|
|
|
* @buf: the buffer to append to
|
|
|
|
* @str: the string argument which will be URI-encoded
|
|
|
|
*
|
|
|
|
* Append the string to the buffer. The string will be URI-encoded
|
|
|
|
* during the append (ie any non alpha-numeric characters are replaced
|
|
|
|
* with '%xx' hex sequences).
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2007-12-17 10:05:35 +00:00
|
|
|
virBufferURIEncodeString (virBufferPtr buf, const char *str)
|
|
|
|
{
|
|
|
|
int grow_size = 0;
|
|
|
|
const char *p;
|
|
|
|
unsigned char uc;
|
|
|
|
const char *hex = "0123456789abcdef";
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if ((buf == NULL) || (str == NULL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (buf->error)
|
|
|
|
return;
|
|
|
|
|
2007-12-17 10:05:35 +00:00
|
|
|
for (p = str; *p; ++p) {
|
|
|
|
/* This may not work on EBCDIC. */
|
|
|
|
if ((*p >= 'a' && *p <= 'z') ||
|
|
|
|
(*p >= 'A' && *p <= 'Z') ||
|
|
|
|
(*p >= '0' && *p <= '9'))
|
|
|
|
grow_size++;
|
|
|
|
else
|
|
|
|
grow_size += 3; /* %ab */
|
|
|
|
}
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (virBufferGrow (buf, grow_size) < 0)
|
|
|
|
return;
|
2007-12-17 10:05:35 +00:00
|
|
|
|
|
|
|
for (p = str; *p; ++p) {
|
|
|
|
/* This may not work on EBCDIC. */
|
|
|
|
if ((*p >= 'a' && *p <= 'z') ||
|
|
|
|
(*p >= 'A' && *p <= 'Z') ||
|
|
|
|
(*p >= '0' && *p <= '9'))
|
|
|
|
buf->content[buf->use++] = *p;
|
|
|
|
else {
|
|
|
|
uc = (unsigned char) *p;
|
|
|
|
buf->content[buf->use++] = '%';
|
|
|
|
buf->content[buf->use++] = hex[uc >> 4];
|
|
|
|
buf->content[buf->use++] = hex[uc & 0xf];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf->content[buf->use] = '\0';
|
|
|
|
}
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
/**
|
2007-06-26 22:21:22 +00:00
|
|
|
* virBufferStrcat:
|
2007-03-15 17:30:04 +00:00
|
|
|
* @buf: the buffer to dump
|
2007-06-29 13:23:13 +00:00
|
|
|
* @...: the variable list of strings, the last argument must be NULL
|
2007-03-15 17:30:04 +00:00
|
|
|
*
|
|
|
|
* Concatenate strings to an XML buffer.
|
|
|
|
*/
|
2008-04-28 15:14:59 +00:00
|
|
|
void
|
2007-06-26 22:21:22 +00:00
|
|
|
virBufferStrcat(virBufferPtr buf, ...)
|
2007-03-15 17:30:04 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
char *str;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (buf->error)
|
|
|
|
return;
|
|
|
|
|
2007-03-15 17:30:04 +00:00
|
|
|
va_start(ap, buf);
|
|
|
|
|
|
|
|
while ((str = va_arg(ap, char *)) != NULL) {
|
|
|
|
unsigned int len = strlen(str);
|
|
|
|
unsigned int needSize = buf->use + len + 2;
|
|
|
|
|
|
|
|
if (needSize > buf->size) {
|
2008-04-28 15:14:59 +00:00
|
|
|
if (virBufferGrow(buf, needSize - buf->use) < 0)
|
|
|
|
return;
|
2007-03-15 17:30:04 +00:00
|
|
|
}
|
|
|
|
memcpy(&buf->content[buf->use], str, len);
|
|
|
|
buf->use += len;
|
|
|
|
buf->content[buf->use] = 0;
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
}
|