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