Annotation of embedaddon/libxml2/buf.c, revision 1.1
1.1 ! misho 1: /*
! 2: * buf.c: memory buffers for libxml2
! 3: *
! 4: * new buffer structures and entry points to simplify the maintainance
! 5: * of libxml2 and ensure we keep good control over memory allocations
! 6: * and stay 64 bits clean.
! 7: * The new entry point use the xmlBufPtr opaque structure and
! 8: * xmlBuf...() counterparts to the old xmlBuf...() functions
! 9: *
! 10: * See Copyright for the status of this software.
! 11: *
! 12: * daniel@veillard.com
! 13: */
! 14:
! 15: #define IN_LIBXML
! 16: #include "libxml.h"
! 17:
! 18: #include <string.h> /* for memset() only ! */
! 19: #include <limits.h>
! 20: #ifdef HAVE_CTYPE_H
! 21: #include <ctype.h>
! 22: #endif
! 23: #ifdef HAVE_STDLIB_H
! 24: #include <stdlib.h>
! 25: #endif
! 26:
! 27: #include <libxml/tree.h>
! 28: #include <libxml/globals.h>
! 29: #include <libxml/tree.h>
! 30: #include "buf.h"
! 31:
! 32: #define WITH_BUFFER_COMPAT
! 33:
! 34: /**
! 35: * xmlBuf:
! 36: *
! 37: * A buffer structure. The base of the structure is somehow compatible
! 38: * with struct _xmlBuffer to limit risks on application which accessed
! 39: * directly the input->buf->buffer structures.
! 40: */
! 41:
! 42: struct _xmlBuf {
! 43: xmlChar *content; /* The buffer content UTF8 */
! 44: unsigned int compat_use; /* for binary compatibility */
! 45: unsigned int compat_size; /* for binary compatibility */
! 46: xmlBufferAllocationScheme alloc; /* The realloc method */
! 47: xmlChar *contentIO; /* in IO mode we may have a different base */
! 48: size_t use; /* The buffer size used */
! 49: size_t size; /* The buffer size */
! 50: xmlBufferPtr buffer; /* wrapper for an old buffer */
! 51: int error; /* an error code if a failure occured */
! 52: };
! 53:
! 54: #ifdef WITH_BUFFER_COMPAT
! 55: /*
! 56: * Macro for compatibility with xmlBuffer to be used after an xmlBuf
! 57: * is updated. This makes sure the compat fields are updated too.
! 58: */
! 59: #define UPDATE_COMPAT(buf) \
! 60: if (buf->size < INT_MAX) buf->compat_size = buf->size; \
! 61: else buf->compat_size = INT_MAX; \
! 62: if (buf->use < INT_MAX) buf->compat_use = buf->use; \
! 63: else buf->compat_use = INT_MAX;
! 64:
! 65: /*
! 66: * Macro for compatibility with xmlBuffer to be used in all the xmlBuf
! 67: * entry points, it checks that the compat fields have not been modified
! 68: * by direct call to xmlBuffer function from code compiled before 2.9.0 .
! 69: */
! 70: #define CHECK_COMPAT(buf) \
! 71: if (buf->size != (size_t) buf->compat_size) \
! 72: if (buf->compat_size < INT_MAX) \
! 73: buf->size = buf->compat_size; \
! 74: if (buf->use != (size_t) buf->compat_use) \
! 75: if (buf->compat_use < INT_MAX) \
! 76: buf->use = buf->compat_use;
! 77:
! 78: #else /* ! WITH_BUFFER_COMPAT */
! 79: #define UPDATE_COMPAT(buf)
! 80: #define CHECK_COMPAT(buf)
! 81: #endif /* WITH_BUFFER_COMPAT */
! 82:
! 83: /**
! 84: * xmlBufMemoryError:
! 85: * @extra: extra informations
! 86: *
! 87: * Handle an out of memory condition
! 88: * To be improved...
! 89: */
! 90: static void
! 91: xmlBufMemoryError(xmlBufPtr buf, const char *extra)
! 92: {
! 93: __xmlSimpleError(XML_FROM_BUFFER, XML_ERR_NO_MEMORY, NULL, NULL, extra);
! 94: if ((buf) && (buf->error == 0))
! 95: buf->error = XML_ERR_NO_MEMORY;
! 96: }
! 97:
! 98: /**
! 99: * xmlBufOverflowError:
! 100: * @extra: extra informations
! 101: *
! 102: * Handle a buffer overflow error
! 103: * To be improved...
! 104: */
! 105: static void
! 106: xmlBufOverflowError(xmlBufPtr buf, const char *extra)
! 107: {
! 108: __xmlSimpleError(XML_FROM_BUFFER, XML_BUF_OVERFLOW, NULL, NULL, extra);
! 109: if ((buf) && (buf->error == 0))
! 110: buf->error = XML_BUF_OVERFLOW;
! 111: }
! 112:
! 113:
! 114: /**
! 115: * xmlBufCreate:
! 116: *
! 117: * routine to create an XML buffer.
! 118: * returns the new structure.
! 119: */
! 120: xmlBufPtr
! 121: xmlBufCreate(void) {
! 122: xmlBufPtr ret;
! 123:
! 124: ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
! 125: if (ret == NULL) {
! 126: xmlBufMemoryError(NULL, "creating buffer");
! 127: return(NULL);
! 128: }
! 129: ret->compat_use = 0;
! 130: ret->use = 0;
! 131: ret->error = 0;
! 132: ret->buffer = NULL;
! 133: ret->size = xmlDefaultBufferSize;
! 134: ret->compat_size = xmlDefaultBufferSize;
! 135: ret->alloc = xmlBufferAllocScheme;
! 136: ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
! 137: if (ret->content == NULL) {
! 138: xmlBufMemoryError(ret, "creating buffer");
! 139: xmlFree(ret);
! 140: return(NULL);
! 141: }
! 142: ret->content[0] = 0;
! 143: ret->contentIO = NULL;
! 144: return(ret);
! 145: }
! 146:
! 147: /**
! 148: * xmlBufCreateSize:
! 149: * @size: initial size of buffer
! 150: *
! 151: * routine to create an XML buffer.
! 152: * returns the new structure.
! 153: */
! 154: xmlBufPtr
! 155: xmlBufCreateSize(size_t size) {
! 156: xmlBufPtr ret;
! 157:
! 158: ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
! 159: if (ret == NULL) {
! 160: xmlBufMemoryError(NULL, "creating buffer");
! 161: return(NULL);
! 162: }
! 163: ret->compat_use = 0;
! 164: ret->use = 0;
! 165: ret->error = 0;
! 166: ret->buffer = NULL;
! 167: ret->alloc = xmlBufferAllocScheme;
! 168: ret->size = (size ? size+2 : 0); /* +1 for ending null */
! 169: ret->compat_size = (int) ret->size;
! 170: if (ret->size){
! 171: ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
! 172: if (ret->content == NULL) {
! 173: xmlBufMemoryError(ret, "creating buffer");
! 174: xmlFree(ret);
! 175: return(NULL);
! 176: }
! 177: ret->content[0] = 0;
! 178: } else
! 179: ret->content = NULL;
! 180: ret->contentIO = NULL;
! 181: return(ret);
! 182: }
! 183:
! 184: /**
! 185: * xmlBufDetach:
! 186: * @buf: the buffer
! 187: *
! 188: * Remove the string contained in a buffer and give it back to the
! 189: * caller. The buffer is reset to an empty content.
! 190: * This doesn't work with immutable buffers as they can't be reset.
! 191: *
! 192: * Returns the previous string contained by the buffer.
! 193: */
! 194: xmlChar *
! 195: xmlBufDetach(xmlBufPtr buf) {
! 196: xmlChar *ret;
! 197:
! 198: if (buf == NULL)
! 199: return(NULL);
! 200: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
! 201: return(NULL);
! 202: if (buf->buffer != NULL)
! 203: return(NULL);
! 204: if (buf->error)
! 205: return(NULL);
! 206:
! 207: ret = buf->content;
! 208: buf->content = NULL;
! 209: buf->size = 0;
! 210: buf->use = 0;
! 211: buf->compat_use = 0;
! 212: buf->compat_size = 0;
! 213:
! 214: return ret;
! 215: }
! 216:
! 217:
! 218: /**
! 219: * xmlBufCreateStatic:
! 220: * @mem: the memory area
! 221: * @size: the size in byte
! 222: *
! 223: * routine to create an XML buffer from an immutable memory area.
! 224: * The area won't be modified nor copied, and is expected to be
! 225: * present until the end of the buffer lifetime.
! 226: *
! 227: * returns the new structure.
! 228: */
! 229: xmlBufPtr
! 230: xmlBufCreateStatic(void *mem, size_t size) {
! 231: xmlBufPtr ret;
! 232:
! 233: if ((mem == NULL) || (size == 0))
! 234: return(NULL);
! 235:
! 236: ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
! 237: if (ret == NULL) {
! 238: xmlBufMemoryError(NULL, "creating buffer");
! 239: return(NULL);
! 240: }
! 241: if (size < INT_MAX) {
! 242: ret->compat_use = size;
! 243: ret->compat_size = size;
! 244: } else {
! 245: ret->compat_use = INT_MAX;
! 246: ret->compat_size = INT_MAX;
! 247: }
! 248: ret->use = size;
! 249: ret->size = size;
! 250: ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
! 251: ret->content = (xmlChar *) mem;
! 252: ret->error = 0;
! 253: ret->buffer = NULL;
! 254: return(ret);
! 255: }
! 256:
! 257: /**
! 258: * xmlBufGetAllocationScheme:
! 259: * @buf: the buffer
! 260: *
! 261: * Get the buffer allocation scheme
! 262: *
! 263: * Returns the scheme or -1 in case of error
! 264: */
! 265: int
! 266: xmlBufGetAllocationScheme(xmlBufPtr buf) {
! 267: if (buf == NULL) {
! 268: #ifdef DEBUG_BUFFER
! 269: xmlGenericError(xmlGenericErrorContext,
! 270: "xmlBufGetAllocationScheme: buf == NULL\n");
! 271: #endif
! 272: return(-1);
! 273: }
! 274: return(buf->alloc);
! 275: }
! 276:
! 277: /**
! 278: * xmlBufSetAllocationScheme:
! 279: * @buf: the buffer to tune
! 280: * @scheme: allocation scheme to use
! 281: *
! 282: * Sets the allocation scheme for this buffer
! 283: *
! 284: * returns 0 in case of success and -1 in case of failure
! 285: */
! 286: int
! 287: xmlBufSetAllocationScheme(xmlBufPtr buf,
! 288: xmlBufferAllocationScheme scheme) {
! 289: if ((buf == NULL) || (buf->error != 0)) {
! 290: #ifdef DEBUG_BUFFER
! 291: xmlGenericError(xmlGenericErrorContext,
! 292: "xmlBufSetAllocationScheme: buf == NULL or in error\n");
! 293: #endif
! 294: return(-1);
! 295: }
! 296: if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
! 297: (buf->alloc == XML_BUFFER_ALLOC_IO))
! 298: return(-1);
! 299: if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
! 300: (scheme == XML_BUFFER_ALLOC_EXACT) ||
! 301: (scheme == XML_BUFFER_ALLOC_HYBRID) ||
! 302: (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) {
! 303: buf->alloc = scheme;
! 304: if (buf->buffer)
! 305: buf->buffer->alloc = scheme;
! 306: return(0);
! 307: }
! 308: /*
! 309: * Switching a buffer ALLOC_IO has the side effect of initializing
! 310: * the contentIO field with the current content
! 311: */
! 312: if (scheme == XML_BUFFER_ALLOC_IO) {
! 313: buf->alloc = XML_BUFFER_ALLOC_IO;
! 314: buf->contentIO = buf->content;
! 315: }
! 316: return(-1);
! 317: }
! 318:
! 319: /**
! 320: * xmlBufFree:
! 321: * @buf: the buffer to free
! 322: *
! 323: * Frees an XML buffer. It frees both the content and the structure which
! 324: * encapsulate it.
! 325: */
! 326: void
! 327: xmlBufFree(xmlBufPtr buf) {
! 328: if (buf == NULL) {
! 329: #ifdef DEBUG_BUFFER
! 330: xmlGenericError(xmlGenericErrorContext,
! 331: "xmlBufFree: buf == NULL\n");
! 332: #endif
! 333: return;
! 334: }
! 335:
! 336: if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
! 337: (buf->contentIO != NULL)) {
! 338: xmlFree(buf->contentIO);
! 339: } else if ((buf->content != NULL) &&
! 340: (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
! 341: xmlFree(buf->content);
! 342: }
! 343: xmlFree(buf);
! 344: }
! 345:
! 346: /**
! 347: * xmlBufEmpty:
! 348: * @buf: the buffer
! 349: *
! 350: * empty a buffer.
! 351: */
! 352: void
! 353: xmlBufEmpty(xmlBufPtr buf) {
! 354: if ((buf == NULL) || (buf->error != 0)) return;
! 355: if (buf->content == NULL) return;
! 356: CHECK_COMPAT(buf)
! 357: buf->use = 0;
! 358: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
! 359: buf->content = BAD_CAST "";
! 360: } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
! 361: (buf->contentIO != NULL)) {
! 362: size_t start_buf = buf->content - buf->contentIO;
! 363:
! 364: buf->size += start_buf;
! 365: buf->content = buf->contentIO;
! 366: buf->content[0] = 0;
! 367: } else {
! 368: buf->content[0] = 0;
! 369: }
! 370: UPDATE_COMPAT(buf)
! 371: }
! 372:
! 373: /**
! 374: * xmlBufShrink:
! 375: * @buf: the buffer to dump
! 376: * @len: the number of xmlChar to remove
! 377: *
! 378: * Remove the beginning of an XML buffer.
! 379: * NOTE that this routine behaviour differs from xmlBufferShrink()
! 380: * as it will return 0 on error instead of -1 due to size_t being
! 381: * used as the return type.
! 382: *
! 383: * Returns the number of byte removed or 0 in case of failure
! 384: */
! 385: size_t
! 386: xmlBufShrink(xmlBufPtr buf, size_t len) {
! 387: if ((buf == NULL) || (buf->error != 0)) return(0);
! 388: CHECK_COMPAT(buf)
! 389: if (len == 0) return(0);
! 390: if (len > buf->use) return(0);
! 391:
! 392: buf->use -= len;
! 393: if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
! 394: ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
! 395: /*
! 396: * we just move the content pointer, but also make sure
! 397: * the perceived buffer size has shrinked accordingly
! 398: */
! 399: buf->content += len;
! 400: buf->size -= len;
! 401:
! 402: /*
! 403: * sometimes though it maybe be better to really shrink
! 404: * on IO buffers
! 405: */
! 406: if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
! 407: size_t start_buf = buf->content - buf->contentIO;
! 408: if (start_buf >= buf->size) {
! 409: memmove(buf->contentIO, &buf->content[0], buf->use);
! 410: buf->content = buf->contentIO;
! 411: buf->content[buf->use] = 0;
! 412: buf->size += start_buf;
! 413: }
! 414: }
! 415: } else {
! 416: memmove(buf->content, &buf->content[len], buf->use);
! 417: buf->content[buf->use] = 0;
! 418: }
! 419: UPDATE_COMPAT(buf)
! 420: return(len);
! 421: }
! 422:
! 423: /**
! 424: * xmlBufGrowInternal:
! 425: * @buf: the buffer
! 426: * @len: the minimum free size to allocate
! 427: *
! 428: * Grow the available space of an XML buffer, @len is the target value
! 429: * Error checking should be done on buf->error since using the return
! 430: * value doesn't work that well
! 431: *
! 432: * Returns 0 in case of error or the length made available otherwise
! 433: */
! 434: static size_t
! 435: xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
! 436: size_t size;
! 437: xmlChar *newbuf;
! 438:
! 439: if ((buf == NULL) || (buf->error != 0)) return(0);
! 440: CHECK_COMPAT(buf)
! 441:
! 442: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
! 443: if (buf->use + len < buf->size)
! 444: return(buf->size - buf->use);
! 445:
! 446: /*
! 447: * Windows has a BIG problem on realloc timing, so we try to double
! 448: * the buffer size (if that's enough) (bug 146697)
! 449: * Apparently BSD too, and it's probably best for linux too
! 450: * On an embedded system this may be something to change
! 451: */
! 452: #if 1
! 453: if (buf->size > (size_t) len)
! 454: size = buf->size * 2;
! 455: else
! 456: size = buf->use + len + 100;
! 457: #else
! 458: size = buf->use + len + 100;
! 459: #endif
! 460:
! 461: if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
! 462: size_t start_buf = buf->content - buf->contentIO;
! 463:
! 464: newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
! 465: if (newbuf == NULL) {
! 466: xmlBufMemoryError(buf, "growing buffer");
! 467: return(0);
! 468: }
! 469: buf->contentIO = newbuf;
! 470: buf->content = newbuf + start_buf;
! 471: } else {
! 472: newbuf = (xmlChar *) xmlRealloc(buf->content, size);
! 473: if (newbuf == NULL) {
! 474: xmlBufMemoryError(buf, "growing buffer");
! 475: return(0);
! 476: }
! 477: buf->content = newbuf;
! 478: }
! 479: buf->size = size;
! 480: UPDATE_COMPAT(buf)
! 481: return(buf->size - buf->use);
! 482: }
! 483:
! 484: /**
! 485: * xmlBufGrow:
! 486: * @buf: the buffer
! 487: * @len: the minimum free size to allocate
! 488: *
! 489: * Grow the available space of an XML buffer, @len is the target value
! 490: * This is been kept compatible with xmlBufferGrow() as much as possible
! 491: *
! 492: * Returns -1 in case of error or the length made available otherwise
! 493: */
! 494: int
! 495: xmlBufGrow(xmlBufPtr buf, int len) {
! 496: size_t ret;
! 497:
! 498: if ((buf == NULL) || (len < 0)) return(-1);
! 499: if (len == 0)
! 500: return(0);
! 501: ret = xmlBufGrowInternal(buf, len);
! 502: if (buf->error != 0)
! 503: return(-1);
! 504: return((int) ret);
! 505: }
! 506:
! 507: /**
! 508: * xmlBufInflate:
! 509: * @buf: the buffer
! 510: * @len: the minimum extra free size to allocate
! 511: *
! 512: * Grow the available space of an XML buffer, adding at least @len bytes
! 513: *
! 514: * Returns 0 if successful or -1 in case of error
! 515: */
! 516: int
! 517: xmlBufInflate(xmlBufPtr buf, size_t len) {
! 518: if (buf == NULL) return(-1);
! 519: xmlBufGrowInternal(buf, len + buf->size);
! 520: if (buf->error)
! 521: return(-1);
! 522: return(0);
! 523: }
! 524:
! 525: /**
! 526: * xmlBufDump:
! 527: * @file: the file output
! 528: * @buf: the buffer to dump
! 529: *
! 530: * Dumps an XML buffer to a FILE *.
! 531: * Returns the number of #xmlChar written
! 532: */
! 533: size_t
! 534: xmlBufDump(FILE *file, xmlBufPtr buf) {
! 535: size_t ret;
! 536:
! 537: if ((buf == NULL) || (buf->error != 0)) {
! 538: #ifdef DEBUG_BUFFER
! 539: xmlGenericError(xmlGenericErrorContext,
! 540: "xmlBufDump: buf == NULL or in error\n");
! 541: #endif
! 542: return(0);
! 543: }
! 544: if (buf->content == NULL) {
! 545: #ifdef DEBUG_BUFFER
! 546: xmlGenericError(xmlGenericErrorContext,
! 547: "xmlBufDump: buf->content == NULL\n");
! 548: #endif
! 549: return(0);
! 550: }
! 551: CHECK_COMPAT(buf)
! 552: if (file == NULL)
! 553: file = stdout;
! 554: ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
! 555: return(ret);
! 556: }
! 557:
! 558: /**
! 559: * xmlBufContent:
! 560: * @buf: the buffer
! 561: *
! 562: * Function to extract the content of a buffer
! 563: *
! 564: * Returns the internal content
! 565: */
! 566:
! 567: xmlChar *
! 568: xmlBufContent(const xmlBufPtr buf)
! 569: {
! 570: if ((!buf) || (buf->error))
! 571: return NULL;
! 572:
! 573: return(buf->content);
! 574: }
! 575:
! 576: /**
! 577: * xmlBufEnd:
! 578: * @buf: the buffer
! 579: *
! 580: * Function to extract the end of the content of a buffer
! 581: *
! 582: * Returns the end of the internal content or NULL in case of error
! 583: */
! 584:
! 585: xmlChar *
! 586: xmlBufEnd(const xmlBufPtr buf)
! 587: {
! 588: if ((!buf) || (buf->error))
! 589: return NULL;
! 590: CHECK_COMPAT(buf)
! 591:
! 592: return(&buf->content[buf->use]);
! 593: }
! 594:
! 595: /**
! 596: * xmlBufAddLen:
! 597: * @buf: the buffer
! 598: * @len: the size which were added at the end
! 599: *
! 600: * Sometime data may be added at the end of the buffer without
! 601: * using the xmlBuf APIs that is used to expand the used space
! 602: * and set the zero terminating at the end of the buffer
! 603: *
! 604: * Returns -1 in case of error and 0 otherwise
! 605: */
! 606: int
! 607: xmlBufAddLen(xmlBufPtr buf, size_t len) {
! 608: if ((buf == NULL) || (buf->error))
! 609: return(-1);
! 610: CHECK_COMPAT(buf)
! 611: if (len > (buf->size - buf->use))
! 612: return(-1);
! 613: buf->use += len;
! 614: UPDATE_COMPAT(buf)
! 615: if (buf->size > buf->use)
! 616: buf->content[buf->use] = 0;
! 617: else
! 618: return(-1);
! 619: return(0);
! 620: }
! 621:
! 622: /**
! 623: * xmlBufErase:
! 624: * @buf: the buffer
! 625: * @len: the size to erase at the end
! 626: *
! 627: * Sometime data need to be erased at the end of the buffer
! 628: *
! 629: * Returns -1 in case of error and 0 otherwise
! 630: */
! 631: int
! 632: xmlBufErase(xmlBufPtr buf, size_t len) {
! 633: if ((buf == NULL) || (buf->error))
! 634: return(-1);
! 635: CHECK_COMPAT(buf)
! 636: if (len > buf->use)
! 637: return(-1);
! 638: buf->use -= len;
! 639: buf->content[buf->use] = 0;
! 640: UPDATE_COMPAT(buf)
! 641: return(0);
! 642: }
! 643:
! 644: /**
! 645: * xmlBufLength:
! 646: * @buf: the buffer
! 647: *
! 648: * Function to get the length of a buffer
! 649: *
! 650: * Returns the length of data in the internal content
! 651: */
! 652:
! 653: size_t
! 654: xmlBufLength(const xmlBufPtr buf)
! 655: {
! 656: if ((!buf) || (buf->error))
! 657: return 0;
! 658: CHECK_COMPAT(buf)
! 659:
! 660: return(buf->use);
! 661: }
! 662:
! 663: /**
! 664: * xmlBufUse:
! 665: * @buf: the buffer
! 666: *
! 667: * Function to get the length of a buffer
! 668: *
! 669: * Returns the length of data in the internal content
! 670: */
! 671:
! 672: size_t
! 673: xmlBufUse(const xmlBufPtr buf)
! 674: {
! 675: if ((!buf) || (buf->error))
! 676: return 0;
! 677: CHECK_COMPAT(buf)
! 678:
! 679: return(buf->use);
! 680: }
! 681:
! 682: /**
! 683: * xmlBufAvail:
! 684: * @buf: the buffer
! 685: *
! 686: * Function to find how much free space is allocated but not
! 687: * used in the buffer. It does not account for the terminating zero
! 688: * usually needed
! 689: *
! 690: * Returns the amount or 0 if none or an error occured
! 691: */
! 692:
! 693: size_t
! 694: xmlBufAvail(const xmlBufPtr buf)
! 695: {
! 696: if ((!buf) || (buf->error))
! 697: return 0;
! 698: CHECK_COMPAT(buf)
! 699:
! 700: return(buf->size - buf->use);
! 701: }
! 702:
! 703: /**
! 704: * xmlBufIsEmpty:
! 705: * @buf: the buffer
! 706: *
! 707: * Tell if a buffer is empty
! 708: *
! 709: * Returns 0 if no, 1 if yes and -1 in case of error
! 710: */
! 711: int
! 712: xmlBufIsEmpty(const xmlBufPtr buf)
! 713: {
! 714: if ((!buf) || (buf->error))
! 715: return(-1);
! 716: CHECK_COMPAT(buf)
! 717:
! 718: return(buf->use == 0);
! 719: }
! 720:
! 721: /**
! 722: * xmlBufResize:
! 723: * @buf: the buffer to resize
! 724: * @size: the desired size
! 725: *
! 726: * Resize a buffer to accommodate minimum size of @size.
! 727: *
! 728: * Returns 0 in case of problems, 1 otherwise
! 729: */
! 730: int
! 731: xmlBufResize(xmlBufPtr buf, size_t size)
! 732: {
! 733: unsigned int newSize;
! 734: xmlChar* rebuf = NULL;
! 735: size_t start_buf;
! 736:
! 737: if ((buf == NULL) || (buf->error))
! 738: return(0);
! 739: CHECK_COMPAT(buf)
! 740:
! 741: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
! 742:
! 743: /* Don't resize if we don't have to */
! 744: if (size < buf->size)
! 745: return 1;
! 746:
! 747: /* figure out new size */
! 748: switch (buf->alloc){
! 749: case XML_BUFFER_ALLOC_IO:
! 750: case XML_BUFFER_ALLOC_DOUBLEIT:
! 751: /*take care of empty case*/
! 752: newSize = (buf->size ? buf->size*2 : size + 10);
! 753: while (size > newSize) {
! 754: if (newSize > UINT_MAX / 2) {
! 755: xmlBufMemoryError(buf, "growing buffer");
! 756: return 0;
! 757: }
! 758: newSize *= 2;
! 759: }
! 760: break;
! 761: case XML_BUFFER_ALLOC_EXACT:
! 762: newSize = size+10;
! 763: break;
! 764: case XML_BUFFER_ALLOC_HYBRID:
! 765: if (buf->use < BASE_BUFFER_SIZE)
! 766: newSize = size;
! 767: else {
! 768: newSize = buf->size * 2;
! 769: while (size > newSize) {
! 770: if (newSize > UINT_MAX / 2) {
! 771: xmlBufMemoryError(buf, "growing buffer");
! 772: return 0;
! 773: }
! 774: newSize *= 2;
! 775: }
! 776: }
! 777: break;
! 778:
! 779: default:
! 780: newSize = size+10;
! 781: break;
! 782: }
! 783:
! 784: if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
! 785: start_buf = buf->content - buf->contentIO;
! 786:
! 787: if (start_buf > newSize) {
! 788: /* move data back to start */
! 789: memmove(buf->contentIO, buf->content, buf->use);
! 790: buf->content = buf->contentIO;
! 791: buf->content[buf->use] = 0;
! 792: buf->size += start_buf;
! 793: } else {
! 794: rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
! 795: if (rebuf == NULL) {
! 796: xmlBufMemoryError(buf, "growing buffer");
! 797: return 0;
! 798: }
! 799: buf->contentIO = rebuf;
! 800: buf->content = rebuf + start_buf;
! 801: }
! 802: } else {
! 803: if (buf->content == NULL) {
! 804: rebuf = (xmlChar *) xmlMallocAtomic(newSize);
! 805: } else if (buf->size - buf->use < 100) {
! 806: rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
! 807: } else {
! 808: /*
! 809: * if we are reallocating a buffer far from being full, it's
! 810: * better to make a new allocation and copy only the used range
! 811: * and free the old one.
! 812: */
! 813: rebuf = (xmlChar *) xmlMallocAtomic(newSize);
! 814: if (rebuf != NULL) {
! 815: memcpy(rebuf, buf->content, buf->use);
! 816: xmlFree(buf->content);
! 817: rebuf[buf->use] = 0;
! 818: }
! 819: }
! 820: if (rebuf == NULL) {
! 821: xmlBufMemoryError(buf, "growing buffer");
! 822: return 0;
! 823: }
! 824: buf->content = rebuf;
! 825: }
! 826: buf->size = newSize;
! 827: UPDATE_COMPAT(buf)
! 828:
! 829: return 1;
! 830: }
! 831:
! 832: /**
! 833: * xmlBufAdd:
! 834: * @buf: the buffer to dump
! 835: * @str: the #xmlChar string
! 836: * @len: the number of #xmlChar to add
! 837: *
! 838: * Add a string range to an XML buffer. if len == -1, the length of
! 839: * str is recomputed.
! 840: *
! 841: * Returns 0 successful, a positive error code number otherwise
! 842: * and -1 in case of internal or API error.
! 843: */
! 844: int
! 845: xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
! 846: unsigned int needSize;
! 847:
! 848: if ((str == NULL) || (buf == NULL) || (buf->error))
! 849: return -1;
! 850: CHECK_COMPAT(buf)
! 851:
! 852: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
! 853: if (len < -1) {
! 854: #ifdef DEBUG_BUFFER
! 855: xmlGenericError(xmlGenericErrorContext,
! 856: "xmlBufAdd: len < 0\n");
! 857: #endif
! 858: return -1;
! 859: }
! 860: if (len == 0) return 0;
! 861:
! 862: if (len < 0)
! 863: len = xmlStrlen(str);
! 864:
! 865: if (len < 0) return -1;
! 866: if (len == 0) return 0;
! 867:
! 868: needSize = buf->use + len + 2;
! 869: if (needSize > buf->size){
! 870: if (!xmlBufResize(buf, needSize)){
! 871: xmlBufMemoryError(buf, "growing buffer");
! 872: return XML_ERR_NO_MEMORY;
! 873: }
! 874: }
! 875:
! 876: memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
! 877: buf->use += len;
! 878: buf->content[buf->use] = 0;
! 879: UPDATE_COMPAT(buf)
! 880: return 0;
! 881: }
! 882:
! 883: /**
! 884: * xmlBufAddHead:
! 885: * @buf: the buffer
! 886: * @str: the #xmlChar string
! 887: * @len: the number of #xmlChar to add
! 888: *
! 889: * Add a string range to the beginning of an XML buffer.
! 890: * if len == -1, the length of @str is recomputed.
! 891: *
! 892: * Returns 0 successful, a positive error code number otherwise
! 893: * and -1 in case of internal or API error.
! 894: */
! 895: int
! 896: xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
! 897: unsigned int needSize;
! 898:
! 899: if ((buf == NULL) || (buf->error))
! 900: return(-1);
! 901: CHECK_COMPAT(buf)
! 902: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
! 903: if (str == NULL) {
! 904: #ifdef DEBUG_BUFFER
! 905: xmlGenericError(xmlGenericErrorContext,
! 906: "xmlBufAddHead: str == NULL\n");
! 907: #endif
! 908: return -1;
! 909: }
! 910: if (len < -1) {
! 911: #ifdef DEBUG_BUFFER
! 912: xmlGenericError(xmlGenericErrorContext,
! 913: "xmlBufAddHead: len < 0\n");
! 914: #endif
! 915: return -1;
! 916: }
! 917: if (len == 0) return 0;
! 918:
! 919: if (len < 0)
! 920: len = xmlStrlen(str);
! 921:
! 922: if (len <= 0) return -1;
! 923:
! 924: if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
! 925: size_t start_buf = buf->content - buf->contentIO;
! 926:
! 927: if (start_buf > (unsigned int) len) {
! 928: /*
! 929: * We can add it in the space previously shrinked
! 930: */
! 931: buf->content -= len;
! 932: memmove(&buf->content[0], str, len);
! 933: buf->use += len;
! 934: buf->size += len;
! 935: UPDATE_COMPAT(buf)
! 936: return(0);
! 937: }
! 938: }
! 939: needSize = buf->use + len + 2;
! 940: if (needSize > buf->size){
! 941: if (!xmlBufResize(buf, needSize)){
! 942: xmlBufMemoryError(buf, "growing buffer");
! 943: return XML_ERR_NO_MEMORY;
! 944: }
! 945: }
! 946:
! 947: memmove(&buf->content[len], &buf->content[0], buf->use);
! 948: memmove(&buf->content[0], str, len);
! 949: buf->use += len;
! 950: buf->content[buf->use] = 0;
! 951: UPDATE_COMPAT(buf)
! 952: return 0;
! 953: }
! 954:
! 955: /**
! 956: * xmlBufCat:
! 957: * @buf: the buffer to add to
! 958: * @str: the #xmlChar string
! 959: *
! 960: * Append a zero terminated string to an XML buffer.
! 961: *
! 962: * Returns 0 successful, a positive error code number otherwise
! 963: * and -1 in case of internal or API error.
! 964: */
! 965: int
! 966: xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
! 967: if ((buf == NULL) || (buf->error))
! 968: return(-1);
! 969: CHECK_COMPAT(buf)
! 970: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
! 971: if (str == NULL) return -1;
! 972: return xmlBufAdd(buf, str, -1);
! 973: }
! 974:
! 975: /**
! 976: * xmlBufCCat:
! 977: * @buf: the buffer to dump
! 978: * @str: the C char string
! 979: *
! 980: * Append a zero terminated C string to an XML buffer.
! 981: *
! 982: * Returns 0 successful, a positive error code number otherwise
! 983: * and -1 in case of internal or API error.
! 984: */
! 985: int
! 986: xmlBufCCat(xmlBufPtr buf, const char *str) {
! 987: const char *cur;
! 988:
! 989: if ((buf == NULL) || (buf->error))
! 990: return(-1);
! 991: CHECK_COMPAT(buf)
! 992: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
! 993: if (str == NULL) {
! 994: #ifdef DEBUG_BUFFER
! 995: xmlGenericError(xmlGenericErrorContext,
! 996: "xmlBufCCat: str == NULL\n");
! 997: #endif
! 998: return -1;
! 999: }
! 1000: for (cur = str;*cur != 0;cur++) {
! 1001: if (buf->use + 10 >= buf->size) {
! 1002: if (!xmlBufResize(buf, buf->use+10)){
! 1003: xmlBufMemoryError(buf, "growing buffer");
! 1004: return XML_ERR_NO_MEMORY;
! 1005: }
! 1006: }
! 1007: buf->content[buf->use++] = *cur;
! 1008: }
! 1009: buf->content[buf->use] = 0;
! 1010: UPDATE_COMPAT(buf)
! 1011: return 0;
! 1012: }
! 1013:
! 1014: /**
! 1015: * xmlBufWriteCHAR:
! 1016: * @buf: the XML buffer
! 1017: * @string: the string to add
! 1018: *
! 1019: * routine which manages and grows an output buffer. This one adds
! 1020: * xmlChars at the end of the buffer.
! 1021: *
! 1022: * Returns 0 if successful, a positive error code number otherwise
! 1023: * and -1 in case of internal or API error.
! 1024: */
! 1025: int
! 1026: xmlBufWriteCHAR(xmlBufPtr buf, const xmlChar *string) {
! 1027: if ((buf == NULL) || (buf->error))
! 1028: return(-1);
! 1029: CHECK_COMPAT(buf)
! 1030: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
! 1031: return(-1);
! 1032: return(xmlBufCat(buf, string));
! 1033: }
! 1034:
! 1035: /**
! 1036: * xmlBufWriteChar:
! 1037: * @buf: the XML buffer output
! 1038: * @string: the string to add
! 1039: *
! 1040: * routine which manage and grows an output buffer. This one add
! 1041: * C chars at the end of the array.
! 1042: *
! 1043: * Returns 0 if successful, a positive error code number otherwise
! 1044: * and -1 in case of internal or API error.
! 1045: */
! 1046: int
! 1047: xmlBufWriteChar(xmlBufPtr buf, const char *string) {
! 1048: if ((buf == NULL) || (buf->error))
! 1049: return(-1);
! 1050: CHECK_COMPAT(buf)
! 1051: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
! 1052: return(-1);
! 1053: return(xmlBufCCat(buf, string));
! 1054: }
! 1055:
! 1056:
! 1057: /**
! 1058: * xmlBufWriteQuotedString:
! 1059: * @buf: the XML buffer output
! 1060: * @string: the string to add
! 1061: *
! 1062: * routine which manage and grows an output buffer. This one writes
! 1063: * a quoted or double quoted #xmlChar string, checking first if it holds
! 1064: * quote or double-quotes internally
! 1065: *
! 1066: * Returns 0 if successful, a positive error code number otherwise
! 1067: * and -1 in case of internal or API error.
! 1068: */
! 1069: int
! 1070: xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
! 1071: const xmlChar *cur, *base;
! 1072: if ((buf == NULL) || (buf->error))
! 1073: return(-1);
! 1074: CHECK_COMPAT(buf)
! 1075: if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
! 1076: return(-1);
! 1077: if (xmlStrchr(string, '\"')) {
! 1078: if (xmlStrchr(string, '\'')) {
! 1079: #ifdef DEBUG_BUFFER
! 1080: xmlGenericError(xmlGenericErrorContext,
! 1081: "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
! 1082: #endif
! 1083: xmlBufCCat(buf, "\"");
! 1084: base = cur = string;
! 1085: while(*cur != 0){
! 1086: if(*cur == '"'){
! 1087: if (base != cur)
! 1088: xmlBufAdd(buf, base, cur - base);
! 1089: xmlBufAdd(buf, BAD_CAST """, 6);
! 1090: cur++;
! 1091: base = cur;
! 1092: }
! 1093: else {
! 1094: cur++;
! 1095: }
! 1096: }
! 1097: if (base != cur)
! 1098: xmlBufAdd(buf, base, cur - base);
! 1099: xmlBufCCat(buf, "\"");
! 1100: }
! 1101: else{
! 1102: xmlBufCCat(buf, "\'");
! 1103: xmlBufCat(buf, string);
! 1104: xmlBufCCat(buf, "\'");
! 1105: }
! 1106: } else {
! 1107: xmlBufCCat(buf, "\"");
! 1108: xmlBufCat(buf, string);
! 1109: xmlBufCCat(buf, "\"");
! 1110: }
! 1111: return(0);
! 1112: }
! 1113:
! 1114: /**
! 1115: * xmlBufFromBuffer:
! 1116: * @buffer: incoming old buffer to convert to a new one
! 1117: *
! 1118: * Helper routine to switch from the old buffer structures in use
! 1119: * in various APIs. It creates a wrapper xmlBufPtr which will be
! 1120: * used for internal processing until the xmlBufBackToBuffer() is
! 1121: * issued.
! 1122: *
! 1123: * Returns a new xmlBufPtr unless the call failed and NULL is returned
! 1124: */
! 1125: xmlBufPtr
! 1126: xmlBufFromBuffer(xmlBufferPtr buffer) {
! 1127: xmlBufPtr ret;
! 1128:
! 1129: if (buffer == NULL)
! 1130: return(NULL);
! 1131:
! 1132: ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
! 1133: if (ret == NULL) {
! 1134: xmlBufMemoryError(NULL, "creating buffer");
! 1135: return(NULL);
! 1136: }
! 1137: ret->use = buffer->use;
! 1138: ret->size = buffer->size;
! 1139: ret->compat_use = buffer->use;
! 1140: ret->compat_size = buffer->size;
! 1141: ret->error = 0;
! 1142: ret->buffer = buffer;
! 1143: ret->alloc = buffer->alloc;
! 1144: ret->content = buffer->content;
! 1145: ret->contentIO = buffer->contentIO;
! 1146:
! 1147: return(ret);
! 1148: }
! 1149:
! 1150: /**
! 1151: * xmlBufBackToBuffer:
! 1152: * @buf: new buffer wrapping the old one
! 1153: *
! 1154: * Function to be called once internal processing had been done to
! 1155: * update back the buffer provided by the user. This can lead to
! 1156: * a failure in case the size accumulated in the xmlBuf is larger
! 1157: * than what an xmlBuffer can support on 64 bits (INT_MAX)
! 1158: * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
! 1159: *
! 1160: * Returns the old xmlBufferPtr unless the call failed and NULL is returned
! 1161: */
! 1162: xmlBufferPtr
! 1163: xmlBufBackToBuffer(xmlBufPtr buf) {
! 1164: xmlBufferPtr ret;
! 1165:
! 1166: if ((buf == NULL) || (buf->error))
! 1167: return(NULL);
! 1168: CHECK_COMPAT(buf)
! 1169: if (buf->buffer == NULL) {
! 1170: xmlBufFree(buf);
! 1171: return(NULL);
! 1172: }
! 1173:
! 1174: ret = buf->buffer;
! 1175: /*
! 1176: * What to do in case of error in the buffer ???
! 1177: */
! 1178: if (buf->use > INT_MAX) {
! 1179: /*
! 1180: * Worse case, we really allocated and used more than the
! 1181: * maximum allowed memory for an xmlBuffer on this architecture.
! 1182: * Keep the buffer but provide a truncated size value.
! 1183: */
! 1184: xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
! 1185: ret->use = INT_MAX;
! 1186: ret->size = INT_MAX;
! 1187: } else if (buf->size > INT_MAX) {
! 1188: /*
! 1189: * milder case, we allocated more than the maximum allowed memory
! 1190: * for an xmlBuffer on this architecture, but used less than the
! 1191: * limit.
! 1192: * Keep the buffer but provide a truncated size value.
! 1193: */
! 1194: xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
! 1195: ret->size = INT_MAX;
! 1196: }
! 1197: ret->use = (int) buf->use;
! 1198: ret->size = (int) buf->size;
! 1199: ret->alloc = buf->alloc;
! 1200: ret->content = buf->content;
! 1201: ret->contentIO = buf->contentIO;
! 1202: xmlFree(buf);
! 1203: return(ret);
! 1204: }
! 1205:
! 1206: /**
! 1207: * xmlBufMergeBuffer:
! 1208: * @buf: an xmlBufPtr
! 1209: * @buffer: the buffer to consume into @buf
! 1210: *
! 1211: * The content of @buffer is appended to @buf and @buffer is freed
! 1212: *
! 1213: * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
! 1214: */
! 1215: int
! 1216: xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
! 1217: int ret = 0;
! 1218:
! 1219: if ((buf == NULL) || (buf->error)) {
! 1220: xmlBufferFree(buffer);
! 1221: return(-1);
! 1222: }
! 1223: CHECK_COMPAT(buf)
! 1224: if ((buffer != NULL) && (buffer->content != NULL) &&
! 1225: (buffer->use > 0)) {
! 1226: ret = xmlBufAdd(buf, buffer->content, buffer->use);
! 1227: }
! 1228: xmlBufferFree(buffer);
! 1229: return(ret);
! 1230: }
! 1231:
! 1232: /**
! 1233: * xmlBufResetInput:
! 1234: * @buf: an xmlBufPtr
! 1235: * @input: an xmlParserInputPtr
! 1236: *
! 1237: * Update the input to use the current set of pointers from the buffer.
! 1238: *
! 1239: * Returns -1 in case of error, 0 otherwise
! 1240: */
! 1241: int
! 1242: xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
! 1243: if ((input == NULL) || (buf == NULL) || (buf->error))
! 1244: return(-1);
! 1245: CHECK_COMPAT(buf)
! 1246: input->base = input->cur = buf->content;
! 1247: input->end = &buf->content[buf->use];
! 1248: return(0);
! 1249: }
! 1250:
! 1251: /**
! 1252: * xmlBufGetInputBase:
! 1253: * @buf: an xmlBufPtr
! 1254: * @input: an xmlParserInputPtr
! 1255: *
! 1256: * Get the base of the @input relative to the beginning of the buffer
! 1257: *
! 1258: * Returns the size_t corresponding to the displacement
! 1259: */
! 1260: size_t
! 1261: xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
! 1262: size_t base;
! 1263:
! 1264: if ((input == NULL) || (buf == NULL) || (buf->error))
! 1265: return(-1);
! 1266: CHECK_COMPAT(buf)
! 1267: base = input->base - buf->content;
! 1268: /*
! 1269: * We could do some pointer arythmetic checks but that's probably
! 1270: * sufficient.
! 1271: */
! 1272: if (base > buf->size) {
! 1273: xmlBufOverflowError(buf, "Input reference outside of the buffer");
! 1274: base = 0;
! 1275: }
! 1276: return(base);
! 1277: }
! 1278:
! 1279: /**
! 1280: * xmlBufSetInputBaseCur:
! 1281: * @buf: an xmlBufPtr
! 1282: * @input: an xmlParserInputPtr
! 1283: * @base: the base value relative to the beginning of the buffer
! 1284: * @cur: the cur value relative to the beginning of the buffer
! 1285: *
! 1286: * Update the input to use the base and cur relative to the buffer
! 1287: * after a possible reallocation of its content
! 1288: *
! 1289: * Returns -1 in case of error, 0 otherwise
! 1290: */
! 1291: int
! 1292: xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
! 1293: size_t base, size_t cur) {
! 1294: if ((input == NULL) || (buf == NULL) || (buf->error))
! 1295: return(-1);
! 1296: CHECK_COMPAT(buf)
! 1297: input->base = &buf->content[base];
! 1298: input->cur = input->base + cur;
! 1299: input->end = &buf->content[buf->use];
! 1300: return(0);
! 1301: }
! 1302:
! 1303: #define bottom_buf
! 1304: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>