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