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