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